├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── LICENSE ├── README.md ├── README_EN.md ├── docs ├── _config.yml ├── images │ ├── architecture.png │ └── logo.jpg └── sponsor │ ├── weixin.JPG │ └── zhifubao.JPG └── hybridclr ├── CommonDef.cpp ├── CommonDef.h ├── Il2CppCompatibleDef.cpp ├── Il2CppCompatibleDef.h ├── Runtime.cpp ├── Runtime.h ├── RuntimeApi.cpp ├── RuntimeApi.h ├── RuntimeConfig.cpp ├── RuntimeConfig.h ├── generated ├── AssemblyManifest.cpp ├── MethodBridge.cpp └── UnityVersion.h ├── interpreter ├── Engine.cpp ├── Engine.h ├── InstrinctDef.h ├── Instruction.cpp ├── Instruction.h ├── Interpreter.cpp ├── Interpreter.h ├── InterpreterDefs.cpp ├── InterpreterDefs.h ├── InterpreterModule.cpp ├── InterpreterModule.h ├── InterpreterUtil.cpp ├── InterpreterUtil.h ├── Interpreter_Execute.cpp ├── MemoryUtil.h ├── MethodBridge.cpp └── MethodBridge.h ├── metadata ├── AOTHomologousImage.cpp ├── AOTHomologousImage.h ├── Assembly.cpp ├── Assembly.h ├── BlobReader.h ├── ClassFieldLayoutCalculator.cpp ├── ClassFieldLayoutCalculator.h ├── Coff.h ├── ConsistentAOTHomologousImage.cpp ├── ConsistentAOTHomologousImage.h ├── CustomAttributeDataWriter.h ├── Image.cpp ├── Image.h ├── InterpreterImage.cpp ├── InterpreterImage.h ├── MetadataDef.h ├── MetadataModule.cpp ├── MetadataModule.h ├── MetadataPool.cpp ├── MetadataPool.h ├── MetadataUtil.cpp ├── MetadataUtil.h ├── MethodBodyCache.cpp ├── MethodBodyCache.h ├── Opcodes.cpp ├── Opcodes.h ├── PDBImage.cpp ├── PDBImage.h ├── RawImage.cpp ├── RawImage.h ├── RawImageBase.cpp ├── RawImageBase.h ├── SuperSetAOTHomologousImage.cpp ├── SuperSetAOTHomologousImage.h ├── Tables.h ├── VTableSetup.cpp └── VTableSetup.h └── transform ├── BasicBlockSpliter.cpp ├── BasicBlockSpliter.h ├── TemporaryMemoryArena.cpp ├── TemporaryMemoryArena.h ├── Transform.cpp ├── Transform.h ├── TransformContext.cpp ├── TransformContext.h ├── TransformContext_CallCommon.cpp ├── TransformContext_Instinct.cpp ├── TransformModule.cpp └── TransformModule.h /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: ['https://raw.githubusercontent.com/focus-creative-games/hybridclr/main/docs/sponsor/weixin.JPG','https://raw.githubusercontent.com/focus-creative-games/hybridclr/main/docs/sponsor/zhifubao.JPG'] 14 | 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug | 描述问题** 11 | A clear and concise description of what the bug is. 12 | 13 | ** Enviroment | 环境 ** 14 | 15 | - Unity Version: 202x.y.z 16 | - com.code-philosophy.hybridclr Version: 4.x.y 17 | - Platform: Win 64 Standalone|Android|iOS| ... 18 | 19 | **To Reproduce | 复制步骤 ** 20 | 21 | Please provide a reproduction project. Please try to reproduce this bug on the https://github.com/focus-creative-games/hybridclr_trial project. | 提供复现工程,请尽量在 https://github.com/focus-creative-games/hybridclr_trial 项目上复现这个bug。 22 | 23 | 24 | Steps to reproduce the behavior : 25 | 1. Go to '...' 26 | 2. Click on '....' 27 | 3. Scroll down to '....' 28 | 4. See error 29 | 30 | **Expected behavior | 期望的结果** 31 | A clear and concise description of what you expected to happen. 32 | 33 | **Screenshots | 截图或者日志** 34 | If applicable, add screenshots to help explain your problem. 35 | 36 | **Additional context | 补充信息** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Code Philosophy Technology Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - [README 中文](./README.md) 2 | - [README English](./README_EN.md) 3 | 4 | # HybridCLR 5 | 6 | [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) 7 | 8 | ![logo](./docs/images/logo.jpg) 9 | 10 |
11 |
12 | 13 | HybridCLR是一个**特性完整、零成本、高性能、低内存**的**近乎完美**的Unity全平台原生c#热更新解决方案。 14 | 15 | HybridCLR扩充了il2cpp运行时代码,使它由纯[AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,从底层彻底支持了热更新。使用HybridCLR技术的游戏不仅能在Android平台,也能在IOS、Consoles、WebGL等所有il2cpp支持的平台上高效运行。 16 | 17 | 由于HybridCLR对ECMA-335规范 的良好支持以及对Unity开发工作流的高度兼容,Unity项目在接入HybridCLR后,可以几乎无缝地获得C#代码热更新的能力,开发者不需要改变日常开发习惯和要求。HybridCLR首次实现了将Unity平台的全平台代码热更新方案的工程难度降到几乎为零的水平。 18 | 19 | 欢迎拥抱现代原生C#热更新技术 !!! 20 | 21 | ## 文档 22 | 23 | - [官方文档](https://hybridclr.doc.code-philosophy.com/docs/intro) 24 | - [快速上手](https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart) 25 | - [商业项目案例](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase) 26 | 27 | 28 | ## 特性 29 | 30 | - 近乎完整实现了[ECMA-335规范](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/),只有极少量的[不支持的特性](https://hybridclr.doc.code-philosophy.com/docs/basic/notsupportedfeatures)。 31 | - 零学习和使用成本。对绝大多数开发者来说写代码近乎没有限制。 热更新代码与AOT代码无缝工作,可以随意写继承、**泛型**、**反射**之类的代码。不需要额外写任何特殊代码、没有代码生成 32 | - 完全支持多线程,包含但不限于 volatile、ThreadStatic、async Task等相关功能和特性。这是其他所有热更新方案都不支持的 33 | - 几乎完全兼容Unity的工作流。包括且不限于支持热更新**MonoBehaviour**、ScriptableObject、**DOTS**技术,资源上挂载的热更新脚本可以正确实例化,这是其他所有热更新方案都不支持的 34 | - 执行高效。实现了一个极其高效的寄存器解释器,所有指标都大幅优于其他热更新方案。[性能测试报告](https://hybridclr.doc.code-philosophy.com/docs/basic/performance) 35 | - 内存高效。 热更新脚本中定义的类跟普通c#类占用一样的内存空间,远优于其他热更新方案。[内存占用报告](https://hybridclr.doc.code-philosophy.com/docs/basic/memory) 36 | - 支持MonoPInvokeCallback,可以与native代码或者其他语言如lua、javascript、python良好交互 37 | - 支持一些il2cpp不支持的特性,如__makeref、 __reftype、__refvalue指令 38 | - 支持独创的 **Differential Hybrid Execution(DHE)** 差分混合执行技术,即可以对AOT dll任意增删改,会智能地让未改动的函数以AOT方式运行,变化或者新增的函数以interpreter模式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平 39 | - 支持 **热重载** 技术,可以100%卸载程序集 40 | - 支持 **热修复** 技术,不需要重启游戏即可无感修复bug 41 | - 支持现代的dll加密技术,有效保障代码安全 42 | 43 | ## 支持的版本与平台 44 | 45 | - 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x、2023.2.x、6000.x.y全系列LTS版本 46 | - 支持所有il2cpp支持的平台 47 | - 支持团结引擎和鸿蒙平台 48 | 49 | ## 工作原理 50 | 51 | HybridCLR从mono的 [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) 技术中得到启发,为unity的il2cpp之类的AOT runtime额外提供了interpreter模块,将它们由纯AOT运行时改造为"AOT + Interpreter"混合运行方式。 52 | 53 | ![icon](docs/images/architecture.png) 54 | 55 | 更具体地说,HybridCLR做了以下几点工作: 56 | 57 | - 实现了一个高效的元数据(dll)解析库 58 | - 改造了元数据管理模块,实现了元数据的动态注册 59 | - 实现了一个IL指令集到自定义的寄存器指令集的compiler 60 | - 实现了一个高效的寄存器解释器 61 | - 额外提供大量的instinct函数,提升解释器性能 62 | 63 | ## 稳定性状况 64 | 65 | HybridCLR已经被广泛验证是非常高效、稳定的Unity热更新解决方案,良好满足大中型商业项目的稳定和性能要求。 66 | 67 | 目前已经有数千个商业游戏项目接入了HybridCLR,其中有超过千个已经在App Store和Google Player上线,仅仅iOS免费榜前500名中就有近百款使用了HybridCLR。上线的项目中包括MMORPG、重度卡牌、重度塔防之类的游戏。国内绝大多数**Top游戏公司**都已经在使用HybridCLR。 68 | 69 | 可查看我们已知的头部公司中使用HybridCLR并且已经上线的[项目列表](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase)。 70 | 71 | ## 支持与联系 72 | 73 | - 官方1群(3000人):651188171(满) 74 | - 新手1群(3000人):428404198(满) 75 | - 新手2群(2000人):680274677(满) 76 | - 新手3群(2000人):**920714552(推荐)** 77 | - discord频道 https://discord.gg/BATfNfJnm2 78 | - 商业合作邮箱: business#code-philosophy.com 79 | - [商业化支持](https://hybridclr.doc.code-philosophy.com/docs/business/intro) 80 | 81 | ## 关于作者 82 | 83 | **walon** :**Code Philosophy(代码哲学)** 创始人 84 | 85 | 毕业于清华大学物理系,2006年CMO金牌,奥数国家集训队成员,保送清华基科班。专注于游戏技术,擅长开发架构和基础技术设施。 86 | 87 | ## license 88 | 89 | HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license 90 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | 2 | - [README Chinese](./README.md) 3 | - [README English](./README_EN.md) 4 | 5 | # HybridCLR 6 | 7 | [![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) 8 | 9 | ![logo](./docs/images/logo.jpg) 10 | 11 |
12 |
13 | 14 | HybridCLR is a **feature-complete, zero-cost, high-performance, low-memory** **near-perfect** Unity cross-platform native C# hot update solution. 15 | 16 | HybridCLR extends the il2cpp runtime code, transforming it from a pure [AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime to an AOT+Interpreter hybrid runtime, thereby natively supporting the dynamic loading of assemblies and fundamentally supporting hot updates from the bottom layer. Games using HybridCLR technology can not only run efficiently on the Android platform but also on all platforms supported by il2cpp, including iOS, Consoles, WebGL, etc. 17 | 18 | Thanks to HybridCLR's good support for the ECMA-335 specification and its high compatibility with the Unity development workflow, Unity projects can almost seamlessly gain the ability to hot update C# code after integrating HybridCLR. Developers do not need to change their daily development habits and requirements. HybridCLR is the first to achieve the engineering difficulty of a full-platform code hot update solution for the Unity platform to almost zero. 19 | 20 | Welcome to embrace modern native C# hot update technology! 21 | 22 | ## Documentation 23 | 24 | - [Official Documentation](https://hybridclr.doc.code-philosophy.com/en/docs/intro) 25 | - [Quick Start](https://hybridclr.doc.code-philosophy.com/en/docs/beginner/quickstart) 26 | - [Business Project Cases](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase) 27 | 28 | ## Features 29 | 30 | - Nearly complete implementation of the [ECMA-335 specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), with only a very small number of [unsupported features](https://hybridclr.doc.code-philosophy.com/en/docs/basic/notsupportedfeatures). 31 | - Zero learning and usage costs. For most developers, writing code is almost unrestricted. Hot update code works seamlessly with AOT code, allowing for inheritance, **generics**, **reflection**, and other code without additional special code or code generation. 32 | - Full support for multithreading, including but not limited to volatile, ThreadStatic, async Task, and related features and characteristics. This is not supported by any other hot update solution. 33 | - Almost complete compatibility with Unity's workflow. This includes support for hot updating **MonoBehaviour**, ScriptableObject, **DOTS** technology, and correctly instantiating hot update scripts mounted on resources, which is not supported by any other hot update solution. 34 | - Efficient execution. A highly efficient register interpreter has been implemented, with all indicators significantly better than other hot update solutions. [Performance Test Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/performance) 35 | - Efficient memory usage. Classes defined in hot update scripts occupy the same memory space as ordinary C# classes, far superior to other hot update solutions. [Memory Usage Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/memory) 36 | - Supports MonoPInvokeCallback, enabling good interaction with native code or other languages such as Lua, JavaScript, Python. 37 | - Supports some features not supported by il2cpp, such as __makeref, __reftype, __refvalue instructions. 38 | - Supports the unique **Differential Hybrid Execution (DHE)** technology, which allows for arbitrary additions, deletions, and modifications to AOT DLLs. It intelligently runs unchanged functions in AOT mode and changed or newly added functions in interpreter mode, bringing the performance of hot-updated game logic close to that of native AOT. 39 | - Supports **hot reload** technology, allowing 100% unloading of assemblies. 40 | - Supports **Hotfix** technology, allowing for bug fixes without the need to restart the game, resulting in a seamless repair experience. 41 | - Supports modern DLL encryption technology to effectively protect code security. 42 | 43 | ## Supported Versions and Platforms 44 | 45 | - Supports all LTS versions including 2019.4.x, 2020.3.x, 2021.3.x, 2022.3.x, 2023.2.x, 6000.x.y. 46 | - Supports all platforms supported by il2cpp. 47 | - Supports Tuanjie(China) Engine and HarmonyOS platform. 48 | 49 | ## Working Principle 50 | 51 | HybridCLR draws inspiration from Mono's [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) technology, providing an interpreter module for AOT runtimes like Unity's il2cpp, transforming them from pure AOT runtimes to "AOT + Interpreter" hybrid operation modes. 52 | 53 | ![icon](docs/images/architecture.png) 54 | 55 | More specifically, HybridCLR has done the following: 56 | 57 | - Implemented an efficient metadata (dll) parsing library. 58 | - Modified the metadata management module to achieve dynamic registration of metadata. 59 | - Implemented a compiler that converts IL instructions to a custom register instruction set. 60 | - Implemented an efficient register interpreter. 61 | - Provided a large number of instinct functions to enhance interpreter performance. 62 | 63 | ## Stability Status 64 | 65 | HybridCLR has been widely verified as an efficient and stable Unity hot update solution, meeting the stability and performance requirements of medium and large commercial projects. 66 | 67 | Currently, thousands of commercial game projects have integrated HybridCLR, with over a thousand already launched on the App Store and Google Play. Nearly a hundred of the top 500 free iOS games use HybridCLR, including MMORPGs, heavy card games, and heavy tower defense games. Most of the **Top Game Companies** in China are already using HybridCLR. 68 | 69 | You can view the [list of known top companies using HybridCLR and their launched projects](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase). 70 | 71 | ## Support and Contact 72 | 73 | - Official Group 1: 651188171 (Full) 74 | - Beginner Group 1: 428404198 (Full) 75 | - Beginner Group 2: 680274677 (Full) 76 | - Beginner Group 3: **920714552 (Recommended)** 77 | - Discord channel https://discord.gg/BATfNfJnm2 78 | - Business cooperation email: business#code-philosophy.com 79 | - [Commercial Support](https://hybridclr.doc.code-philosophy.com/en/docs/business/intro) 80 | 81 | ## About the Author 82 | 83 | **walon**: Founder of **Code Philosophy (代码哲学)** 84 | 85 | Graduated from the Department of Physics at Tsinghua University, gold medalist of the 2006 CMO, member of the National Mathematical Olympiad Training Team, and sent to the Basic Science Class of Tsinghua. Focused on game technology, proficient in development architecture and basic technical infrastructure. 86 | 87 | ## License 88 | 89 | HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license. 90 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/focus-creative-games/hybridclr/ea5ca06a606d711dae754935530cfa6cb806a167/docs/images/architecture.png -------------------------------------------------------------------------------- /docs/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/focus-creative-games/hybridclr/ea5ca06a606d711dae754935530cfa6cb806a167/docs/images/logo.jpg -------------------------------------------------------------------------------- /docs/sponsor/weixin.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/focus-creative-games/hybridclr/ea5ca06a606d711dae754935530cfa6cb806a167/docs/sponsor/weixin.JPG -------------------------------------------------------------------------------- /docs/sponsor/zhifubao.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/focus-creative-games/hybridclr/ea5ca06a606d711dae754935530cfa6cb806a167/docs/sponsor/zhifubao.JPG -------------------------------------------------------------------------------- /hybridclr/CommonDef.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "CommonDef.h" 4 | 5 | 6 | namespace hybridclr 7 | { 8 | void LogPanic(const char* errMsg) 9 | { 10 | std::cerr << "panic:" << std::endl; 11 | std::cerr << "\t" << errMsg << std::endl; 12 | exit(1); 13 | } 14 | 15 | const char* GetAssemblyNameFromPath(const char* assPath) 16 | { 17 | const char* last = nullptr; 18 | for (const char* p = assPath; *p; p++) 19 | { 20 | if (*p == '/' || *p == '\\') 21 | { 22 | last = p + 1; 23 | } 24 | } 25 | return last ? last : assPath; 26 | } 27 | 28 | const char* CopyString(const char* src) 29 | { 30 | size_t len = std::strlen(src); 31 | char* dst = (char*)HYBRIDCLR_MALLOC(len + 1); 32 | std::strcpy(dst, src); 33 | return dst; 34 | } 35 | 36 | const char* ConcatNewString(const char* s1, const char* s2) 37 | { 38 | size_t len1 = std::strlen(s1); 39 | size_t len = len1 + std::strlen(s2); 40 | char* dst = (char*)HYBRIDCLR_MALLOC(len + 1); 41 | std::strcpy(dst, s1); 42 | strcpy(dst + len1, s2); 43 | return dst; 44 | } 45 | 46 | void* CopyBytes(const void* src, size_t length) 47 | { 48 | void* dst = HYBRIDCLR_MALLOC(length); 49 | std::memcpy(dst, src, length); 50 | return dst; 51 | } 52 | } 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /hybridclr/CommonDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Il2CppCompatibleDef.h" 8 | 9 | #include "utils/Memory.h" 10 | #include "utils/StringView.h" 11 | #include "utils/Il2CppHashSet.h" 12 | #include "utils/Il2CppHashMap.h" 13 | #include "utils/HashUtils.h" 14 | #include "vm/GlobalMetadataFileInternals.h" 15 | #include "vm/Exception.h" 16 | #include "vm/Class.h" 17 | #include "icalls/mscorlib/System/Type.h" 18 | #ifdef HYBRIDCLR_UNITY_2021_OR_NEW 19 | #include "icalls/mscorlib/System/RuntimeType.h" 20 | #else 21 | #include "icalls/mscorlib/System/MonoType.h" 22 | #endif 23 | 24 | namespace hybridclr 25 | { 26 | typedef uint8_t byte; 27 | 28 | #define TEMP_FORMAT(var, fmt, ...) char var[600]; \ 29 | snprintf(var, sizeof(var), fmt, __VA_ARGS__); 30 | 31 | void LogPanic(const char* errMsg); 32 | 33 | const char* GetAssemblyNameFromPath(const char* assPath); 34 | 35 | const char* CopyString(const char* src); 36 | 37 | const char* ConcatNewString(const char* s1, const char* s2); 38 | 39 | void* CopyBytes(const void* src, size_t length); 40 | 41 | struct CStringHash 42 | { 43 | size_t operator()(const char* s) const noexcept 44 | { 45 | uint32_t hash = 0; 46 | 47 | for (; *s; ++s) 48 | { 49 | hash += *s; 50 | hash += (hash << 10); 51 | hash ^= (hash >> 6); 52 | } 53 | 54 | hash += (hash << 3); 55 | hash ^= (hash >> 11); 56 | hash += (hash << 15); 57 | 58 | return hash; 59 | } 60 | }; 61 | 62 | struct CStringEqualTo 63 | { 64 | bool operator()(const char* _Left, const char* _Right) const 65 | { 66 | return std::strcmp(_Left, _Right) == 0; 67 | } 68 | }; 69 | 70 | inline il2cpp::utils::StringView CStringToStringView(const char* str) 71 | { 72 | return il2cpp::utils::StringView(str, std::strlen(str)); 73 | } 74 | 75 | inline std::string GetKlassCStringFullName(const Il2CppType* type) 76 | { 77 | return GetKlassFullName2(type); 78 | } 79 | 80 | inline void RaiseNotSupportedException(const char* msg) 81 | { 82 | TEMP_FORMAT(errMsg, "hybridclr doesn't support %s", msg); 83 | return il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetNotSupportedException(errMsg)); 84 | } 85 | 86 | inline void RaiseExecutionEngineException(const char* msg) 87 | { 88 | return il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(msg)); 89 | } 90 | 91 | inline void RaiseMethodNotFindException(const Il2CppType* type, const char* methodName) 92 | { 93 | if (!type) 94 | { 95 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException("type not exists")); 96 | } 97 | 98 | std::string fullName = GetKlassCStringFullName(type); 99 | TEMP_FORMAT(errMsg, "MethodNotFind %s::%s", fullName.c_str(), methodName); 100 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingMethodException(errMsg)); 101 | } 102 | 103 | inline void AppendTypeName(std::string& s, const Il2CppType* type) 104 | { 105 | s.append(GetKlassCStringFullName(type)); 106 | } 107 | 108 | inline std::string GetMethodNameWithSignature(const MethodInfo* method) 109 | { 110 | std::string name; 111 | AppendTypeName(name, method->return_type); 112 | name.append(" "); 113 | 114 | name.append(GetKlassCStringFullName(&method->klass->byval_arg)); 115 | name.append("::"); 116 | name.append(method->name); 117 | if (method->genericMethod && method->genericMethod->context.method_inst) 118 | { 119 | name.append("<"); 120 | const Il2CppGenericInst* gi= method->genericMethod->context.method_inst; 121 | for (uint32_t i = 0; i < gi->type_argc; i++) 122 | { 123 | if (i > 0) 124 | { 125 | name.append(","); 126 | } 127 | AppendTypeName(name, gi->type_argv[i]); 128 | } 129 | name.append(">"); 130 | } 131 | name.append("("); 132 | for (uint8_t i = 0; i < method->parameters_count; i++) 133 | { 134 | if (i > 0) 135 | { 136 | name.append(","); 137 | } 138 | AppendTypeName(name, GET_METHOD_PARAMETER_TYPE(method->parameters[i])); 139 | } 140 | name.append(")"); 141 | return name; 142 | } 143 | 144 | inline void RaiseAOTGenericMethodNotInstantiatedException(const MethodInfo* method) 145 | { 146 | std::string methodName = GetMethodNameWithSignature(method); 147 | TEMP_FORMAT(errMsg, "AOT generic method not instantiated in aot. assembly:%s, method:%s", method->klass->image->name, methodName.c_str()); 148 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingMethodException(errMsg)); 149 | } 150 | 151 | inline void RaiseMissingFieldException(const Il2CppType* type, const char* fieldName) 152 | { 153 | if (!type) 154 | { 155 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException("type not exists")); 156 | } 157 | std::string stdFullName = GetKlassCStringFullName(type); 158 | TEMP_FORMAT(errMsg, "field %s::%s not exists", stdFullName.c_str(), fieldName); 159 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetMissingFieldException(errMsg)); 160 | } 161 | 162 | } 163 | 164 | 165 | -------------------------------------------------------------------------------- /hybridclr/Il2CppCompatibleDef.cpp: -------------------------------------------------------------------------------- 1 | #include "Il2CppCompatibleDef.h" 2 | 3 | #include "vm/Runtime.h" 4 | 5 | #include "metadata/MetadataModule.h" 6 | #include "interpreter/InterpreterModule.h" 7 | 8 | 9 | namespace hybridclr 10 | { 11 | Il2CppMethodPointer InitAndGetInterpreterDirectlyCallMethodPointerSlow(MethodInfo* method) 12 | { 13 | IL2CPP_ASSERT(!method->initInterpCallMethodPointer); 14 | method->initInterpCallMethodPointer = true; 15 | bool isAdjustorThunkMethod = IS_CLASS_VALUE_TYPE(method->klass) && hybridclr::metadata::IsInstanceMethod(method); 16 | if (hybridclr::metadata::MetadataModule::IsImplementedByInterpreter(method)) 17 | { 18 | method->methodPointerCallByInterp = interpreter::InterpreterModule::GetMethodPointer(method); 19 | if (isAdjustorThunkMethod) 20 | { 21 | method->virtualMethodPointerCallByInterp = interpreter::InterpreterModule::GetAdjustThunkMethodPointer(method); 22 | } 23 | else 24 | { 25 | method->virtualMethodPointerCallByInterp = method->methodPointerCallByInterp; 26 | } 27 | if (method->invoker_method == nullptr 28 | #if HYBRIDCLR_UNITY_2021_OR_NEW 29 | || method->invoker_method == il2cpp::vm::Runtime::GetMissingMethodInvoker() 30 | || method->has_full_generic_sharing_signature 31 | #endif 32 | ) 33 | { 34 | method->invoker_method = hybridclr::interpreter::InterpreterModule::GetMethodInvoker(method); 35 | } 36 | #if HYBRIDCLR_UNITY_2021_OR_NEW 37 | if (method->methodPointer == nullptr || method->has_full_generic_sharing_signature) 38 | { 39 | method->methodPointer = method->methodPointerCallByInterp; 40 | } 41 | if (method->virtualMethodPointer == nullptr || method->has_full_generic_sharing_signature) 42 | { 43 | method->virtualMethodPointer = method->virtualMethodPointerCallByInterp; 44 | } 45 | #else 46 | if (method->methodPointer == nullptr) 47 | { 48 | method->methodPointer = method->virtualMethodPointerCallByInterp; 49 | } 50 | #endif 51 | method->isInterpterImpl = true; 52 | } 53 | return method->methodPointerCallByInterp; 54 | } 55 | } -------------------------------------------------------------------------------- /hybridclr/Runtime.cpp: -------------------------------------------------------------------------------- 1 | #include "Runtime.h" 2 | 3 | #include "vm/Exception.h" 4 | #include "vm/String.h" 5 | #include "vm/Assembly.h" 6 | #include "vm/Class.h" 7 | #include "vm/Object.h" 8 | #include "vm/Reflection.h" 9 | #include "icalls/mscorlib/System.Reflection/Assembly.h" 10 | 11 | #include "RuntimeApi.h" 12 | #include "interpreter/InterpreterModule.h" 13 | #include "metadata/MetadataModule.h" 14 | #include "transform/TransformModule.h" 15 | 16 | 17 | namespace hybridclr 18 | { 19 | 20 | void Runtime::Initialize() 21 | { 22 | RuntimeApi::RegisterInternalCalls(); 23 | metadata::MetadataModule::Initialize(); 24 | interpreter::InterpreterModule::Initialize(); 25 | transform::TransformModule::Initialize(); 26 | } 27 | } -------------------------------------------------------------------------------- /hybridclr/Runtime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommonDef.h" 4 | 5 | namespace hybridclr 6 | { 7 | 8 | class Runtime 9 | { 10 | public: 11 | static void Initialize(); 12 | }; 13 | } -------------------------------------------------------------------------------- /hybridclr/RuntimeApi.cpp: -------------------------------------------------------------------------------- 1 | #include "RuntimeApi.h" 2 | 3 | #include "codegen/il2cpp-codegen.h" 4 | #include "vm/InternalCalls.h" 5 | #include "vm/Array.h" 6 | #include "vm/Exception.h" 7 | #include "vm/Class.h" 8 | 9 | #include "metadata/MetadataModule.h" 10 | #include "metadata/MetadataUtil.h" 11 | #include "interpreter/InterpreterModule.h" 12 | #include "RuntimeConfig.h" 13 | 14 | namespace hybridclr 15 | { 16 | void RuntimeApi::RegisterInternalCalls() 17 | { 18 | il2cpp::vm::InternalCalls::Add("HybridCLR.RuntimeApi::LoadMetadataForAOTAssembly(System.Byte[],HybridCLR.HomologousImageMode)", (Il2CppMethodPointer)LoadMetadataForAOTAssembly); 19 | il2cpp::vm::InternalCalls::Add("HybridCLR.RuntimeApi::GetRuntimeOption(HybridCLR.RuntimeOptionId)", (Il2CppMethodPointer)GetRuntimeOption); 20 | il2cpp::vm::InternalCalls::Add("HybridCLR.RuntimeApi::SetRuntimeOption(HybridCLR.RuntimeOptionId,System.Int32)", (Il2CppMethodPointer)SetRuntimeOption); 21 | il2cpp::vm::InternalCalls::Add("HybridCLR.RuntimeApi::PreJitClass(System.Type)", (Il2CppMethodPointer)PreJitClass); 22 | il2cpp::vm::InternalCalls::Add("HybridCLR.RuntimeApi::PreJitMethod(System.Reflection.MethodInfo)", (Il2CppMethodPointer)PreJitMethod); 23 | } 24 | 25 | int32_t RuntimeApi::LoadMetadataForAOTAssembly(Il2CppArray* dllBytes, int32_t mode) 26 | { 27 | if (!dllBytes) 28 | { 29 | il2cpp::vm::Exception::RaiseNullReferenceException(); 30 | } 31 | return (int32_t)hybridclr::metadata::Assembly::LoadMetadataForAOTAssembly(il2cpp::vm::Array::GetFirstElementAddress(dllBytes), il2cpp::vm::Array::GetByteLength(dllBytes), (hybridclr::metadata::HomologousImageMode)mode); 32 | } 33 | 34 | int32_t RuntimeApi::GetRuntimeOption(int32_t optionId) 35 | { 36 | return hybridclr::RuntimeConfig::GetRuntimeOption((hybridclr::RuntimeOptionId)optionId); 37 | } 38 | 39 | void RuntimeApi::SetRuntimeOption(int32_t optionId, int32_t value) 40 | { 41 | hybridclr::RuntimeConfig::SetRuntimeOption((hybridclr::RuntimeOptionId)optionId, value); 42 | } 43 | 44 | int32_t PreJitMethod0(const MethodInfo* methodInfo); 45 | 46 | int32_t RuntimeApi::PreJitClass(Il2CppReflectionType* type) 47 | { 48 | if (metadata::HasNotInstantiatedGenericType(type->type)) 49 | { 50 | return false; 51 | } 52 | Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type->type, false); 53 | if (!klass) 54 | { 55 | return false; 56 | } 57 | metadata::Image* image = metadata::MetadataModule::GetImage(klass->image); 58 | if (!image) 59 | { 60 | (metadata::Image*)hybridclr::metadata::AOTHomologousImage::FindImageByAssembly( 61 | klass->rank ? il2cpp_defaults.corlib->assembly : klass->image->assembly); 62 | if (!image) 63 | { 64 | return false; 65 | } 66 | } 67 | for (uint16_t i = 0; i < klass->method_count; i++) 68 | { 69 | const MethodInfo* methodInfo = klass->methods[i]; 70 | PreJitMethod0(methodInfo); 71 | } 72 | return true; 73 | } 74 | 75 | int32_t PreJitMethod0(const MethodInfo* methodInfo) 76 | { 77 | if (!methodInfo->isInterpterImpl) 78 | { 79 | return false; 80 | } 81 | if (!methodInfo->is_inflated) 82 | { 83 | if (methodInfo->is_generic) 84 | { 85 | return false; 86 | } 87 | } 88 | else 89 | { 90 | const Il2CppGenericMethod* genericMethod = methodInfo->genericMethod; 91 | if (metadata::HasNotInstantiatedGenericType(genericMethod->context.class_inst) || metadata::HasNotInstantiatedGenericType(genericMethod->context.method_inst)) 92 | { 93 | return false; 94 | } 95 | } 96 | 97 | return interpreter::InterpreterModule::GetInterpMethodInfo(methodInfo) != nullptr; 98 | } 99 | 100 | int32_t RuntimeApi::PreJitMethod(Il2CppReflectionMethod* method) 101 | { 102 | return PreJitMethod0(method->method); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /hybridclr/RuntimeApi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CommonDef.h" 5 | 6 | namespace hybridclr 7 | { 8 | class RuntimeApi 9 | { 10 | public: 11 | static void RegisterInternalCalls(); 12 | 13 | static int32_t LoadMetadataForAOTAssembly(Il2CppArray* dllData, int32_t mode); 14 | 15 | static int32_t GetRuntimeOption(int32_t optionId); 16 | static void SetRuntimeOption(int32_t optionId, int32_t value); 17 | 18 | static int32_t PreJitClass(Il2CppReflectionType* type); 19 | static int32_t PreJitMethod(Il2CppReflectionMethod* method); 20 | }; 21 | } -------------------------------------------------------------------------------- /hybridclr/RuntimeConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "RuntimeConfig.h" 2 | 3 | #include "vm/Exception.h" 4 | 5 | namespace hybridclr 6 | { 7 | static int32_t s_threadObjectStackSize = 1024 * 128; 8 | static int32_t s_threadFrameStackSize = 1024 * 2; 9 | static int32_t s_threadExceptionFlowSize = 512; 10 | static int32_t s_maxMethodBodyCacheSize = 1024; 11 | static int32_t s_maxMethodInlineDepth = 3; 12 | static int32_t s_maxInlineableMethodBodySize = 32; 13 | 14 | 15 | 16 | int32_t RuntimeConfig::GetRuntimeOption(RuntimeOptionId optionId) 17 | { 18 | switch (optionId) 19 | { 20 | case RuntimeOptionId::InterpreterThreadObjectStackSize: 21 | return s_threadObjectStackSize; 22 | case RuntimeOptionId::InterpreterThreadFrameStackSize: 23 | return s_threadFrameStackSize; 24 | case RuntimeOptionId::InterpreterThreadExceptionFlowSize: 25 | return s_threadExceptionFlowSize; 26 | case RuntimeOptionId::MaxMethodBodyCacheSize: 27 | return s_maxMethodBodyCacheSize; 28 | case RuntimeOptionId::MaxMethodInlineDepth: 29 | return s_maxMethodInlineDepth; 30 | default: 31 | { 32 | TEMP_FORMAT(optionIdStr, "%d", optionId); 33 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetArgumentException(optionIdStr, "invalid runtime option id")); 34 | return 0; 35 | } 36 | } 37 | } 38 | 39 | void RuntimeConfig::SetRuntimeOption(RuntimeOptionId optionId, int32_t value) 40 | { 41 | switch (optionId) 42 | { 43 | case hybridclr::RuntimeOptionId::InterpreterThreadObjectStackSize: 44 | s_threadObjectStackSize = value; 45 | break; 46 | case hybridclr::RuntimeOptionId::InterpreterThreadFrameStackSize: 47 | s_threadFrameStackSize = value; 48 | break; 49 | case hybridclr::RuntimeOptionId::InterpreterThreadExceptionFlowSize: 50 | s_threadExceptionFlowSize = value; 51 | break; 52 | case RuntimeOptionId::MaxMethodBodyCacheSize: 53 | s_maxMethodBodyCacheSize = value; 54 | break; 55 | case RuntimeOptionId::MaxMethodInlineDepth: 56 | s_maxMethodInlineDepth = value; 57 | break; 58 | default: 59 | { 60 | TEMP_FORMAT(optionIdStr, "%d", optionId); 61 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetArgumentException(optionIdStr, "invalid runtime option id")); 62 | break; 63 | } 64 | } 65 | } 66 | 67 | uint32_t RuntimeConfig::GetInterpreterThreadObjectStackSize() 68 | { 69 | return s_threadObjectStackSize; 70 | } 71 | 72 | uint32_t RuntimeConfig::GetInterpreterThreadFrameStackSize() 73 | { 74 | return s_threadFrameStackSize; 75 | } 76 | 77 | uint32_t RuntimeConfig::GetInterpreterThreadExceptionFlowSize() 78 | { 79 | return s_threadExceptionFlowSize; 80 | } 81 | 82 | int32_t RuntimeConfig::GetMaxMethodBodyCacheSize() 83 | { 84 | return s_maxMethodBodyCacheSize; 85 | } 86 | 87 | int32_t RuntimeConfig::GetMaxMethodInlineDepth() 88 | { 89 | return s_maxMethodInlineDepth; 90 | } 91 | 92 | int32_t RuntimeConfig::GetMaxInlineableMethodBodySize() 93 | { 94 | return s_maxInlineableMethodBodySize; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /hybridclr/RuntimeConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommonDef.h" 4 | 5 | namespace hybridclr 6 | { 7 | enum class RuntimeOptionId 8 | { 9 | InterpreterThreadObjectStackSize = 1, 10 | InterpreterThreadFrameStackSize = 2, 11 | InterpreterThreadExceptionFlowSize = 3, 12 | MaxMethodBodyCacheSize = 4, 13 | MaxMethodInlineDepth = 5, 14 | MaxInlineableMethodBodySize = 6, 15 | }; 16 | 17 | class RuntimeConfig 18 | { 19 | 20 | public: 21 | 22 | static int32_t GetRuntimeOption(RuntimeOptionId optionId); 23 | static void SetRuntimeOption(RuntimeOptionId optionId, int32_t value); 24 | 25 | static uint32_t GetInterpreterThreadObjectStackSize(); 26 | static uint32_t GetInterpreterThreadFrameStackSize(); 27 | static uint32_t GetInterpreterThreadExceptionFlowSize(); 28 | static int32_t GetMaxMethodBodyCacheSize(); 29 | static int32_t GetMaxMethodInlineDepth(); 30 | static int32_t GetMaxInlineableMethodBodySize(); 31 | }; 32 | } 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /hybridclr/generated/AssemblyManifest.cpp: -------------------------------------------------------------------------------- 1 | #include "../Il2CppCompatibleDef.h" 2 | 3 | namespace hybridclr 4 | { 5 | const char* g_placeHolderAssemblies[] = 6 | { 7 | //!!!{{PLACE_HOLDER 8 | 9 | //!!!}}PLACE_HOLDER 10 | nullptr, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /hybridclr/generated/MethodBridge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #if HYBRIDCLR_UNITY_2023_OR_NEW 3 | #include 4 | #elif HYBRIDCLR_UNITY_2022 5 | #include 6 | #elif HYBRIDCLR_UNITY_2020 || HYBRIDCLR_UNITY_2021 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "vm/ClassInlines.h" 13 | #include "vm/Object.h" 14 | #include "vm/Class.h" 15 | #include "vm/ScopedThreadAttacher.h" 16 | 17 | #include "../metadata/MetadataUtil.h" 18 | 19 | 20 | #include "../interpreter/InterpreterModule.h" 21 | #include "../interpreter/MethodBridge.h" 22 | #include "../interpreter/Interpreter.h" 23 | #include "../interpreter/MemoryUtil.h" 24 | #include "../interpreter/InstrinctDef.h" 25 | 26 | using namespace hybridclr::interpreter; 27 | using namespace hybridclr::metadata; 28 | 29 | //!!!{{CODE 30 | 31 | const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = { 32 | { nullptr, nullptr}, 33 | }; 34 | 35 | 36 | const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = 37 | { 38 | 39 | {nullptr, nullptr}, 40 | }; 41 | 42 | 43 | const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = 44 | { 45 | {nullptr, nullptr}, 46 | }; 47 | 48 | const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = 49 | { 50 | {nullptr, nullptr}, 51 | }; 52 | 53 | const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStub[] 54 | { 55 | {nullptr, nullptr}, 56 | }; 57 | 58 | const Managed2NativeFunctionPointerCallData hybridclr::interpreter::g_managed2NativeFunctionPointerCallStub[] 59 | { 60 | {nullptr, nullptr}, 61 | }; 62 | //!!!}}CODE 63 | -------------------------------------------------------------------------------- /hybridclr/generated/UnityVersion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //!!!{{UNITY_VERSION 4 | 5 | 6 | 7 | //!!!}}UNITY_VERSION -------------------------------------------------------------------------------- /hybridclr/interpreter/Engine.cpp: -------------------------------------------------------------------------------- 1 | #include "Engine.h" 2 | 3 | #include "codegen/il2cpp-codegen.h" 4 | 5 | #include "Interpreter.h" 6 | #include "MemoryUtil.h" 7 | #include "../metadata/InterpreterImage.h" 8 | #include "../metadata/MetadataModule.h" 9 | 10 | namespace hybridclr 11 | { 12 | namespace interpreter 13 | { 14 | 15 | #if HYBRIDCLR_ENABLE_STRACKTRACE 16 | 17 | #define PUSH_STACK_FRAME(method, rawIp) do { \ 18 | Il2CppStackFrameInfo stackFrameInfo = { method, rawIp }; \ 19 | il2cpp::vm::StackTrace::PushFrame(stackFrameInfo); \ 20 | } while(0) 21 | 22 | #define POP_STACK_FRAME() do { il2cpp::vm::StackTrace::PopFrame(); } while(0) 23 | 24 | #else 25 | #define PUSH_STACK_FRAME(method, rawIp) 26 | #define POP_STACK_FRAME() 27 | #endif 28 | 29 | InterpFrame* InterpFrameGroup::EnterFrameFromInterpreter(const MethodInfo* method, StackObject* argBase) 30 | { 31 | #if HYBRIDCLR_ENABLE_PROFILER 32 | il2cpp_codegen_profiler_method_enter(method); 33 | #endif 34 | const InterpMethodInfo* imi = (const InterpMethodInfo*)method->interpData; 35 | int32_t oldStackTop = _machineState.GetStackTop(); 36 | StackObject* stackBasePtr = _machineState.AllocStackSlot(imi->maxStackSize - imi->argStackObjectSize); 37 | InterpFrame* newFrame = _machineState.PushFrame(); 38 | *newFrame = { method, argBase, oldStackTop, nullptr, nullptr, nullptr, 0, 0, _machineState.GetLocalPoolBottomIdx() }; 39 | PUSH_STACK_FRAME(method, (uintptr_t)newFrame); 40 | return newFrame; 41 | } 42 | 43 | 44 | InterpFrame* InterpFrameGroup::EnterFrameFromNative(const MethodInfo* method, StackObject* argBase) 45 | { 46 | #if HYBRIDCLR_ENABLE_PROFILER 47 | il2cpp_codegen_profiler_method_enter(method); 48 | #endif 49 | const InterpMethodInfo* imi = (const InterpMethodInfo*)method->interpData; 50 | int32_t oldStackTop = _machineState.GetStackTop(); 51 | StackObject* stackBasePtr = _machineState.AllocStackSlot(imi->maxStackSize); 52 | InterpFrame* newFrame = _machineState.PushFrame(); 53 | *newFrame = { method, stackBasePtr, oldStackTop, nullptr, nullptr, nullptr, 0, 0, _machineState.GetLocalPoolBottomIdx() }; 54 | 55 | // if not prepare arg stack. copy from args 56 | if (imi->args) 57 | { 58 | IL2CPP_ASSERT(imi->argCount == metadata::GetActualArgumentNum(method)); 59 | CopyStackObject(stackBasePtr, argBase, imi->argStackObjectSize); 60 | } 61 | PUSH_STACK_FRAME(method, (uintptr_t)newFrame); 62 | return newFrame; 63 | } 64 | 65 | InterpFrame* InterpFrameGroup::LeaveFrame() 66 | { 67 | IL2CPP_ASSERT(_machineState.GetFrameTopIdx() > _frameBaseIdx); 68 | POP_STACK_FRAME(); 69 | InterpFrame* frame = _machineState.GetTopFrame(); 70 | #if HYBRIDCLR_ENABLE_PROFILER 71 | il2cpp_codegen_profiler_method_exit(frame->method); 72 | #endif 73 | if (frame->exFlowBase) 74 | { 75 | _machineState.SetExceptionFlowTop(frame->exFlowBase); 76 | } 77 | _machineState.PopFrame(); 78 | _machineState.SetStackTop(frame->oldStackTop); 79 | _machineState.SetLocalPoolBottomIdx(frame->oldLocalPoolBottomIdx); 80 | return _machineState.GetFrameTopIdx() > _frameBaseIdx ? _machineState.GetTopFrame() : nullptr; 81 | } 82 | 83 | static bool FrameNeedsSkipped(const Il2CppStackFrameInfo& frame) 84 | { 85 | const MethodInfo* method = frame.method; 86 | const Il2CppClass* klass = method->klass; 87 | return (strcmp(klass->namespaze, "System.Diagnostics") == 0 && 88 | (strcmp(klass->name, "StackFrame") == 0 || strcmp(klass->name, "StackTrace") == 0)) 89 | || (strcmp(klass->namespaze, "UnityEngine") == 0 90 | && (strcmp(klass->name, "StackTraceUtility") == 0 91 | || strcmp(klass->name, "Debug") == 0 92 | || strcmp(klass->name, "Logger") == 0 93 | || strcmp(klass->name, "DebugLogHandler") == 0)); 94 | } 95 | 96 | static void SetupStackFrameInfo(const InterpFrame* frame, Il2CppStackFrameInfo& stackFrame) 97 | { 98 | const MethodInfo* method = frame->method; 99 | const InterpMethodInfo* imi = (const InterpMethodInfo*)method->interpData; 100 | const byte* actualIp = (const byte*)frame->ip; 101 | 102 | stackFrame.method = method; 103 | stackFrame.raw_ip = (uintptr_t)frame; 104 | 105 | if (!hybridclr::metadata::IsInterpreterMethod(method)) 106 | { 107 | return; 108 | } 109 | 110 | hybridclr::metadata::InterpreterImage* interpImage = hybridclr::metadata::MetadataModule::GetImage(method); 111 | if (!interpImage) 112 | { 113 | return; 114 | } 115 | 116 | hybridclr::metadata::PDBImage* pdbImage = interpImage->GetPDBImage(); 117 | if (!pdbImage) 118 | { 119 | return; 120 | } 121 | pdbImage->SetupStackFrameInfo(method, actualIp, stackFrame); 122 | } 123 | 124 | void MachineState::CollectFrames(il2cpp::vm::StackFrames* stackFrames) 125 | { 126 | if (_frameTopIdx <= 0) 127 | { 128 | return; 129 | } 130 | size_t insertIndex = 0; 131 | for (; insertIndex < stackFrames->size(); insertIndex++) 132 | { 133 | if (FrameNeedsSkipped((*stackFrames)[insertIndex])) 134 | { 135 | break; 136 | } 137 | } 138 | stackFrames->insert(stackFrames->begin() + insertIndex, _frameTopIdx, Il2CppStackFrameInfo()); 139 | for (int32_t i = 0; i < _frameTopIdx; i++) 140 | { 141 | SetupStackFrameInfo(_frameBase + i, (*stackFrames)[insertIndex + i]); 142 | } 143 | } 144 | 145 | void MachineState::SetupFramesDebugInfo(il2cpp::vm::StackFrames* stackFrames) 146 | { 147 | for (Il2CppStackFrameInfo& frame : *stackFrames) 148 | { 149 | if (frame.method && hybridclr::metadata::IsInterpreterImplement(frame.method)) 150 | { 151 | hybridclr::metadata::InterpreterImage* interpImage = hybridclr::metadata::MetadataModule::GetImage(frame.method); 152 | if (interpImage) 153 | { 154 | hybridclr::metadata::PDBImage* pdbImage = interpImage->GetPDBImage(); 155 | if (pdbImage) 156 | { 157 | pdbImage->SetupStackFrameInfo(frame.method, (const byte*)(((InterpFrame*)frame.raw_ip)->ip), frame); 158 | } 159 | } 160 | } 161 | } 162 | } 163 | } 164 | } 165 | 166 | -------------------------------------------------------------------------------- /hybridclr/interpreter/Engine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../CommonDef.h" 6 | 7 | #include "gc/GarbageCollector.h" 8 | #include "vm/Exception.h" 9 | #include "vm/StackTrace.h" 10 | 11 | #include "../metadata/MetadataUtil.h" 12 | #include "../RuntimeConfig.h" 13 | 14 | #include "InterpreterDefs.h" 15 | #include "MemoryUtil.h" 16 | #include "MethodBridge.h" 17 | #include 18 | 19 | namespace hybridclr 20 | { 21 | namespace interpreter 22 | { 23 | 24 | class MachineState 25 | { 26 | public: 27 | MachineState() 28 | { 29 | _stackSize = -1; 30 | _stackBase = nullptr; 31 | _stackTopIdx = 0; 32 | _localPoolBottomIdx = -1; 33 | 34 | _frameBase = nullptr; 35 | _frameCount = -1; 36 | _frameTopIdx = 0; 37 | 38 | _exceptionFlowBase = nullptr; 39 | _exceptionFlowCount = -1; 40 | _exceptionFlowTopIdx = 0; 41 | } 42 | 43 | ~MachineState() 44 | { 45 | if (_stackBase) 46 | { 47 | //il2cpp::gc::GarbageCollector::FreeFixed(_stackBase); 48 | il2cpp::gc::GarbageCollector::UnregisterDynamicRoot(this); 49 | HYBRIDCLR_FREE(_stackBase); 50 | } 51 | if (_frameBase) 52 | { 53 | HYBRIDCLR_FREE(_frameBase); 54 | } 55 | if (_exceptionFlowBase) 56 | { 57 | HYBRIDCLR_FREE(_exceptionFlowBase); 58 | } 59 | } 60 | 61 | static std::pair GetGCRootData(void* root) 62 | { 63 | MachineState* machineState = (MachineState*)root; 64 | if (machineState->_stackBase && machineState->_stackTopIdx > 0) 65 | { 66 | return std::make_pair((char*)machineState->_stackBase, machineState->_stackTopIdx * sizeof(StackObject)); 67 | } 68 | else 69 | { 70 | return std::make_pair(nullptr, 0); 71 | } 72 | } 73 | 74 | StackObject* AllocArgments(int32_t argCount) 75 | { 76 | return AllocStackSlot(argCount); 77 | } 78 | 79 | StackObject* GetStackBasePtr() const 80 | { 81 | return _stackBase; 82 | } 83 | 84 | int32_t GetStackTop() const 85 | { 86 | return _stackTopIdx; 87 | } 88 | 89 | StackObject* AllocStackSlot(int32_t slotNum) 90 | { 91 | if (_stackTopIdx + slotNum > _localPoolBottomIdx) 92 | { 93 | if (!_stackBase) 94 | { 95 | InitEvalStack(); 96 | } 97 | if (_stackTopIdx + slotNum > _localPoolBottomIdx) 98 | { 99 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetStackOverflowException("AllocStackSlot")); 100 | } 101 | } 102 | StackObject* dataPtr = _stackBase + _stackTopIdx; 103 | _stackTopIdx += slotNum; 104 | #if DEBUG 105 | std::memset(dataPtr, 0xEA, slotNum * sizeof(StackObject)); 106 | #endif 107 | return dataPtr; 108 | } 109 | 110 | void* AllocLocalloc(size_t size) 111 | { 112 | IL2CPP_ASSERT(size % 8 == 0); 113 | int32_t slotNum = (int32_t)(size / 8); 114 | IL2CPP_ASSERT(slotNum > 0); 115 | if (_stackTopIdx + slotNum > _localPoolBottomIdx) 116 | { 117 | if (!_stackBase) 118 | { 119 | InitEvalStack(); 120 | } 121 | if (_stackTopIdx + slotNum > _localPoolBottomIdx) 122 | { 123 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetStackOverflowException("AllocLocalloc")); 124 | } 125 | } 126 | _localPoolBottomIdx -= slotNum; 127 | return _stackBase + _localPoolBottomIdx; 128 | } 129 | 130 | void SetStackTop(int32_t oldTop) 131 | { 132 | _stackTopIdx = oldTop; 133 | } 134 | 135 | uint32_t GetFrameTopIdx() const 136 | { 137 | return _frameTopIdx; 138 | } 139 | 140 | int32_t GetLocalPoolBottomIdx() const 141 | { 142 | return _localPoolBottomIdx; 143 | } 144 | 145 | void SetLocalPoolBottomIdx(int32_t idx) 146 | { 147 | _localPoolBottomIdx = idx; 148 | } 149 | 150 | InterpFrame* PushFrame() 151 | { 152 | if (_frameTopIdx >= _frameCount) 153 | { 154 | if (!_frameBase) 155 | { 156 | InitFrames(); 157 | } 158 | else 159 | { 160 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetStackOverflowException("AllocFrame")); 161 | } 162 | } 163 | return _frameBase + _frameTopIdx++; 164 | } 165 | 166 | void PopFrame() 167 | { 168 | IL2CPP_ASSERT(_frameTopIdx > 0); 169 | --_frameTopIdx; 170 | } 171 | 172 | void PopFrameN(int32_t count) 173 | { 174 | IL2CPP_ASSERT(count > 0 && _frameTopIdx >= count); 175 | _frameTopIdx -= count; 176 | } 177 | 178 | InterpFrame* GetTopFrame() const 179 | { 180 | if (_frameTopIdx > 0) 181 | { 182 | return _frameBase + _frameTopIdx - 1; 183 | } 184 | else 185 | { 186 | return nullptr; 187 | } 188 | } 189 | 190 | ExceptionFlowInfo* AllocExceptionFlow(int32_t count) 191 | { 192 | if (_exceptionFlowTopIdx + count >= _exceptionFlowCount) 193 | { 194 | if (!_exceptionFlowBase) 195 | { 196 | InitExceptionFlows(); 197 | } 198 | if (_exceptionFlowTopIdx + count >= _exceptionFlowCount) 199 | { 200 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException("AllocExceptionFlowZero")); 201 | } 202 | } 203 | ExceptionFlowInfo* efi = _exceptionFlowBase + _exceptionFlowTopIdx; 204 | _exceptionFlowTopIdx += count; 205 | return efi; 206 | } 207 | 208 | uint32_t GetExceptionFlowTopIdx() const 209 | { 210 | return _exceptionFlowTopIdx; 211 | } 212 | 213 | void SetExceptionFlowTopIdx(uint32_t exTopIdx) 214 | { 215 | _exceptionFlowTopIdx = exTopIdx; 216 | } 217 | 218 | void SetExceptionFlowTop(ExceptionFlowInfo* top) 219 | { 220 | _exceptionFlowTopIdx = (int32_t)(top - _exceptionFlowBase); 221 | IL2CPP_ASSERT(_exceptionFlowTopIdx >= 0 && _exceptionFlowTopIdx <= _exceptionFlowCount); 222 | } 223 | 224 | void PushExecutingImage(const Il2CppImage* image) 225 | { 226 | _executingImageStack.push(image); 227 | } 228 | 229 | void PopExecutingImage() 230 | { 231 | _executingImageStack.pop(); 232 | } 233 | 234 | const Il2CppImage* GetTopExecutingImage() const 235 | { 236 | if (_executingImageStack.empty()) 237 | { 238 | return nullptr; 239 | } 240 | else 241 | { 242 | return _executingImageStack.top(); 243 | } 244 | } 245 | 246 | void CollectFrames(il2cpp::vm::StackFrames* stackFrames); 247 | void SetupFramesDebugInfo(il2cpp::vm::StackFrames* stackFrames); 248 | 249 | private: 250 | 251 | 252 | void InitEvalStack() 253 | { 254 | _stackSize = (int32_t)RuntimeConfig::GetInterpreterThreadObjectStackSize(); 255 | _stackBase = (StackObject*)HYBRIDCLR_MALLOC_ZERO(RuntimeConfig::GetInterpreterThreadObjectStackSize() * sizeof(StackObject)); 256 | _stackTopIdx = 0; 257 | _localPoolBottomIdx = _stackSize; 258 | il2cpp::gc::GarbageCollector::RegisterDynamicRoot(this, GetGCRootData); 259 | } 260 | 261 | void InitFrames() 262 | { 263 | _frameBase = (InterpFrame*)HYBRIDCLR_CALLOC(RuntimeConfig::GetInterpreterThreadFrameStackSize(), sizeof(InterpFrame)); 264 | _frameCount = (int32_t)RuntimeConfig::GetInterpreterThreadFrameStackSize(); 265 | _frameTopIdx = 0; 266 | } 267 | 268 | void InitExceptionFlows() 269 | { 270 | _exceptionFlowBase = (ExceptionFlowInfo*)HYBRIDCLR_CALLOC(RuntimeConfig::GetInterpreterThreadExceptionFlowSize(), sizeof(ExceptionFlowInfo)); 271 | _exceptionFlowCount = (int32_t)RuntimeConfig::GetInterpreterThreadExceptionFlowSize(); 272 | _exceptionFlowTopIdx = 0; 273 | } 274 | 275 | StackObject* _stackBase; 276 | int32_t _stackSize; 277 | int32_t _stackTopIdx; 278 | int32_t _localPoolBottomIdx; 279 | 280 | InterpFrame* _frameBase; 281 | int32_t _frameTopIdx; 282 | int32_t _frameCount; 283 | 284 | ExceptionFlowInfo* _exceptionFlowBase; 285 | int32_t _exceptionFlowTopIdx; 286 | int32_t _exceptionFlowCount; 287 | 288 | 289 | std::stack _executingImageStack; 290 | }; 291 | 292 | class ExecutingInterpImageScope 293 | { 294 | public: 295 | ExecutingInterpImageScope(MachineState& state, const Il2CppImage* image) : _state(state) 296 | { 297 | _state.PushExecutingImage(image); 298 | } 299 | 300 | ~ExecutingInterpImageScope() 301 | { 302 | _state.PopExecutingImage(); 303 | } 304 | 305 | private: 306 | MachineState& _state; 307 | }; 308 | 309 | class InterpFrameGroup 310 | { 311 | public: 312 | InterpFrameGroup(MachineState& ms) : _machineState(ms), _stackBaseIdx(ms.GetStackTop()), _frameBaseIdx(ms.GetFrameTopIdx()) 313 | { 314 | 315 | } 316 | 317 | void CleanUpFrames() 318 | { 319 | IL2CPP_ASSERT(_machineState.GetFrameTopIdx() >= _frameBaseIdx); 320 | uint32_t n = _machineState.GetFrameTopIdx() - _frameBaseIdx; 321 | if (n > 0) 322 | { 323 | for (uint32_t i = 0; i < n; i++) 324 | { 325 | LeaveFrame(); 326 | } 327 | } 328 | } 329 | 330 | InterpFrame* EnterFrameFromInterpreter(const MethodInfo* method, StackObject* argBase); 331 | 332 | InterpFrame* EnterFrameFromNative(const MethodInfo* method, StackObject* argBase); 333 | 334 | InterpFrame* LeaveFrame(); 335 | 336 | void* AllocLoc(size_t originSize, bool fillZero) 337 | { 338 | if (originSize == 0) 339 | { 340 | return nullptr; 341 | } 342 | size_t size = (originSize + 7) & ~(size_t)7; 343 | void* data = _machineState.AllocLocalloc(size); 344 | if (fillZero) 345 | { 346 | std::memset(data, 0, size); 347 | } 348 | return data; 349 | } 350 | 351 | size_t GetFrameCount() const { return _machineState.GetFrameTopIdx() - _frameBaseIdx; } 352 | private: 353 | MachineState& _machineState; 354 | int32_t _stackBaseIdx; 355 | uint32_t _frameBaseIdx; 356 | }; 357 | } 358 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/InstrinctDef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../CommonDef.h" 3 | 4 | namespace hybridclr 5 | { 6 | namespace interpreter 7 | { 8 | 9 | struct HtVector2f 10 | { 11 | float x; 12 | float y; 13 | }; 14 | static_assert(sizeof(HtVector2f) == 8, "Vector2f"); 15 | 16 | struct HtVector3f 17 | { 18 | float x; 19 | float y; 20 | float z; 21 | }; 22 | static_assert(sizeof(HtVector3f) == 12, "Vector3f"); 23 | 24 | struct HtVector4f 25 | { 26 | float x; 27 | float y; 28 | float z; 29 | float w; 30 | }; 31 | static_assert(sizeof(HtVector4f) == 16, "Vector4f"); 32 | 33 | struct HtVector2d 34 | { 35 | double x; 36 | double y; 37 | }; 38 | static_assert(sizeof(HtVector2d) == 16, "Vector2d"); 39 | 40 | struct HtVector3d 41 | { 42 | double x; 43 | double y; 44 | double z; 45 | }; 46 | static_assert(sizeof(HtVector3d) == 24, "Vector3d"); 47 | 48 | struct HtVector4d 49 | { 50 | double x; 51 | double y; 52 | double z; 53 | double w; 54 | }; 55 | static_assert(sizeof(HtVector4d) == 32, "Vector4d"); 56 | 57 | struct HtVector2i 58 | { 59 | int32_t x; 60 | int32_t y; 61 | }; 62 | static_assert(sizeof(HtVector2i) == 8, "IntVector2i"); 63 | 64 | struct HtVector3i 65 | { 66 | int32_t x; 67 | int32_t y; 68 | int32_t z; 69 | }; 70 | static_assert(sizeof(HtVector3i) == 12, "IntVector3i"); 71 | 72 | struct HtVector4i 73 | { 74 | int32_t x; 75 | int32_t y; 76 | int32_t z; 77 | int32_t w; 78 | }; 79 | static_assert(sizeof(HtVector4i) == 16, "IntVector4i"); 80 | 81 | #pragma endregion 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /hybridclr/interpreter/Instruction.cpp: -------------------------------------------------------------------------------- 1 | #include "Instruction.h" 2 | 3 | namespace hybridclr 4 | { 5 | namespace interpreter 6 | { 7 | uint16_t g_instructionSizes[] = 8 | { 9 | 0, 10 | //!!!{{INST_SIZE 11 | 8, 12 | 8, 13 | 8, 14 | 8, 15 | 8, 16 | 8, 17 | 8, 18 | 16, 19 | 8, 20 | 8, 21 | 8, 22 | 8, 23 | 8, 24 | 8, 25 | 8, 26 | 8, 27 | 8, 28 | 8, 29 | 8, 30 | 8, 31 | 8, 32 | 8, 33 | 16, 34 | 8, 35 | 8, 36 | 8, 37 | 8, 38 | 8, 39 | 8, 40 | 8, 41 | 8, 42 | 8, 43 | 8, 44 | 8, 45 | 8, 46 | 8, 47 | 8, 48 | 8, 49 | 8, 50 | 8, 51 | 8, 52 | 8, 53 | 8, 54 | 8, 55 | 8, 56 | 8, 57 | 8, 58 | 8, 59 | 8, 60 | 8, 61 | 8, 62 | 8, 63 | 8, 64 | 8, 65 | 8, 66 | 8, 67 | 8, 68 | 8, 69 | 8, 70 | 8, 71 | 8, 72 | 8, 73 | 8, 74 | 8, 75 | 8, 76 | 8, 77 | 8, 78 | 8, 79 | 8, 80 | 8, 81 | 8, 82 | 8, 83 | 8, 84 | 8, 85 | 8, 86 | 8, 87 | 8, 88 | 8, 89 | 8, 90 | 8, 91 | 8, 92 | 8, 93 | 8, 94 | 8, 95 | 8, 96 | 8, 97 | 8, 98 | 8, 99 | 8, 100 | 8, 101 | 8, 102 | 8, 103 | 8, 104 | 8, 105 | 8, 106 | 8, 107 | 8, 108 | 8, 109 | 8, 110 | 8, 111 | 8, 112 | 8, 113 | 8, 114 | 8, 115 | 8, 116 | 8, 117 | 8, 118 | 8, 119 | 8, 120 | 8, 121 | 8, 122 | 8, 123 | 8, 124 | 8, 125 | 8, 126 | 8, 127 | 8, 128 | 8, 129 | 8, 130 | 8, 131 | 8, 132 | 8, 133 | 8, 134 | 8, 135 | 8, 136 | 8, 137 | 8, 138 | 8, 139 | 8, 140 | 8, 141 | 8, 142 | 8, 143 | 8, 144 | 8, 145 | 8, 146 | 8, 147 | 8, 148 | 8, 149 | 8, 150 | 8, 151 | 8, 152 | 8, 153 | 8, 154 | 8, 155 | 8, 156 | 8, 157 | 8, 158 | 8, 159 | 8, 160 | 8, 161 | 8, 162 | 8, 163 | 8, 164 | 8, 165 | 8, 166 | 8, 167 | 8, 168 | 8, 169 | 8, 170 | 8, 171 | 8, 172 | 8, 173 | 8, 174 | 8, 175 | 8, 176 | 8, 177 | 8, 178 | 8, 179 | 8, 180 | 8, 181 | 8, 182 | 8, 183 | 8, 184 | 8, 185 | 8, 186 | 8, 187 | 8, 188 | 8, 189 | 8, 190 | 8, 191 | 8, 192 | 8, 193 | 8, 194 | 8, 195 | 8, 196 | 8, 197 | 8, 198 | 8, 199 | 8, 200 | 8, 201 | 8, 202 | 8, 203 | 8, 204 | 8, 205 | 8, 206 | 8, 207 | 8, 208 | 8, 209 | 8, 210 | 8, 211 | 8, 212 | 8, 213 | 8, 214 | 8, 215 | 8, 216 | 8, 217 | 8, 218 | 8, 219 | 8, 220 | 8, 221 | 8, 222 | 8, 223 | 8, 224 | 8, 225 | 8, 226 | 8, 227 | 8, 228 | 8, 229 | 8, 230 | 8, 231 | 8, 232 | 8, 233 | 8, 234 | 8, 235 | 8, 236 | 8, 237 | 8, 238 | 8, 239 | 8, 240 | 8, 241 | 8, 242 | 8, 243 | 8, 244 | 8, 245 | 8, 246 | 8, 247 | 8, 248 | 8, 249 | 8, 250 | 8, 251 | 8, 252 | 8, 253 | 16, 254 | 16, 255 | 16, 256 | 16, 257 | 16, 258 | 16, 259 | 16, 260 | 16, 261 | 16, 262 | 16, 263 | 16, 264 | 16, 265 | 16, 266 | 16, 267 | 16, 268 | 16, 269 | 16, 270 | 16, 271 | 16, 272 | 16, 273 | 16, 274 | 16, 275 | 16, 276 | 16, 277 | 16, 278 | 16, 279 | 16, 280 | 16, 281 | 16, 282 | 16, 283 | 16, 284 | 16, 285 | 16, 286 | 16, 287 | 16, 288 | 16, 289 | 16, 290 | 16, 291 | 16, 292 | 16, 293 | 8, 294 | 16, 295 | 16, 296 | 8, 297 | 8, 298 | 16, 299 | 16, 300 | 16, 301 | 16, 302 | 8, 303 | 16, 304 | 16, 305 | 8, 306 | 8, 307 | 8, 308 | 8, 309 | 8, 310 | 8, 311 | 8, 312 | 8, 313 | 8, 314 | 8, 315 | 8, 316 | 8, 317 | 16, 318 | 16, 319 | 24, 320 | 16, 321 | 16, 322 | 24, 323 | 8, 324 | 16, 325 | 16, 326 | 16, 327 | 24, 328 | 8, 329 | 16, 330 | 24, 331 | 24, 332 | 24, 333 | 16, 334 | 16, 335 | 24, 336 | 16, 337 | 24, 338 | 24, 339 | 16, 340 | 8, 341 | 16, 342 | 16, 343 | 16, 344 | 8, 345 | 16, 346 | 16, 347 | 16, 348 | 16, 349 | 16, 350 | 16, 351 | 16, 352 | 16, 353 | 16, 354 | 16, 355 | 16, 356 | 16, 357 | 16, 358 | 16, 359 | 16, 360 | 16, 361 | 16, 362 | 16, 363 | 16, 364 | 16, 365 | 16, 366 | 16, 367 | 16, 368 | 16, 369 | 16, 370 | 16, 371 | 16, 372 | 24, 373 | 16, 374 | 16, 375 | 16, 376 | 24, 377 | 16, 378 | 16, 379 | 16, 380 | 24, 381 | 16, 382 | 16, 383 | 16, 384 | 24, 385 | 16, 386 | 16, 387 | 16, 388 | 24, 389 | 16, 390 | 16, 391 | 16, 392 | 24, 393 | 16, 394 | 16, 395 | 16, 396 | 24, 397 | 16, 398 | 16, 399 | 16, 400 | 24, 401 | 16, 402 | 16, 403 | 16, 404 | 24, 405 | 16, 406 | 16, 407 | 16, 408 | 24, 409 | 16, 410 | 16, 411 | 16, 412 | 24, 413 | 16, 414 | 16, 415 | 16, 416 | 24, 417 | 16, 418 | 16, 419 | 16, 420 | 24, 421 | 16, 422 | 16, 423 | 16, 424 | 24, 425 | 16, 426 | 16, 427 | 16, 428 | 24, 429 | 16, 430 | 16, 431 | 16, 432 | 24, 433 | 16, 434 | 16, 435 | 16, 436 | 24, 437 | 16, 438 | 16, 439 | 16, 440 | 24, 441 | 16, 442 | 16, 443 | 16, 444 | 24, 445 | 16, 446 | 16, 447 | 16, 448 | 24, 449 | 8, 450 | 8, 451 | 8, 452 | 8, 453 | 8, 454 | 8, 455 | 8, 456 | 8, 457 | 8, 458 | 8, 459 | 16, 460 | 16, 461 | 16, 462 | 8, 463 | 16, 464 | 16, 465 | 16, 466 | 8, 467 | 16, 468 | 16, 469 | 16, 470 | 8, 471 | 16, 472 | 16, 473 | 16, 474 | 16, 475 | 16, 476 | 16, 477 | 16, 478 | 16, 479 | 16, 480 | 16, 481 | 16, 482 | 16, 483 | 16, 484 | 16, 485 | 16, 486 | 16, 487 | 16, 488 | 16, 489 | 16, 490 | 16, 491 | 16, 492 | 16, 493 | 16, 494 | 16, 495 | 16, 496 | 16, 497 | 16, 498 | 16, 499 | 16, 500 | 16, 501 | 16, 502 | 16, 503 | 16, 504 | 16, 505 | 16, 506 | 16, 507 | 16, 508 | 16, 509 | 16, 510 | 16, 511 | 16, 512 | 16, 513 | 16, 514 | 16, 515 | 16, 516 | 16, 517 | 16, 518 | 16, 519 | 16, 520 | 16, 521 | 16, 522 | 16, 523 | 16, 524 | 16, 525 | 16, 526 | 16, 527 | 16, 528 | 16, 529 | 16, 530 | 16, 531 | 16, 532 | 16, 533 | 16, 534 | 16, 535 | 16, 536 | 16, 537 | 16, 538 | 16, 539 | 16, 540 | 16, 541 | 16, 542 | 16, 543 | 16, 544 | 16, 545 | 16, 546 | 16, 547 | 16, 548 | 16, 549 | 16, 550 | 16, 551 | 16, 552 | 16, 553 | 16, 554 | 16, 555 | 16, 556 | 16, 557 | 8, 558 | 8, 559 | 8, 560 | 16, 561 | 8, 562 | 16, 563 | 8, 564 | 8, 565 | 8, 566 | 8, 567 | 8, 568 | 8, 569 | 8, 570 | 8, 571 | 8, 572 | 8, 573 | 8, 574 | 8, 575 | 16, 576 | 8, 577 | 16, 578 | 8, 579 | 8, 580 | 8, 581 | 8, 582 | 8, 583 | 8, 584 | 8, 585 | 8, 586 | 8, 587 | 8, 588 | 8, 589 | 16, 590 | 8, 591 | 8, 592 | 8, 593 | 8, 594 | 8, 595 | 8, 596 | 8, 597 | 8, 598 | 8, 599 | 8, 600 | 8, 601 | 16, 602 | 16, 603 | 8, 604 | 8, 605 | 8, 606 | 8, 607 | 8, 608 | 8, 609 | 8, 610 | 8, 611 | 8, 612 | 8, 613 | 8, 614 | 8, 615 | 8, 616 | 8, 617 | 8, 618 | 8, 619 | 8, 620 | 8, 621 | 8, 622 | 8, 623 | 8, 624 | 8, 625 | 8, 626 | 8, 627 | 8, 628 | 8, 629 | 8, 630 | 8, 631 | 8, 632 | 8, 633 | 8, 634 | 16, 635 | 16, 636 | 8, 637 | 8, 638 | 8, 639 | 8, 640 | 8, 641 | 8, 642 | 8, 643 | 8, 644 | 8, 645 | 8, 646 | 8, 647 | 8, 648 | 8, 649 | 8, 650 | 8, 651 | 16, 652 | 16, 653 | 8, 654 | 8, 655 | 8, 656 | 8, 657 | 8, 658 | 8, 659 | 8, 660 | 8, 661 | 8, 662 | 8, 663 | 8, 664 | 8, 665 | 8, 666 | 8, 667 | 8, 668 | 8, 669 | 8, 670 | 16, 671 | 16, 672 | 16, 673 | 16, 674 | 16, 675 | 16, 676 | 16, 677 | 16, 678 | 16, 679 | 16, 680 | 16, 681 | 16, 682 | 16, 683 | 16, 684 | 16, 685 | 16, 686 | 16, 687 | 16, 688 | 16, 689 | 16, 690 | 16, 691 | 16, 692 | 16, 693 | 16, 694 | 16, 695 | 16, 696 | 16, 697 | 16, 698 | 16, 699 | 16, 700 | 16, 701 | 16, 702 | 16, 703 | 16, 704 | 16, 705 | 16, 706 | 16, 707 | 16, 708 | 16, 709 | 16, 710 | 16, 711 | 16, 712 | 8, 713 | 16, 714 | 16, 715 | 16, 716 | 16, 717 | 16, 718 | 16, 719 | 16, 720 | 16, 721 | 16, 722 | 16, 723 | 16, 724 | 16, 725 | 16, 726 | 16, 727 | 16, 728 | 16, 729 | 16, 730 | 16, 731 | 16, 732 | 16, 733 | 16, 734 | 16, 735 | 16, 736 | 16, 737 | 16, 738 | 16, 739 | 16, 740 | 16, 741 | 16, 742 | 16, 743 | 16, 744 | 16, 745 | 16, 746 | 16, 747 | 16, 748 | 16, 749 | 16, 750 | 16, 751 | 8, 752 | 16, 753 | 16, 754 | 8, 755 | 8, 756 | 16, 757 | 8, 758 | 8, 759 | 8, 760 | 8, 761 | 8, 762 | 8, 763 | 8, 764 | 8, 765 | 8, 766 | 8, 767 | 8, 768 | 8, 769 | 8, 770 | 8, 771 | 8, 772 | 8, 773 | 8, 774 | 8, 775 | 8, 776 | 8, 777 | 8, 778 | 8, 779 | 8, 780 | 8, 781 | 8, 782 | 8, 783 | 8, 784 | 8, 785 | 8, 786 | 8, 787 | 8, 788 | 8, 789 | 16, 790 | 16, 791 | 8, 792 | 8, 793 | 8, 794 | 8, 795 | 8, 796 | 8, 797 | 8, 798 | 8, 799 | 8, 800 | 8, 801 | 8, 802 | 8, 803 | 8, 804 | 8, 805 | 8, 806 | 8, 807 | 8, 808 | 8, 809 | 8, 810 | 8, 811 | 8, 812 | 8, 813 | 8, 814 | 8, 815 | 8, 816 | 8, 817 | 8, 818 | 16, 819 | 16, 820 | 16, 821 | 16, 822 | 16, 823 | 16, 824 | 16, 825 | 16, 826 | 16, 827 | 8, 828 | 8, 829 | 8, 830 | 8, 831 | 8, 832 | 8, 833 | 16, 834 | 8, 835 | 16, 836 | 16, 837 | 8, 838 | 8, 839 | 16, 840 | 8, 841 | 16, 842 | 16, 843 | 8, 844 | 8, 845 | 8, 846 | 16, 847 | 8, 848 | 8, 849 | 8, 850 | 8, 851 | 8, 852 | 853 | //!!!}}INST_SIZE 854 | }; 855 | } 856 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/Interpreter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Interpreter.h" 3 | 4 | #include 5 | 6 | #include "vm/GlobalMetadata.h" 7 | #include "vm/MetadataLock.h" 8 | #include "vm/Class.h" 9 | 10 | #include "MethodBridge.h" 11 | #include "../metadata/MetadataModule.h" 12 | #include "../metadata/MetadataUtil.h" 13 | #include "../transform/Transform.h" 14 | 15 | 16 | 17 | 18 | namespace hybridclr 19 | { 20 | namespace interpreter 21 | { 22 | 23 | 24 | } 25 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/Interpreter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "InterpreterDefs.h" 4 | 5 | namespace hybridclr 6 | { 7 | 8 | namespace interpreter 9 | { 10 | 11 | class Interpreter 12 | { 13 | public: 14 | 15 | static void Execute(const MethodInfo* methodInfo, StackObject* args, void* ret); 16 | 17 | }; 18 | 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /hybridclr/interpreter/InterpreterDefs.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../metadata/MetadataUtil.h" 3 | 4 | #include "MemoryUtil.h" 5 | 6 | 7 | namespace hybridclr 8 | { 9 | namespace interpreter 10 | { 11 | 12 | } 13 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/InterpreterDefs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../CommonDef.h" 3 | #include "../metadata/MetadataDef.h" 4 | 5 | namespace hybridclr 6 | { 7 | namespace interpreter 8 | { 9 | 10 | // from obj or arg 11 | enum class LocationDataType : uint8_t 12 | { 13 | I1, 14 | U1, 15 | I2, 16 | U2, 17 | U8, 18 | S_N, // struct size = 3,5,6,7, > 8, size is described by stackObjectSize 19 | }; 20 | 21 | union StackObject 22 | { 23 | uint64_t __u64; 24 | void* ptr; // can't adjust position. will raise native_invoke init args bugs. 25 | bool b; 26 | int8_t i8; 27 | uint8_t u8; 28 | int16_t i16; 29 | uint16_t u16; 30 | int32_t i32; 31 | uint32_t u32; 32 | int64_t i64; 33 | uint64_t u64; 34 | float f4; 35 | double f8; 36 | Il2CppObject* obj; 37 | Il2CppString* str; 38 | Il2CppObject** ptrObj; 39 | }; 40 | 41 | static_assert(sizeof(StackObject) == 8, "requrie 8 bytes"); 42 | 43 | 44 | enum class ExceptionFlowType 45 | { 46 | Exception, 47 | Catch, 48 | Leave, 49 | }; 50 | 51 | struct InterpMethodInfo; 52 | 53 | struct ExceptionFlowInfo 54 | { 55 | ExceptionFlowType exFlowType; 56 | int32_t throwOffset; 57 | Il2CppException* ex; 58 | int32_t nextExClauseIndex; 59 | int32_t leaveTarget; 60 | }; 61 | 62 | struct InterpFrame 63 | { 64 | const MethodInfo* method; 65 | StackObject* stackBasePtr; 66 | int32_t oldStackTop; 67 | void* ret; 68 | byte* ip; 69 | 70 | ExceptionFlowInfo* exFlowBase; 71 | int32_t exFlowCount; 72 | int32_t exFlowCapaticy; 73 | 74 | int32_t oldLocalPoolBottomIdx; 75 | 76 | ExceptionFlowInfo* GetCurExFlow() const 77 | { 78 | return exFlowCount > 0 ? exFlowBase + exFlowCount - 1 : nullptr; 79 | } 80 | 81 | ExceptionFlowInfo* GetPrevExFlow() const 82 | { 83 | return exFlowCount > 1 ? exFlowBase + exFlowCount - 2 : nullptr; 84 | } 85 | }; 86 | 87 | struct InterpExceptionClause 88 | { 89 | metadata::CorILExceptionClauseType flags; 90 | int32_t tryBeginOffset; 91 | int32_t tryEndOffset; 92 | int32_t handlerBeginOffset; 93 | int32_t handlerEndOffset; 94 | int32_t filterBeginOffset; 95 | Il2CppClass* exKlass; 96 | }; 97 | 98 | struct MethodArgDesc 99 | { 100 | bool passbyValWhenInvoke; 101 | LocationDataType type; 102 | uint16_t stackObjectSize; 103 | }; 104 | 105 | struct InterpMethodInfo 106 | { 107 | byte* codes; 108 | MethodArgDesc* args; 109 | uint64_t* resolveDatas; 110 | const InterpExceptionClause* exClauses; 111 | uint32_t argStackObjectSize; 112 | uint32_t retStackObjectSize : 24; 113 | uint32_t initLocals : 8; 114 | uint32_t localStackSize; // args + locals StackObject size 115 | uint32_t maxStackSize; // args + locals + evalstack size 116 | uint32_t argCount : 8; 117 | uint32_t codeLength : 24; 118 | uint32_t localVarBaseOffset; 119 | uint32_t evalStackBaseOffset; 120 | uint32_t exClauseCount; 121 | }; 122 | } 123 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/InterpreterModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "os/ThreadLocalValue.h" 4 | 5 | #include "../CommonDef.h" 6 | #include "MethodBridge.h" 7 | #include "Engine.h" 8 | #include "../metadata/Image.h" 9 | 10 | namespace hybridclr 11 | { 12 | namespace interpreter 13 | { 14 | 15 | class InterpreterModule 16 | { 17 | public: 18 | static void Initialize(); 19 | 20 | static MachineState& GetCurrentThreadMachineState() 21 | { 22 | MachineState* state = nullptr; 23 | s_machineState.GetValue((void**)&state); 24 | if (!state) 25 | { 26 | state = new MachineState(); 27 | s_machineState.SetValue(state); 28 | } 29 | return *state; 30 | } 31 | 32 | static void FreeThreadLocalMachineState() 33 | { 34 | MachineState* state = nullptr; 35 | s_machineState.GetValue((void**)&state); 36 | if (state) 37 | { 38 | delete state; 39 | s_machineState.SetValue(nullptr); 40 | } 41 | } 42 | 43 | static InterpMethodInfo* GetInterpMethodInfo(const MethodInfo* methodInfo); 44 | 45 | static Il2CppMethodPointer GetMethodPointer(const Il2CppMethodDefinition* method); 46 | static Il2CppMethodPointer GetMethodPointer(const MethodInfo* method); 47 | static Il2CppMethodPointer GetAdjustThunkMethodPointer(const Il2CppMethodDefinition* method); 48 | static Il2CppMethodPointer GetAdjustThunkMethodPointer(const MethodInfo* method); 49 | static Managed2NativeCallMethod GetManaged2NativeMethodPointer(const MethodInfo* method, bool forceStatic); 50 | static Managed2NativeCallMethod GetManaged2NativeMethodPointer(const metadata::ResolveStandAloneMethodSig& methodSig); 51 | static Managed2NativeFunctionPointerCallMethod GetManaged2NativeFunctionPointerMethodPointer(const MethodInfo* method, Il2CppCallConvention callConvention); 52 | static Managed2NativeFunctionPointerCallMethod GetManaged2NativeFunctionPointerMethodPointer(const metadata::ResolveStandAloneMethodSig& methodSig); 53 | 54 | static InvokerMethod GetMethodInvoker(const Il2CppMethodDefinition* method); 55 | static InvokerMethod GetMethodInvoker(const MethodInfo* method); 56 | 57 | static bool IsImplementsByInterpreter(const MethodInfo* method); 58 | 59 | static bool HasImplementCallNative2Managed(const MethodInfo* method) 60 | { 61 | IL2CPP_ASSERT(method->methodPointerCallByInterp != NotSupportAdjustorThunk); 62 | return method->methodPointerCallByInterp != (Il2CppMethodPointer)NotSupportNative2Managed; 63 | } 64 | 65 | static bool HasImplementCallVirtualNative2Managed(const MethodInfo* method) 66 | { 67 | IL2CPP_ASSERT(method->virtualMethodPointerCallByInterp != NotSupportNative2Managed); 68 | return method->virtualMethodPointerCallByInterp != (Il2CppMethodPointer)NotSupportAdjustorThunk; 69 | } 70 | 71 | static void Managed2NativeCallByReflectionInvoke(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret); 72 | 73 | static void NotSupportNative2Managed(); 74 | static void NotSupportAdjustorThunk(); 75 | 76 | static Il2CppMethodPointer GetReversePInvokeWrapper(const Il2CppImage* image, const MethodInfo* method, Il2CppCallConvention callConvention); 77 | static const MethodInfo* GetMethodInfoByReversePInvokeWrapperIndex(int32_t index); 78 | static const MethodInfo* GetMethodInfoByReversePInvokeWrapperMethodPointer(Il2CppMethodPointer methodPointer); 79 | static int32_t GetWrapperIndexByReversePInvokeWrapperMethodPointer(Il2CppMethodPointer methodPointer); 80 | 81 | static const char* GetValueTypeSignature(const char* fullName); 82 | 83 | static bool IsMethodInfoPointer(void* pointer); 84 | private: 85 | static il2cpp::os::ThreadLocalValue s_machineState; 86 | }; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /hybridclr/interpreter/InterpreterUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "InterpreterUtil.h" 2 | 3 | #include "vm/Object.h" 4 | 5 | #include "../metadata/MetadataUtil.h" 6 | 7 | namespace hybridclr 8 | { 9 | namespace interpreter 10 | { 11 | TypeDesc GetValueTypeArgDescBySize(uint32_t size) 12 | { 13 | if (size <= 8) 14 | { 15 | return { LocationDataType::U8, 1 }; 16 | } 17 | return { LocationDataType::S_N, (uint32_t)metadata::GetStackSizeByByteSize(size) }; 18 | } 19 | 20 | TypeDesc GetTypeArgDesc(const Il2CppType* type) 21 | { 22 | if (type->byref) 23 | { 24 | return { LocationDataType::U8, 1 }; 25 | } 26 | switch (type->type) 27 | { 28 | case IL2CPP_TYPE_BOOLEAN: 29 | case IL2CPP_TYPE_U1: 30 | return{ LocationDataType::U1, 1 }; 31 | case IL2CPP_TYPE_I1: 32 | return{ LocationDataType::I1, 1 }; 33 | case IL2CPP_TYPE_I2: 34 | return{ LocationDataType::I2, 1 }; 35 | case IL2CPP_TYPE_CHAR: 36 | case IL2CPP_TYPE_U2: 37 | return{ LocationDataType::U2, 1 }; 38 | case IL2CPP_TYPE_I4: 39 | case IL2CPP_TYPE_U4: 40 | case IL2CPP_TYPE_R4: 41 | case IL2CPP_TYPE_I8: 42 | case IL2CPP_TYPE_U8: 43 | case IL2CPP_TYPE_R8: 44 | case IL2CPP_TYPE_I: 45 | case IL2CPP_TYPE_U: 46 | case IL2CPP_TYPE_FNPTR: 47 | case IL2CPP_TYPE_PTR: 48 | case IL2CPP_TYPE_BYREF: 49 | case IL2CPP_TYPE_STRING: 50 | case IL2CPP_TYPE_ARRAY: 51 | case IL2CPP_TYPE_SZARRAY: 52 | case IL2CPP_TYPE_OBJECT: 53 | case IL2CPP_TYPE_CLASS: 54 | return{ LocationDataType::U8, 1 }; 55 | case IL2CPP_TYPE_TYPEDBYREF: 56 | return GetValueTypeArgDescBySize(sizeof(Il2CppTypedRef)); 57 | case IL2CPP_TYPE_VALUETYPE: 58 | { 59 | Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); 60 | IL2CPP_ASSERT(IS_CLASS_VALUE_TYPE(klass)); 61 | if (klass->enumtype) 62 | { 63 | return GetTypeArgDesc(&klass->castClass->byval_arg); 64 | } 65 | return GetValueTypeArgDescBySize(il2cpp::vm::Class::GetValueSize(klass, nullptr)); 66 | } 67 | case IL2CPP_TYPE_GENERICINST: 68 | { 69 | Il2CppGenericClass* genericClass = type->data.generic_class; 70 | if (genericClass->type->type == IL2CPP_TYPE_CLASS) 71 | { 72 | IL2CPP_ASSERT(!IS_CLASS_VALUE_TYPE(il2cpp::vm::Class::FromIl2CppType(type))); 73 | return{ LocationDataType::U8, 1 }; 74 | } 75 | else 76 | { 77 | Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); 78 | IL2CPP_ASSERT(IS_CLASS_VALUE_TYPE(klass)); 79 | if (klass->enumtype) 80 | { 81 | return GetTypeArgDesc(&klass->castClass->byval_arg); 82 | } 83 | return GetValueTypeArgDescBySize(il2cpp::vm::Class::GetValueSize(klass, nullptr)); 84 | } 85 | } 86 | default: 87 | { 88 | RaiseExecutionEngineException("not support arg type"); 89 | return{ LocationDataType::U8, 1 }; 90 | } 91 | } 92 | } 93 | 94 | Il2CppObject* TranslateNativeValueToBoxValue(const Il2CppType* type, void* value) 95 | { 96 | if (type->byref) 97 | { 98 | RaiseExecutionEngineException("TranslateNativeValueToBoxValue can't box ref"); 99 | return nullptr; 100 | } 101 | Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); 102 | return il2cpp::vm::Object::Box(klass, value); 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /hybridclr/interpreter/InterpreterUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if HYBRIDCLR_UNITY_2023_OR_NEW 4 | #include "codegen/il2cpp-codegen.h" 5 | #else 6 | #include "codegen/il2cpp-codegen-il2cpp.h" 7 | #endif 8 | 9 | #include "InterpreterDefs.h" 10 | 11 | namespace hybridclr 12 | { 13 | namespace interpreter 14 | { 15 | 16 | struct TypeDesc 17 | { 18 | LocationDataType type; 19 | uint32_t stackObjectSize; // 20 | }; 21 | 22 | IL2CPP_FORCE_INLINE void RuntimeInitClassCCtor(Il2CppClass* klass) 23 | { 24 | il2cpp::vm::ClassInlines::InitFromCodegen(klass); 25 | if (!IS_CCTOR_FINISH_OR_NO_CCTOR(klass)) 26 | { 27 | il2cpp_codegen_runtime_class_init(klass); 28 | } 29 | } 30 | 31 | IL2CPP_FORCE_INLINE void RuntimeInitClassCCtor(const MethodInfo* method) 32 | { 33 | RuntimeInitClassCCtor(method->klass); 34 | } 35 | 36 | IL2CPP_FORCE_INLINE void RuntimeInitClassCCtorWithoutInitClass(Il2CppClass* klass) 37 | { 38 | if (!IS_CCTOR_FINISH_OR_NO_CCTOR(klass)) 39 | { 40 | il2cpp_codegen_runtime_class_init(klass); 41 | } 42 | } 43 | 44 | IL2CPP_FORCE_INLINE void RuntimeInitClassCCtorWithoutInitClass(const MethodInfo* method) 45 | { 46 | RuntimeInitClassCCtorWithoutInitClass(method->klass); 47 | } 48 | 49 | inline bool IsNeedExpandLocationType(LocationDataType type) 50 | { 51 | return type < LocationDataType::U8; 52 | } 53 | 54 | TypeDesc GetTypeArgDesc(const Il2CppType* type); 55 | 56 | inline LocationDataType GetLocationDataTypeByType(const Il2CppType* type) 57 | { 58 | return GetTypeArgDesc(type).type; 59 | } 60 | 61 | inline void ExpandLocationData2StackDataByType(void* retValue, LocationDataType type) 62 | { 63 | switch (type) 64 | { 65 | case LocationDataType::I1: 66 | *(int32_t*)retValue = *(int8_t*)retValue; 67 | break; 68 | case LocationDataType::U1: 69 | *(int32_t*)retValue = *(uint8_t*)retValue; 70 | break; 71 | case LocationDataType::I2: 72 | *(int32_t*)retValue = *(int16_t*)retValue; 73 | break; 74 | case LocationDataType::U2: 75 | *(int32_t*)retValue = *(uint16_t*)retValue; 76 | break; 77 | default: 78 | break; 79 | } 80 | } 81 | 82 | inline void CopyLocationData2StackDataByType(StackObject* dst, StackObject* src, LocationDataType type) 83 | { 84 | switch (type) 85 | { 86 | case LocationDataType::I1: 87 | *(int32_t*)dst = *(int8_t*)src; 88 | break; 89 | case LocationDataType::U1: 90 | *(int32_t*)dst = *(uint8_t*)src; 91 | break; 92 | case LocationDataType::I2: 93 | *(int32_t*)dst = *(int16_t*)src; 94 | break; 95 | case LocationDataType::U2: 96 | *(int32_t*)dst = *(uint16_t*)src; 97 | break; 98 | default: 99 | *dst = *src; 100 | break; 101 | } 102 | } 103 | 104 | TypeDesc GetValueTypeArgDescBySize(uint32_t size); 105 | 106 | Il2CppObject* TranslateNativeValueToBoxValue(const Il2CppType* type, void* value); 107 | 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /hybridclr/interpreter/MemoryUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "InterpreterDefs.h" 3 | 4 | namespace hybridclr 5 | { 6 | namespace interpreter 7 | { 8 | 9 | inline void Copy1(void* dst, void* src) 10 | { 11 | *(uint8_t*)dst = *(uint8_t*)src; 12 | } 13 | 14 | inline void Copy2(void* dst, void* src) 15 | { 16 | *(uint16_t*)dst = *(uint16_t*)src; 17 | } 18 | 19 | inline void Copy4(void* dst, void* src) 20 | { 21 | *(uint32_t*)dst = *(uint32_t*)src; 22 | } 23 | 24 | inline void Copy8(void* dst, void* src) 25 | { 26 | *(uint64_t*)dst = *(uint64_t*)src; 27 | } 28 | 29 | inline void Copy12(void* dst, void* src) 30 | { 31 | if (dst <= src) 32 | { 33 | *(uint64_t*)dst = *(uint64_t*)src; 34 | *(uint32_t*)((byte*)dst + 8) = *(uint32_t*)((byte*)src + 8); 35 | } 36 | else 37 | { 38 | *(uint32_t*)((byte*)dst + 8) = *(uint32_t*)((byte*)src + 8); 39 | *(uint64_t*)dst = *(uint64_t*)src; 40 | } 41 | } 42 | 43 | inline void Copy16(void* dst, void* src) 44 | { 45 | if (dst <= src) 46 | { 47 | *(uint64_t*)dst = *(uint64_t*)src; 48 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 49 | } 50 | else 51 | { 52 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 53 | *(uint64_t*)dst = *(uint64_t*)src; 54 | } 55 | } 56 | 57 | inline void Copy20(void* dst, void* src) 58 | { 59 | if (dst <= src) 60 | { 61 | *(uint64_t*)dst = *(uint64_t*)src; 62 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 63 | *(uint32_t*)((byte*)dst + 16) = *(uint32_t*)((byte*)src + 16); 64 | } 65 | else 66 | { 67 | *(uint32_t*)((byte*)dst + 16) = *(uint32_t*)((byte*)src + 16); 68 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 69 | *(uint64_t*)dst = *(uint64_t*)src; 70 | } 71 | } 72 | 73 | inline void Copy24(void* dst, void* src) 74 | { 75 | if (dst <= src) 76 | { 77 | *(uint64_t*)dst = *(uint64_t*)src; 78 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 79 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 80 | } 81 | else 82 | { 83 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 84 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 85 | *(uint64_t*)dst = *(uint64_t*)src; 86 | } 87 | } 88 | 89 | inline void Copy28(void* dst, void* src) 90 | { 91 | if (dst <= src) 92 | { 93 | *(uint64_t*)dst = *(uint64_t*)src; 94 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 95 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 96 | *(uint32_t*)((byte*)dst + 24) = *(uint32_t*)((byte*)src + 24); 97 | } 98 | else 99 | { 100 | *(uint32_t*)((byte*)dst + 24) = *(uint32_t*)((byte*)src + 24); 101 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 102 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 103 | *(uint64_t*)dst = *(uint64_t*)src; 104 | } 105 | } 106 | 107 | inline void Copy32(void* dst, void* src) 108 | { 109 | if (dst <= src) 110 | { 111 | *(uint64_t*)dst = *(uint64_t*)src; 112 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 113 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 114 | *(uint64_t*)((byte*)dst + 24) = *(uint64_t*)((byte*)src + 24); 115 | } 116 | else 117 | { 118 | *(uint64_t*)((byte*)dst + 24) = *(uint64_t*)((byte*)src + 24); 119 | *(uint64_t*)((byte*)dst + 16) = *(uint64_t*)((byte*)src + 16); 120 | *(uint64_t*)((byte*)dst + 8) = *(uint64_t*)((byte*)src + 8); 121 | *(uint64_t*)dst = *(uint64_t*)src; 122 | } 123 | } 124 | 125 | inline void CopyStackObject(StackObject* dst, void* vsrc, uint32_t count) 126 | { 127 | StackObject* src = (StackObject*)vsrc; 128 | IL2CPP_ASSERT(dst + count <= src || src + count <= dst); 129 | switch (count) 130 | { 131 | case 8: dst[7] = src[7]; 132 | case 7: dst[6] = src[6]; 133 | case 6: dst[5] = src[5]; 134 | case 5: dst[4] = src[4]; 135 | case 4: dst[3] = src[3]; 136 | case 3: dst[2] = src[2]; 137 | case 2: dst[1] = src[1]; 138 | case 1: *dst = *src; break; 139 | case 0: break; 140 | default: std::memcpy(dst, src, count * sizeof(StackObject)); 141 | } 142 | } 143 | 144 | inline void CopyBySize(void* dst, void* src, uint32_t size) 145 | { 146 | switch (size) 147 | { 148 | case 1: Copy1(dst, src); break; 149 | default: std::memmove(dst, src, size); break; 150 | } 151 | } 152 | 153 | inline void InitDefault1(void* dst) 154 | { 155 | *(uint8_t*)dst = 0; 156 | } 157 | 158 | inline void InitDefault2(void* dst) 159 | { 160 | *(uint16_t*)dst = 0; 161 | } 162 | 163 | inline void InitDefault4(void* dst) 164 | { 165 | *(uint32_t*)dst = 0; 166 | } 167 | 168 | inline void InitDefault8(void* dst) 169 | { 170 | *(uint64_t*)dst = 0; 171 | } 172 | 173 | inline void InitDefault12(void* dst) 174 | { 175 | int32_t* p = (int32_t*)dst; 176 | p[0] = 0; 177 | p[1] = 0; 178 | p[2] = 0; 179 | } 180 | 181 | inline void InitDefault16(void* dst) 182 | { 183 | *(uint64_t*)dst = 0; 184 | *(uint64_t*)((byte*)dst + 8) = 0; 185 | } 186 | 187 | inline void InitDefault20(void* dst) 188 | { 189 | int32_t* p = (int32_t*)dst; 190 | p[0] = 0; 191 | p[1] = 0; 192 | p[2] = 0; 193 | p[3] = 0; 194 | p[4] = 0; 195 | } 196 | 197 | inline void InitDefault24(void* dst) 198 | { 199 | *(uint64_t*)dst = 0; 200 | *(uint64_t*)((byte*)dst + 8) = 0; 201 | *(uint64_t*)((byte*)dst + 16) = 0; 202 | } 203 | 204 | inline void InitDefault28(void* dst) 205 | { 206 | int32_t* p = (int32_t*)dst; 207 | p[0] = 0; 208 | p[1] = 0; 209 | p[2] = 0; 210 | p[3] = 0; 211 | p[4] = 0; 212 | p[5] = 0; 213 | p[6] = 0; 214 | } 215 | 216 | inline void InitDefault32(void* dst) 217 | { 218 | *(uint64_t*)dst = 0; 219 | *(uint64_t*)((byte*)dst + 8) = 0; 220 | *(uint64_t*)((byte*)dst + 16) = 0; 221 | *(uint64_t*)((byte*)dst + 24) = 0; 222 | } 223 | 224 | inline void InitDefaultN(void* dst, size_t size) 225 | { 226 | std::memset(dst, 0, size); 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /hybridclr/interpreter/MethodBridge.cpp: -------------------------------------------------------------------------------- 1 | #include "MethodBridge.h" 2 | 3 | #include "vm/Object.h" 4 | #include "vm/Class.h" 5 | #include "metadata/GenericMetadata.h" 6 | 7 | #include "../metadata/MetadataModule.h" 8 | #include "../metadata/MetadataUtil.h" 9 | 10 | #include "Interpreter.h" 11 | #include "InterpreterModule.h" 12 | #include "MemoryUtil.h" 13 | 14 | namespace hybridclr 15 | { 16 | namespace interpreter 17 | { 18 | 19 | void ConvertInvokeArgs(StackObject* resultArgs, const MethodInfo* method, MethodArgDesc* argDescs, void** args) 20 | { 21 | int32_t dstIdx = 0; 22 | for (uint8_t i = 0; i < method->parameters_count; i++) 23 | { 24 | StackObject* dst = resultArgs + dstIdx; 25 | MethodArgDesc& argDesc = argDescs[i]; 26 | if (argDesc.passbyValWhenInvoke) 27 | { 28 | dst->ptr = args[i]; 29 | ++dstIdx; 30 | } 31 | else 32 | { 33 | #if SUPPORT_MEMORY_NOT_ALIGMENT_ACCESS 34 | CopyStackObject(dst, args[i], argDesc.stackObjectSize); 35 | #else 36 | std::memcpy(dst, args[i], argDesc.stackObjectSize * sizeof(StackObject)); 37 | #endif 38 | dstIdx += argDesc.stackObjectSize; 39 | } 40 | } 41 | } 42 | 43 | static void AppendString(char* sigBuf, size_t bufSize, size_t& pos, const char* str) 44 | { 45 | size_t len = std::strlen(str); 46 | if (pos + len < bufSize) 47 | { 48 | std::strcpy(sigBuf + pos, str); 49 | pos += len; 50 | } 51 | else 52 | { 53 | RaiseExecutionEngineException(""); 54 | } 55 | } 56 | 57 | inline void AppendSignatureObjOrRefOrPointer(char* sigBuf, size_t bufSize, size_t& pos) 58 | { 59 | AppendString(sigBuf, bufSize, pos, "u"); 60 | } 61 | 62 | inline void AppendSignatureInterpreterValueType(char* sigBuf, size_t bufSize, size_t& pos) 63 | { 64 | AppendString(sigBuf, bufSize, pos, "$"); 65 | } 66 | 67 | static void AppendSignature(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos, bool convertTypeName2SigName = true); 68 | 69 | static bool IsSystemOrUnityAssembly(const Il2CppImage* image) 70 | { 71 | const char* assName = image->nameNoExt; 72 | if (std::strcmp(assName, "mscorlib") == 0) 73 | { 74 | return true; 75 | } 76 | if (std::strncmp(assName, "System.", 7) == 0) 77 | { 78 | return true; 79 | } 80 | if (std::strncmp(assName, "UnityEngine.", 12) == 0) 81 | { 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | static void BuildValueTypeFullName(const Il2CppClass* klass, char* sigBuf, size_t bufferSize, size_t& pos) 88 | { 89 | if (klass->declaringType) 90 | { 91 | BuildValueTypeFullName(klass->declaringType, sigBuf, bufferSize, pos); 92 | AppendString(sigBuf, bufferSize, pos, "/"); 93 | AppendString(sigBuf, bufferSize, pos, klass->name); 94 | return; 95 | } 96 | if (!IsSystemOrUnityAssembly(klass->image)) 97 | { 98 | AppendString(sigBuf, bufferSize, pos, klass->image->nameNoExt); 99 | AppendString(sigBuf, bufferSize, pos, ":"); 100 | } 101 | if (klass->namespaze[0]) 102 | { 103 | AppendString(sigBuf, bufferSize, pos, klass->namespaze); 104 | AppendString(sigBuf, bufferSize, pos, "."); 105 | } 106 | AppendString(sigBuf, bufferSize, pos, klass->name); 107 | } 108 | 109 | static void BuildGenericValueTypeFullName(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos) 110 | { 111 | const Il2CppType* underlyingGenericType = type->data.generic_class->type; 112 | const Il2CppClass* underlyingGenericClass = il2cpp::vm::Class::FromIl2CppType(underlyingGenericType); 113 | BuildValueTypeFullName(underlyingGenericClass, sigBuf, bufferSize, pos); 114 | AppendString(sigBuf, bufferSize, pos, "<"); 115 | const Il2CppGenericInst* classInst = type->data.generic_class->context.class_inst; 116 | for (uint32_t i = 0 ; i < classInst->type_argc; ++i) 117 | { 118 | if (i != 0) 119 | { 120 | AppendString(sigBuf, bufferSize, pos, ","); 121 | } 122 | AppendSignature(classInst->type_argv[i], sigBuf, bufferSize, pos, false); 123 | } 124 | AppendString(sigBuf, bufferSize, pos, ">"); 125 | } 126 | 127 | static void AppendSignature(const Il2CppType* type, char* sigBuf, size_t bufferSize, size_t& pos, bool convertTypeName2SigName) 128 | { 129 | if (type->byref) 130 | { 131 | AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); 132 | return; 133 | } 134 | switch (type->type) 135 | { 136 | case IL2CPP_TYPE_VOID: AppendString(sigBuf, bufferSize, pos, "v"); break; 137 | case IL2CPP_TYPE_BOOLEAN: AppendString(sigBuf, bufferSize, pos, "u1"); break; 138 | case IL2CPP_TYPE_I1: AppendString(sigBuf, bufferSize, pos, "i1"); break; 139 | case IL2CPP_TYPE_U1: AppendString(sigBuf, bufferSize, pos, "u1"); break; 140 | case IL2CPP_TYPE_I2: AppendString(sigBuf, bufferSize, pos, "i2"); break; 141 | case IL2CPP_TYPE_U2: 142 | case IL2CPP_TYPE_CHAR: AppendString(sigBuf, bufferSize, pos, "u2"); break; 143 | case IL2CPP_TYPE_I4: AppendString(sigBuf, bufferSize, pos, "i4"); break; 144 | case IL2CPP_TYPE_U4: AppendString(sigBuf, bufferSize, pos, "u4"); break; 145 | case IL2CPP_TYPE_R4: AppendString(sigBuf, bufferSize, pos, "r4"); break; 146 | case IL2CPP_TYPE_R8: AppendString(sigBuf, bufferSize, pos, "r8"); break; 147 | case IL2CPP_TYPE_I8: AppendString(sigBuf, bufferSize, pos, "i8"); break; 148 | case IL2CPP_TYPE_U8: AppendString(sigBuf, bufferSize, pos, "u8"); break; 149 | case IL2CPP_TYPE_I: AppendString(sigBuf, bufferSize, pos, "i"); break; 150 | case IL2CPP_TYPE_U: AppendString(sigBuf, bufferSize, pos, "u"); break; 151 | case IL2CPP_TYPE_TYPEDBYREF: 152 | { 153 | IL2CPP_ASSERT(sizeof(Il2CppTypedRef) == sizeof(void*) * 3); 154 | AppendString(sigBuf, bufferSize, pos, "typedbyref"); 155 | break; 156 | } 157 | case IL2CPP_TYPE_VALUETYPE: 158 | { 159 | const Il2CppTypeDefinition* typeDef = (const Il2CppTypeDefinition*)type->data.typeHandle; 160 | if (hybridclr::metadata::IsEnumType(typeDef)) 161 | { 162 | AppendSignature(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->elementTypeIndex), sigBuf, bufferSize, pos); 163 | break; 164 | } 165 | if (hybridclr::metadata::IsInterpreterType(typeDef)) 166 | { 167 | AppendSignatureInterpreterValueType(sigBuf, bufferSize, pos); 168 | break; 169 | } 170 | char tempFullName[1024]; 171 | size_t fullNamePos = 0; 172 | Il2CppClass* klass = il2cpp::vm::Class::FromIl2CppType(type); 173 | BuildValueTypeFullName(klass, tempFullName, sizeof(tempFullName) - 1, fullNamePos); 174 | tempFullName[fullNamePos] = 0; 175 | AppendString(sigBuf, bufferSize, pos, convertTypeName2SigName ? InterpreterModule::GetValueTypeSignature(tempFullName) : tempFullName); 176 | break; 177 | } 178 | case IL2CPP_TYPE_GENERICINST: 179 | { 180 | const Il2CppType* underlyingGenericType = type->data.generic_class->type; 181 | if (underlyingGenericType->type == IL2CPP_TYPE_CLASS) 182 | { 183 | AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); 184 | break; 185 | } 186 | const Il2CppTypeDefinition* underlyingTypeDef = (const Il2CppTypeDefinition*)underlyingGenericType->data.typeHandle; 187 | if (hybridclr::metadata::IsEnumType(underlyingTypeDef)) 188 | { 189 | AppendSignature(il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(underlyingTypeDef->elementTypeIndex), sigBuf, bufferSize, pos); 190 | break; 191 | } 192 | IL2CPP_ASSERT(underlyingGenericType->type == IL2CPP_TYPE_VALUETYPE); 193 | if (hybridclr::metadata::IsInterpreterType(underlyingTypeDef)) 194 | { 195 | AppendSignatureInterpreterValueType(sigBuf, bufferSize, pos); 196 | break; 197 | } 198 | 199 | char tempFullName[1024]; 200 | size_t fullNamePos = 0; 201 | BuildGenericValueTypeFullName(type, tempFullName, sizeof(tempFullName) - 1, fullNamePos); 202 | tempFullName[fullNamePos] = 0; 203 | AppendString(sigBuf, bufferSize, pos, convertTypeName2SigName ? InterpreterModule::GetValueTypeSignature(tempFullName) : tempFullName); 204 | break; 205 | } 206 | case IL2CPP_TYPE_VAR: 207 | case IL2CPP_TYPE_MVAR: 208 | { 209 | AppendString(sigBuf, bufferSize, pos, "!"); 210 | break; 211 | } 212 | default: AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); break; 213 | } 214 | } 215 | 216 | bool ComputeSignature(const Il2CppType* ret, const il2cpp::utils::dynamic_array& params, bool instanceCall, char* sigBuf, size_t bufferSize) 217 | { 218 | size_t pos = 0; 219 | AppendSignature(ret, sigBuf, bufferSize, pos); 220 | 221 | if (instanceCall) 222 | { 223 | AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); 224 | } 225 | 226 | for (uint32_t i = 0, paramCount = (uint32_t)params.size(); i < paramCount; i++) 227 | { 228 | AppendSignature(params[i], sigBuf, bufferSize, pos); 229 | } 230 | sigBuf[pos] = 0; 231 | return true; 232 | } 233 | 234 | bool ComputeSignature(const Il2CppMethodDefinition* method, bool call, char* sigBuf, size_t bufferSize) 235 | { 236 | size_t pos = 0; 237 | if (method->genericContainerIndex != kGenericContainerIndexInvalid) 238 | { 239 | AppendString(sigBuf, bufferSize, pos, "!"); 240 | return true; 241 | } 242 | 243 | const Il2CppImage* image = hybridclr::metadata::MetadataModule::GetImage(method)->GetIl2CppImage(); 244 | 245 | AppendSignature(hybridclr::metadata::MetadataModule::GetIl2CppTypeFromEncodeIndex(method->returnType), sigBuf, bufferSize, pos); 246 | 247 | if (call && metadata::IsInstanceMethod(method)) 248 | { 249 | AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); 250 | } 251 | 252 | for (uint8_t i = 0; i < method->parameterCount; i++) 253 | { 254 | TypeIndex paramTypeIndex = hybridclr::metadata::MetadataModule::GetParameterDefinitionFromIndex(image, method->parameterStart + i)->typeIndex; 255 | AppendSignature(hybridclr::metadata::MetadataModule::GetIl2CppTypeFromEncodeIndex(paramTypeIndex), sigBuf, bufferSize, pos); 256 | } 257 | sigBuf[pos] = 0; 258 | return true; 259 | } 260 | 261 | inline bool ContainsGenericParameters(const MethodInfo* method) 262 | { 263 | IL2CPP_ASSERT(method->is_inflated); 264 | auto& ctx = method->genericMethod->context; 265 | if (ctx.class_inst && il2cpp::metadata::GenericMetadata::ContainsGenericParameters(ctx.class_inst)) 266 | { 267 | return true; 268 | } 269 | if (ctx.method_inst && il2cpp::metadata::GenericMetadata::ContainsGenericParameters(ctx.method_inst)) 270 | { 271 | return true; 272 | } 273 | return false; 274 | } 275 | 276 | bool ComputeSignature(const MethodInfo* method, bool call, char* sigBuf, size_t bufferSize) 277 | { 278 | size_t pos = 0; 279 | if (method->is_generic || (method->is_inflated && ContainsGenericParameters(method))) 280 | { 281 | AppendString(sigBuf, bufferSize, pos, "!"); 282 | return true; 283 | } 284 | 285 | AppendSignature(method->return_type, sigBuf, bufferSize, pos); 286 | 287 | if (call && metadata::IsInstanceMethod(method)) 288 | { 289 | AppendSignatureObjOrRefOrPointer(sigBuf, bufferSize, pos); 290 | } 291 | 292 | for (uint8_t i = 0; i < method->parameters_count; i++) 293 | { 294 | AppendSignature(GET_METHOD_PARAMETER_TYPE(method->parameters[i]), sigBuf, bufferSize, pos); 295 | } 296 | sigBuf[pos] = 0; 297 | return true; 298 | } 299 | 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /hybridclr/interpreter/MethodBridge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CommonDef.h" 4 | #include "InterpreterDefs.h" 5 | 6 | namespace hybridclr 7 | { 8 | namespace interpreter 9 | { 10 | union StackObject; 11 | 12 | typedef void (*Managed2NativeCallMethod)(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret); 13 | typedef void (*NativeClassCtor0)(Il2CppObject* obj, const MethodInfo* method); 14 | 15 | struct Managed2NativeMethodInfo 16 | { 17 | const char* signature; 18 | Managed2NativeCallMethod method; 19 | }; 20 | 21 | struct Native2ManagedMethodInfo 22 | { 23 | const char* signature; 24 | Il2CppMethodPointer method; 25 | }; 26 | 27 | struct NativeAdjustThunkMethodInfo 28 | { 29 | const char* signature; 30 | Il2CppMethodPointer method; 31 | }; 32 | 33 | struct FullName2Signature 34 | { 35 | const char* fullName; 36 | const char* signature; 37 | }; 38 | 39 | extern const Managed2NativeMethodInfo g_managed2nativeStub[]; 40 | extern const Native2ManagedMethodInfo g_native2managedStub[]; 41 | extern const NativeAdjustThunkMethodInfo g_adjustThunkStub[]; 42 | extern const FullName2Signature g_fullName2SignatureStub[]; 43 | 44 | 45 | struct ReversePInvokeInfo 46 | { 47 | int32_t index; 48 | Il2CppMethodPointer methodPointer; 49 | const MethodInfo* methodInfo; 50 | }; 51 | 52 | struct ReversePInvokeMethodData 53 | { 54 | const char* methodSig; 55 | Il2CppMethodPointer methodPointer; 56 | }; 57 | 58 | extern const ReversePInvokeMethodData g_reversePInvokeMethodStub[]; 59 | 60 | typedef void (*PInvokeMethodPointer)(intptr_t method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret); 61 | 62 | struct PInvokeMethodData 63 | { 64 | const char* methodSig; 65 | PInvokeMethodPointer methodPointer; 66 | }; 67 | extern const PInvokeMethodData g_PInvokeMethodStub[]; 68 | 69 | 70 | typedef void (*Managed2NativeFunctionPointerCallMethod)(Il2CppMethodPointer methodPointer, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret); 71 | struct Managed2NativeFunctionPointerCallData 72 | { 73 | const char* methodSig; 74 | Managed2NativeFunctionPointerCallMethod methodPointer; 75 | }; 76 | extern const Managed2NativeFunctionPointerCallData g_managed2NativeFunctionPointerCallStub[]; 77 | 78 | void ConvertInvokeArgs(StackObject* resultArgs, const MethodInfo* method, MethodArgDesc* argDescs, void** args); 79 | 80 | bool ComputeSignature(const MethodInfo* method, bool call, char* sigBuf, size_t bufferSize); 81 | bool ComputeSignature(const Il2CppMethodDefinition* method, bool call, char* sigBuf, size_t bufferSize); 82 | bool ComputeSignature(const Il2CppType* ret, const il2cpp::utils::dynamic_array& params, bool instanceCall, char* sigBuf, size_t bufferSize); 83 | 84 | template uint64_t N2MAsUint64ValueOrAddress(T& value) 85 | { 86 | return sizeof(T) <= 8 ? *(uint64_t*)&value : (uint64_t)&value; 87 | } 88 | 89 | template T& M2NFromValueOrAddress(void* value) 90 | { 91 | //return sizeof(T) <= 8 ? *(T*)value : **(T**)value; 92 | return *(T*)value; 93 | } 94 | 95 | } 96 | } -------------------------------------------------------------------------------- /hybridclr/metadata/AOTHomologousImage.cpp: -------------------------------------------------------------------------------- 1 | #include "AOTHomologousImage.h" 2 | 3 | #include "vm/MetadataLock.h" 4 | #include "vm/GlobalMetadata.h" 5 | #include "vm/Class.h" 6 | #include "vm/Image.h" 7 | #include "vm/Exception.h" 8 | #include "vm/MetadataCache.h" 9 | #include "metadata/GenericMetadata.h" 10 | 11 | namespace hybridclr 12 | { 13 | namespace metadata 14 | { 15 | std::vector s_images; 16 | 17 | 18 | AOTHomologousImage* AOTHomologousImage::FindImageByAssembly(const Il2CppAssembly* ass) 19 | { 20 | il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock); 21 | return FindImageByAssemblyLocked(ass, lock); 22 | } 23 | 24 | void AOTHomologousImage::RegisterLocked(AOTHomologousImage* image, il2cpp::os::FastAutoLock& lock) 25 | { 26 | IL2CPP_ASSERT(FindImageByAssemblyLocked(image->_targetAssembly, lock) == nullptr); 27 | s_images.push_back(image); 28 | } 29 | 30 | AOTHomologousImage* AOTHomologousImage::FindImageByAssemblyLocked(const Il2CppAssembly* ass, il2cpp::os::FastAutoLock& lock) 31 | { 32 | for (AOTHomologousImage* image : s_images) 33 | { 34 | if (image->_targetAssembly == ass) 35 | { 36 | return image; 37 | } 38 | } 39 | return nullptr; 40 | } 41 | 42 | LoadImageErrorCode AOTHomologousImage::Load(const byte* imageData, size_t length) 43 | { 44 | _rawImage = new RawImage(); 45 | LoadImageErrorCode err = _rawImage->Load(imageData, length); 46 | if (err != LoadImageErrorCode::OK) 47 | { 48 | return err; 49 | } 50 | 51 | TbAssembly data = _rawImage->ReadAssembly(1); 52 | const char* assName = _rawImage->GetStringFromRawIndex(data.name); 53 | const Il2CppAssembly* aotAss = GetLoadedAssembly(assName); 54 | // FIXME. not free memory. 55 | if (!aotAss) 56 | { 57 | return LoadImageErrorCode::AOT_ASSEMBLY_NOT_FIND; 58 | } 59 | if (hybridclr::metadata::IsInterpreterImage(aotAss->image)) 60 | { 61 | return LoadImageErrorCode::HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY; 62 | } 63 | _targetAssembly = aotAss; 64 | 65 | return LoadImageErrorCode::OK; 66 | } 67 | 68 | const Il2CppType* AOTHomologousImage::GetModuleIl2CppType(uint32_t moduleRowIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound) 69 | { 70 | IL2CPP_ASSERT(moduleRowIndex == 1); 71 | const char* typeNameStr = _rawImage->GetStringFromRawIndex(typeName); 72 | const char* typeNamespaceStr = _rawImage->GetStringFromRawIndex(typeNamespace); 73 | 74 | const Il2CppImage* aotImage = il2cpp::vm::Assembly::GetImage(_targetAssembly); 75 | Il2CppClass* klass = il2cpp::vm::Class::FromName(aotImage, typeNamespaceStr, typeNameStr); 76 | if (klass) 77 | { 78 | return &klass->byval_arg; 79 | } 80 | if (!raiseExceptionIfNotFound) 81 | { 82 | return nullptr; 83 | } 84 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetTypeLoadException( 85 | CStringToStringView(typeNamespaceStr), 86 | CStringToStringView(typeNameStr), 87 | CStringToStringView(aotImage->nameNoExt))); 88 | return nullptr; 89 | } 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /hybridclr/metadata/AOTHomologousImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Image.h" 3 | 4 | namespace hybridclr 5 | { 6 | namespace metadata 7 | { 8 | struct AOTFieldData 9 | { 10 | uint32_t typeDefIndex; // rowIndex - 1 11 | const Il2CppFieldDefinition* fieldDef; 12 | }; 13 | 14 | enum class HomologousImageMode 15 | { 16 | CONSISTENT, 17 | SUPERSET, 18 | }; 19 | 20 | class AOTHomologousImage : public Image 21 | { 22 | public: 23 | 24 | static AOTHomologousImage* FindImageByAssembly(const Il2CppAssembly* ass); 25 | static AOTHomologousImage* FindImageByAssemblyLocked(const Il2CppAssembly* ass, il2cpp::os::FastAutoLock& lock); 26 | static void RegisterLocked(AOTHomologousImage* image, il2cpp::os::FastAutoLock& lock); 27 | 28 | AOTHomologousImage() : _targetAssembly(nullptr) { } 29 | 30 | const Il2CppAssembly* GetTargetAssembly() const 31 | { 32 | return _targetAssembly; 33 | } 34 | 35 | void SetTargetAssembly(const Il2CppAssembly* targetAssembly) 36 | { 37 | _targetAssembly = targetAssembly; 38 | } 39 | 40 | LoadImageErrorCode Load(const byte* imageData, size_t length); 41 | 42 | const Il2CppType* GetModuleIl2CppType(uint32_t moduleRowIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound) override; 43 | protected: 44 | const Il2CppAssembly* _targetAssembly; 45 | }; 46 | } 47 | } -------------------------------------------------------------------------------- /hybridclr/metadata/Assembly.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Assembly.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "os/File.h" 9 | #include "utils/MemoryMappedFile.h" 10 | #include "vm/Assembly.h" 11 | #include "vm/Image.h" 12 | #include "vm/Class.h" 13 | #include "vm/String.h" 14 | #include "vm/MetadataLock.h" 15 | #include "vm/MetadataCache.h" 16 | 17 | #include "Image.h" 18 | #include "MetadataModule.h" 19 | #include "MetadataUtil.h" 20 | #include "ConsistentAOTHomologousImage.h" 21 | #include "SuperSetAOTHomologousImage.h" 22 | 23 | namespace hybridclr 24 | { 25 | namespace metadata 26 | { 27 | 28 | std::vector s_placeHolderAssembies; 29 | 30 | #if ENABLE_PLACEHOLDER_DLL == 1 31 | 32 | static const char* CreateAssemblyNameWithoutExt(const char* assemblyName) 33 | { 34 | const char* extStr = std::strstr(assemblyName, ".dll"); 35 | if (extStr) 36 | { 37 | size_t nameLen = extStr - assemblyName; 38 | char* name = (char*)HYBRIDCLR_MALLOC(nameLen + 1); 39 | std::strncpy(name, assemblyName, nameLen); 40 | name[nameLen] = '\0'; 41 | return name; 42 | } 43 | else 44 | { 45 | return CopyString(assemblyName); 46 | } 47 | } 48 | 49 | static Il2CppAssembly* CreatePlaceHolderAssembly(const char* assemblyName) 50 | { 51 | auto ass = new (HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppAssembly))) Il2CppAssembly; 52 | auto image2 = new (HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppImage))) Il2CppImage; 53 | ass->image = image2; 54 | ass->image->name = CopyString(assemblyName); 55 | ass->image->nameNoExt = ass->aname.name = CreateAssemblyNameWithoutExt(assemblyName); 56 | image2->assembly = ass; 57 | s_placeHolderAssembies.push_back(ass); 58 | return ass; 59 | } 60 | 61 | static Il2CppAssembly* FindPlaceHolderAssembly(const char* assemblyNameNoExt) 62 | { 63 | for (Il2CppAssembly* ass : s_placeHolderAssembies) 64 | { 65 | if (std::strcmp(ass->image->nameNoExt, assemblyNameNoExt) == 0) 66 | { 67 | return ass; 68 | } 69 | } 70 | return nullptr; 71 | } 72 | #else 73 | static Il2CppAssembly* FindPlaceHolderAssembly(const char* assemblyNameNoExt) 74 | { 75 | return nullptr; 76 | } 77 | #endif 78 | 79 | void Assembly::InitializePlaceHolderAssemblies() 80 | { 81 | for (const char** ptrPlaceHolderName = g_placeHolderAssemblies; *ptrPlaceHolderName; ++ptrPlaceHolderName) 82 | { 83 | const char* nameWithExtension = ConcatNewString(*ptrPlaceHolderName, ".dll"); 84 | Il2CppAssembly* placeHolderAss = CreatePlaceHolderAssembly(nameWithExtension); 85 | HYBRIDCLR_FREE((void*)nameWithExtension); 86 | il2cpp::vm::MetadataCache::RegisterInterpreterAssembly(placeHolderAss); 87 | } 88 | } 89 | 90 | static void RunModuleInitializer(Il2CppImage* image) 91 | { 92 | Il2CppClass* moduleKlass = il2cpp::vm::Image::ClassFromName(image, "", ""); 93 | if (!moduleKlass) 94 | { 95 | return; 96 | } 97 | il2cpp::vm::Runtime::ClassInit(moduleKlass); 98 | } 99 | 100 | Il2CppAssembly* Assembly::LoadFromBytes(const void* assemblyData, uint64_t length, const void* rawSymbolStoreBytes, uint64_t rawSymbolStoreLength) 101 | { 102 | Il2CppAssembly* ass = Create((const byte*)assemblyData, length, (const byte*)rawSymbolStoreBytes, rawSymbolStoreLength); 103 | RunModuleInitializer(ass->image); 104 | return ass; 105 | } 106 | 107 | Il2CppAssembly* Assembly::Create(const byte* assemblyData, uint64_t length, const byte* rawSymbolStoreBytes, uint64_t rawSymbolStoreLength) 108 | { 109 | il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock); 110 | 111 | if (!assemblyData) 112 | { 113 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetArgumentNullException("rawAssembly is null")); 114 | } 115 | 116 | uint32_t imageId = InterpreterImage::AllocImageIndex((uint32_t)length); 117 | if (imageId == kInvalidImageIndex) 118 | { 119 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException("InterpreterImage::AllocImageIndex failed")); 120 | } 121 | InterpreterImage* image = new InterpreterImage(imageId); 122 | 123 | assemblyData = (const byte*)CopyBytes(assemblyData, length); 124 | LoadImageErrorCode err = image->Load(assemblyData, (size_t)length); 125 | 126 | if (err != LoadImageErrorCode::OK) 127 | { 128 | TEMP_FORMAT(errMsg, "LoadImageErrorCode:%d", (int)err); 129 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetBadImageFormatException(errMsg)); 130 | // when load a bad image, mean a fatal error. we don't clean image on purpose. 131 | } 132 | 133 | if (rawSymbolStoreBytes) 134 | { 135 | rawSymbolStoreBytes = (const byte*)CopyBytes(rawSymbolStoreBytes, rawSymbolStoreLength); 136 | err = image->LoadPDB(rawSymbolStoreBytes, (size_t)rawSymbolStoreLength); 137 | if (err != LoadImageErrorCode::OK) 138 | { 139 | TEMP_FORMAT(errMsg, "LoadPDB Error:%d", (int)err); 140 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetBadImageFormatException(errMsg)); 141 | } 142 | } 143 | 144 | TbAssembly data = image->GetRawImage().ReadAssembly(1); 145 | const char* nameNoExt = image->GetStringFromRawIndex(data.name); 146 | 147 | Il2CppAssembly* ass; 148 | Il2CppImage* image2; 149 | if ((ass = FindPlaceHolderAssembly(nameNoExt)) != nullptr) 150 | { 151 | if (ass->token) 152 | { 153 | RaiseExecutionEngineException("reloading placeholder assembly is not supported!"); 154 | } 155 | image2 = ass->image; 156 | HYBRIDCLR_FREE((void*)ass->image->name); 157 | HYBRIDCLR_FREE((void*)ass->image->nameNoExt); 158 | } 159 | else 160 | { 161 | ass = new (HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppAssembly))) Il2CppAssembly; 162 | image2 = new (HYBRIDCLR_MALLOC_ZERO(sizeof(Il2CppImage))) Il2CppImage; 163 | } 164 | 165 | image->InitBasic(image2); 166 | image->BuildIl2CppAssembly(ass); 167 | ass->image = image2; 168 | 169 | image->BuildIl2CppImage(image2); 170 | image2->name = ConcatNewString(ass->aname.name, ".dll"); 171 | image2->nameNoExt = ass->aname.name; 172 | image2->assembly = ass; 173 | 174 | image->InitRuntimeMetadatas(); 175 | 176 | il2cpp::vm::MetadataCache::RegisterInterpreterAssembly(ass); 177 | return ass; 178 | } 179 | 180 | LoadImageErrorCode Assembly::LoadMetadataForAOTAssembly(const void* dllBytes, uint32_t dllSize, HomologousImageMode mode) 181 | { 182 | il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock); 183 | 184 | AOTHomologousImage* image = nullptr; 185 | switch (mode) 186 | { 187 | case HomologousImageMode::CONSISTENT: image = new ConsistentAOTHomologousImage(); break; 188 | case HomologousImageMode::SUPERSET: image = new SuperSetAOTHomologousImage(); break; 189 | default: return LoadImageErrorCode::INVALID_HOMOLOGOUS_MODE; 190 | } 191 | 192 | LoadImageErrorCode err = image->Load((byte*)CopyBytes(dllBytes, dllSize), dllSize); 193 | if (err != LoadImageErrorCode::OK) 194 | { 195 | delete image; 196 | return err; 197 | } 198 | 199 | RawImageBase* rawImage = &image->GetRawImage(); 200 | TbAssembly data = rawImage->ReadAssembly(1); 201 | const char* assName = rawImage->GetStringFromRawIndex(data.name); 202 | const Il2CppAssembly* aotAss = il2cpp::vm::Assembly::GetLoadedAssembly(assName); 203 | // FIXME. not free memory. 204 | if (!aotAss) 205 | { 206 | delete image; 207 | return LoadImageErrorCode::AOT_ASSEMBLY_NOT_FIND; 208 | } 209 | if (hybridclr::metadata::IsInterpreterImage(aotAss->image)) 210 | { 211 | delete image; 212 | return LoadImageErrorCode::HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY; 213 | } 214 | image->SetTargetAssembly(aotAss); 215 | if (AOTHomologousImage::FindImageByAssemblyLocked(image->GetTargetAssembly(), lock)) 216 | { 217 | return LoadImageErrorCode::HOMOLOGOUS_ASSEMBLY_HAS_BEEN_LOADED; 218 | } 219 | image->InitRuntimeMetadatas(); 220 | AOTHomologousImage::RegisterLocked(image, lock); 221 | return LoadImageErrorCode::OK; 222 | } 223 | 224 | 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /hybridclr/metadata/Assembly.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CommonDef.h" 4 | 5 | #include "InterpreterImage.h" 6 | #include "AOTHomologousImage.h" 7 | 8 | namespace hybridclr 9 | { 10 | namespace metadata 11 | { 12 | 13 | class Assembly 14 | { 15 | public: 16 | static void InitializePlaceHolderAssemblies(); 17 | static Il2CppAssembly* LoadFromBytes(const void* assemblyData, uint64_t length, const void* rawSymbolStoreBytes, uint64_t rawSymbolStoreLength); 18 | static LoadImageErrorCode LoadMetadataForAOTAssembly(const void* dllBytes, uint32_t dllSize, HomologousImageMode mode); 19 | private: 20 | static Il2CppAssembly* Create(const byte* assemblyData, uint64_t length, const byte* rawSymbolStoreBytes, uint64_t rawSymbolStoreLength); 21 | }; 22 | } 23 | } -------------------------------------------------------------------------------- /hybridclr/metadata/BlobReader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CommonDef.h" 4 | #include "MetadataUtil.h" 5 | 6 | namespace hybridclr 7 | { 8 | namespace metadata 9 | { 10 | 11 | class BlobReader 12 | { 13 | public: 14 | BlobReader(const byte* buf, uint32_t length) : _buf(buf), _length(length), _readPos(0) 15 | { 16 | 17 | } 18 | 19 | const byte* GetData() const 20 | { 21 | return _buf; 22 | } 23 | 24 | uint32_t GetLength() const 25 | { 26 | return _length; 27 | } 28 | 29 | uint32_t GetReadPosition() const 30 | { 31 | return _readPos; 32 | } 33 | 34 | const byte* GetDataOfReadPosition() const 35 | { 36 | return _buf + _readPos; 37 | } 38 | 39 | bool IsEmpty() const 40 | { 41 | return _readPos >= _length; 42 | } 43 | 44 | bool NonEmpty() const 45 | { 46 | return _readPos < _length; 47 | } 48 | 49 | int32_t ReadCompressedInt32() 50 | { 51 | uint32_t unsignedValue = ReadCompressedUint32(); 52 | uint32_t value = unsignedValue >> 1; 53 | if (!(unsignedValue & 0x1)) 54 | { 55 | return value; 56 | } 57 | if (value < 0x40) 58 | { 59 | return value - 0x40; 60 | } 61 | if (value < 0x2000) 62 | { 63 | return value - 0x2000; 64 | } 65 | if (value < 0x10000000) 66 | { 67 | return value - 0x10000000; 68 | } 69 | IL2CPP_ASSERT(value < 0x20000000); 70 | return value - 0x20000000; 71 | } 72 | 73 | static uint32_t ReadCompressedUint32(const byte* buf, uint32_t& lengthSize) 74 | { 75 | uint32_t firstByte = buf[0]; 76 | if (firstByte < 128) 77 | { 78 | lengthSize = 1; 79 | return firstByte; 80 | } 81 | else if (firstByte < 192) 82 | { 83 | lengthSize = 2; 84 | return ((firstByte & 0x3f) << 8) | buf[1]; 85 | } 86 | else if (firstByte < 224) 87 | { 88 | lengthSize = 4; 89 | return ((firstByte & 0x1f) << 24) | (((uint32_t)buf[1]) << 16) | ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; 90 | } 91 | else 92 | { 93 | RaiseExecutionEngineException("bad metadata data. ReadEncodeLength fail"); 94 | return 0; 95 | } 96 | } 97 | 98 | uint32_t ReadCompressedUint32() 99 | { 100 | uint32_t lengthSize; 101 | uint32_t value = ReadCompressedUint32(_buf + _readPos, lengthSize); 102 | _readPos += lengthSize; 103 | return value; 104 | } 105 | 106 | uint8_t ReadByte() 107 | { 108 | IL2CPP_ASSERT(_readPos < _length); 109 | return _buf[_readPos++]; 110 | } 111 | 112 | uint16_t Read16() 113 | { 114 | IL2CPP_ASSERT(_readPos + 2 <= _length); 115 | uint16_t value = GetU2LittleEndian(_buf + _readPos); 116 | _readPos += 2; 117 | return value; 118 | } 119 | 120 | uint32_t Read32() 121 | { 122 | IL2CPP_ASSERT(_readPos + 4 <= _length); 123 | uint32_t value = (uint32_t)GetI4LittleEndian(_buf + _readPos); 124 | _readPos += 4; 125 | return value; 126 | } 127 | 128 | bool TryRead32(uint32_t& value) 129 | { 130 | if (_readPos + 4 <= _length) 131 | { 132 | value = Read32(); 133 | return true; 134 | } 135 | return false; 136 | } 137 | 138 | uint64_t Read64() 139 | { 140 | IL2CPP_ASSERT(_readPos + 8 <= _length); 141 | uint64_t value = (uint64_t)GetI8LittleEndian(_buf + _readPos); 142 | _readPos += 8; 143 | return value; 144 | } 145 | 146 | float ReadFloat() 147 | { 148 | uint32_t x = Read32(); 149 | return *(float*)&x; 150 | } 151 | 152 | double ReadDouble() 153 | { 154 | uint64_t x = Read64(); 155 | return *(double*)&x; 156 | } 157 | 158 | //template 159 | //T Read() 160 | //{ 161 | // IL2CPP_ASSERT(_readPos + sizeof(T) <= _length); 162 | // T value = *(T*)(_buf + _readPos); 163 | // _readPos += sizeof(T); 164 | // return value; 165 | //} 166 | 167 | uint8_t PeekByte() 168 | { 169 | IL2CPP_ASSERT(_readPos < _length); 170 | return _buf[_readPos]; 171 | } 172 | 173 | void SkipByte() 174 | { 175 | IL2CPP_ASSERT(_readPos < _length); 176 | ++_readPos; 177 | } 178 | 179 | void SkipBytes(uint32_t len) 180 | { 181 | IL2CPP_ASSERT(_readPos + len <= _length); 182 | const byte* data = _buf + _readPos; 183 | _readPos += len; 184 | } 185 | 186 | const byte* GetAndSkipCurBytes(uint32_t len) 187 | { 188 | IL2CPP_ASSERT(_readPos + len <= _length); 189 | const byte* data = _buf + _readPos; 190 | _readPos += len; 191 | return data; 192 | } 193 | 194 | private: 195 | const byte* const _buf; 196 | const uint32_t _length; 197 | uint32_t _readPos; 198 | }; 199 | 200 | } 201 | } -------------------------------------------------------------------------------- /hybridclr/metadata/ClassFieldLayoutCalculator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "MetadataUtil.h" 6 | 7 | namespace hybridclr 8 | { 9 | namespace metadata 10 | { 11 | 12 | struct FieldLayout 13 | { 14 | const Il2CppType* type; 15 | int32_t offset; 16 | int32_t size; 17 | bool isNormalStatic; 18 | bool isThreadStatic; 19 | }; 20 | 21 | struct ClassLayoutInfo 22 | { 23 | const Il2CppType* type; 24 | std::vector fields; 25 | int32_t instanceSize; 26 | int32_t actualSize; 27 | int32_t nativeSize; 28 | uint32_t staticFieldsSize; 29 | uint32_t threadStaticFieldsSize; 30 | uint8_t alignment; 31 | #if !HYBRIDCLR_UNITY_2022_OR_NEW 32 | uint8_t naturalAlignment; 33 | #endif 34 | bool blittable; 35 | }; 36 | 37 | struct SizeAndAlignment 38 | { 39 | int32_t size; 40 | int32_t nativeSize; 41 | uint8_t alignment; 42 | #if !HYBRIDCLR_UNITY_2022_OR_NEW 43 | uint8_t naturalAlignment; 44 | #endif 45 | }; 46 | 47 | struct FieldLayoutData 48 | { 49 | std::vector FieldOffsets; 50 | int32_t classSize; 51 | int32_t actualClassSize; 52 | int32_t nativeSize; 53 | 54 | uint8_t minimumAlignment; 55 | #if !HYBRIDCLR_UNITY_2022_OR_NEW 56 | uint8_t naturalAlignment; 57 | #endif 58 | }; 59 | 60 | class InterpreterImage; 61 | 62 | typedef Il2CppHashMap Il2CppType2ClassLayoutInfoMap; 63 | 64 | class ClassFieldLayoutCalculator 65 | { 66 | private: 67 | InterpreterImage* _image; 68 | Il2CppType2ClassLayoutInfoMap _classMap; 69 | 70 | public: 71 | ClassFieldLayoutCalculator(InterpreterImage* image) : _image(image) 72 | { 73 | 74 | } 75 | 76 | ~ClassFieldLayoutCalculator() 77 | { 78 | for (auto it : _classMap) 79 | { 80 | ClassLayoutInfo* info = it.second; 81 | info->~ClassLayoutInfo(); 82 | HYBRIDCLR_FREE(info); 83 | } 84 | } 85 | 86 | ClassLayoutInfo* GetClassLayoutInfo(const Il2CppType* type) 87 | { 88 | auto it = _classMap.find(type); 89 | return it != _classMap.end() ? it->second : nullptr; 90 | } 91 | 92 | void CalcClassNotStaticFields(const Il2CppType* type); 93 | void CalcClassStaticFields(const Il2CppType* type); 94 | 95 | void LayoutFields(int32_t actualParentSize, int32_t parentAlignment, uint8_t packing, std::vector& fields, FieldLayoutData& data); 96 | SizeAndAlignment GetTypeSizeAndAlignment(const Il2CppType* type); 97 | bool IsBlittable(const Il2CppType* type); 98 | }; 99 | } 100 | } -------------------------------------------------------------------------------- /hybridclr/metadata/Coff.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../CommonDef.h" 3 | 4 | 5 | namespace hybridclr 6 | { 7 | namespace metadata 8 | { 9 | struct PEHeader 10 | { 11 | uint16_t matchine; 12 | uint16_t sections; 13 | uint32_t timestamp; 14 | uint32_t ptrSymbolTable; 15 | uint32_t numSymbols; 16 | uint16_t optionalHeadersize; 17 | uint16_t characteristics; 18 | }; 19 | 20 | struct PEDirEntry 21 | { 22 | uint32_t rva; 23 | uint32_t size; 24 | }; 25 | 26 | struct CLIHeader 27 | { 28 | uint32_t cb; 29 | uint16_t majorRuntimeVersion; 30 | uint16_t minorRuntimeVersion; 31 | PEDirEntry metaData; 32 | uint32_t flags; 33 | uint32_t entryPointToken; 34 | PEDirEntry resources; 35 | uint64_t strongNameSignature; 36 | uint64_t codeManagerTable; 37 | uint64_t vTableFixups; 38 | uint64_t exportAddressTableJumps; 39 | uint64_t managedNativeHeader; 40 | }; 41 | 42 | 43 | struct PESectionHeader 44 | { 45 | char name[8]; 46 | uint32_t virtualSize; 47 | uint32_t virtualAddress; 48 | uint32_t sizeOfRawData; 49 | uint32_t ptrRawData; 50 | uint32_t ptrRelocations; 51 | uint32_t ptrLineNumbers; 52 | uint16_t numRelocation; 53 | uint16_t numLineNumber; 54 | uint32_t characteristics; 55 | }; 56 | 57 | struct MetadataRootPartial 58 | { 59 | uint32_t signature; 60 | uint16_t majorVersion; 61 | uint16_t minorVersion; 62 | uint32_t reserved; 63 | uint32_t length; 64 | byte versionFirstByte; 65 | }; 66 | 67 | struct StreamHeader 68 | { 69 | uint32_t offset; 70 | uint32_t size; 71 | char name[1]; 72 | }; 73 | 74 | struct TableStreamHeader 75 | { 76 | uint32_t reserved; 77 | uint8_t majorVersion; 78 | uint8_t minorVersion; 79 | uint8_t heapSizes; 80 | uint8_t reserved2; 81 | uint64_t valid; 82 | uint64_t sorted; 83 | uint32_t rows[1]; 84 | // tables; 85 | }; 86 | 87 | struct CliStream 88 | { 89 | const char* name; 90 | const byte* data; 91 | uint32_t size; 92 | }; 93 | 94 | struct UserString 95 | { 96 | const char* data; 97 | uint32_t size; 98 | uint8_t flags; 99 | }; 100 | 101 | struct Blob 102 | { 103 | const byte* data; 104 | uint32_t size; 105 | }; 106 | 107 | struct Table 108 | { 109 | const byte* data; 110 | uint32_t rowMetaDataSize; 111 | uint32_t rowNum; 112 | bool vaild; 113 | bool sorted; 114 | }; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /hybridclr/metadata/ConsistentAOTHomologousImage.cpp: -------------------------------------------------------------------------------- 1 | #include "ConsistentAOTHomologousImage.h" 2 | 3 | #include "vm/MetadataLock.h" 4 | #include "vm/GlobalMetadata.h" 5 | #include "vm/Class.h" 6 | #include "vm/Image.h" 7 | #include "vm/Exception.h" 8 | #include "vm/MetadataCache.h" 9 | #include "metadata/GenericMetadata.h" 10 | 11 | namespace hybridclr 12 | { 13 | namespace metadata 14 | { 15 | 16 | void ConsistentAOTHomologousImage::InitRuntimeMetadatas() 17 | { 18 | InitTypes(); 19 | InitMethods(); 20 | InitFields(); 21 | } 22 | 23 | void ConsistentAOTHomologousImage::InitTypes() 24 | { 25 | const Table& typeDefTb = _rawImage->GetTable(TableType::TYPEDEF); 26 | uint32_t typeCount = typeDefTb.rowNum; 27 | _il2cppTypeForTypeDefs.resize(typeCount); 28 | _typeDefs.resize(typeCount); 29 | 30 | Il2CppImage* image = _targetAssembly->image; 31 | //if (image->typeCount != typeCount) 32 | //{ 33 | // RaiseExecutionEngineException("image metadata not match"); 34 | //} 35 | for (uint32_t index = 0; index < image->typeCount; index++) 36 | { 37 | Il2CppTypeDefinition* typeDef = (Il2CppTypeDefinition*)il2cpp::vm::MetadataCache::GetAssemblyTypeHandle(image, index); 38 | uint32_t rowIndex = DecodeTokenRowIndex(typeDef->token); 39 | IL2CPP_ASSERT(rowIndex > 0); 40 | if (rowIndex > typeCount) 41 | { 42 | continue; 43 | } 44 | TbTypeDef data = _rawImage->ReadTypeDef(rowIndex); 45 | uint32_t typeIndex = rowIndex - 1; 46 | _typeDefs[typeIndex] = typeDef; 47 | const Il2CppType* il2cppType = il2cpp::vm::GlobalMetadata::GetIl2CppTypeFromIndex(typeDef->byvalTypeIndex); 48 | _il2cppTypeForTypeDefs[typeIndex] = il2cppType; 49 | 50 | const char* name1 = _rawImage->GetStringFromRawIndex(data.typeName); 51 | const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->nameIndex); 52 | if (std::strcmp(name1, name2)) 53 | { 54 | RaiseExecutionEngineException("metadata type not match"); 55 | } 56 | const char* namespaze1 = _rawImage->GetStringFromRawIndex(data.typeNamespace); 57 | const char* namespaze2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(typeDef->namespaceIndex); 58 | if (std::strcmp(namespaze1, namespaze2)) 59 | { 60 | RaiseExecutionEngineException("metadata type not match"); 61 | } 62 | } 63 | } 64 | 65 | void ConsistentAOTHomologousImage::InitMethods() 66 | { 67 | const Table& methodTb = _rawImage->GetTable(TableType::METHOD); 68 | _methodDefs.resize(methodTb.rowNum); 69 | 70 | for (Il2CppTypeDefinition* type : _typeDefs) 71 | { 72 | for (uint16_t i = 0; i < type->method_count; i++) 73 | { 74 | const Il2CppMethodDefinition* methodDef = il2cpp::vm::GlobalMetadata::GetMethodDefinitionFromIndex(type->methodStart + i); 75 | uint32_t rowIndex = DecodeTokenRowIndex(methodDef->token); 76 | IL2CPP_ASSERT(rowIndex > 0 && rowIndex <= methodTb.rowNum); 77 | uint32_t methodIndex = rowIndex - 1; 78 | IL2CPP_ASSERT(_methodDefs[methodIndex] == nullptr); 79 | _methodDefs[methodIndex] = methodDef; 80 | 81 | TbMethod methodData = _rawImage->ReadMethod(rowIndex); 82 | const char* name1 = _rawImage->GetStringFromRawIndex(methodData.name); 83 | const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(methodDef->nameIndex); 84 | if (std::strcmp(name1, name2)) 85 | { 86 | RaiseExecutionEngineException("metadata method not match"); 87 | } 88 | } 89 | } 90 | } 91 | 92 | void ConsistentAOTHomologousImage::InitFields() 93 | { 94 | const Table& fieldTb = _rawImage->GetTable(TableType::FIELD); 95 | _fields.resize(fieldTb.rowNum); 96 | 97 | for (size_t i = 0; i < _typeDefs.size(); i++) 98 | { 99 | Il2CppTypeDefinition* type = _typeDefs[i]; 100 | for (uint16_t j = 0; j < type->field_count; j++) 101 | { 102 | const Il2CppFieldDefinition* fieldDef = il2cpp::vm::GlobalMetadata::GetFieldDefinitionFromTypeDefAndFieldIndex(type, j); 103 | uint32_t rowIndex = DecodeTokenRowIndex(fieldDef->token); 104 | IL2CPP_ASSERT(rowIndex > 0); 105 | uint32_t fieldIndex = rowIndex - 1; 106 | IL2CPP_ASSERT(_fields[fieldIndex].fieldDef == nullptr); 107 | if (rowIndex >= fieldTb.rowNum) 108 | { 109 | continue; 110 | } 111 | _fields[fieldIndex] = { (uint32_t)i, fieldDef }; 112 | 113 | TbField fieldData = _rawImage->ReadField(rowIndex); 114 | const char* name1 = _rawImage->GetStringFromRawIndex(fieldData.name); 115 | const char* name2 = il2cpp::vm::GlobalMetadata::GetStringFromIndex(fieldDef->nameIndex); 116 | if (std::strcmp(name1, name2)) 117 | { 118 | RaiseExecutionEngineException("metadata field not match"); 119 | } 120 | } 121 | } 122 | } 123 | 124 | MethodBody* ConsistentAOTHomologousImage::GetMethodBody(uint32_t token) 125 | { 126 | uint32_t rowIndex = DecodeTokenRowIndex(token); 127 | IL2CPP_ASSERT(rowIndex > 0); 128 | TbMethod methodData = _rawImage->ReadMethod(rowIndex); 129 | MethodBody* body = new (HYBRIDCLR_MALLOC_ZERO(sizeof(MethodBody))) MethodBody(); 130 | ReadMethodBody(*_methodDefs[rowIndex - 1], methodData, *body); 131 | return body; 132 | } 133 | 134 | const Il2CppType* ConsistentAOTHomologousImage::GetIl2CppTypeFromRawTypeDefIndex(uint32_t index) 135 | { 136 | IL2CPP_ASSERT((size_t)index < _il2cppTypeForTypeDefs.size()); 137 | return _il2cppTypeForTypeDefs[index]; 138 | } 139 | 140 | Il2CppGenericContainer* ConsistentAOTHomologousImage::GetGenericContainerByRawIndex(uint32_t index) 141 | { 142 | return (Il2CppGenericContainer*)il2cpp::vm::GlobalMetadata::GetGenericContainerFromIndex(index); 143 | } 144 | 145 | Il2CppGenericContainer* ConsistentAOTHomologousImage::GetGenericContainerByTypeDefRawIndex(int32_t typeDefIndex) 146 | { 147 | Il2CppTypeDefinition* type = (Il2CppTypeDefinition*)il2cpp::vm::GlobalMetadata::GetTypeHandleFromIndex(typeDefIndex); 148 | return (Il2CppGenericContainer*)il2cpp::vm::GlobalMetadata::GetGenericContainerFromIndex(type->genericContainerIndex); 149 | } 150 | 151 | const Il2CppMethodDefinition* ConsistentAOTHomologousImage::GetMethodDefinitionFromRawIndex(uint32_t index) 152 | { 153 | IL2CPP_ASSERT((size_t)index < _methodDefs.size()); 154 | return _methodDefs[index]; 155 | } 156 | 157 | void ConsistentAOTHomologousImage::ReadFieldRefInfoFromFieldDefToken(uint32_t rowIndex, FieldRefInfo& ret) 158 | { 159 | IL2CPP_ASSERT(rowIndex > 0); 160 | AOTFieldData& fd = _fields[rowIndex - 1]; 161 | ret.containerType = _il2cppTypeForTypeDefs[fd.typeDefIndex]; 162 | ret.field = fd.fieldDef; 163 | } 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /hybridclr/metadata/ConsistentAOTHomologousImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AOTHomologousImage.h" 4 | 5 | namespace hybridclr 6 | { 7 | namespace metadata 8 | { 9 | 10 | class ConsistentAOTHomologousImage : public AOTHomologousImage 11 | { 12 | public: 13 | ConsistentAOTHomologousImage() : AOTHomologousImage() {} 14 | 15 | void InitRuntimeMetadatas() override; 16 | 17 | void InitTypes(); 18 | void InitMethods(); 19 | void InitFields(); 20 | 21 | MethodBody* GetMethodBody(uint32_t token) override; 22 | const Il2CppType* GetIl2CppTypeFromRawTypeDefIndex(uint32_t index) override; 23 | Il2CppGenericContainer* GetGenericContainerByRawIndex(uint32_t index) override; 24 | Il2CppGenericContainer* GetGenericContainerByTypeDefRawIndex(int32_t typeDefIndex) override; 25 | const Il2CppMethodDefinition* GetMethodDefinitionFromRawIndex(uint32_t index) override; 26 | void ReadFieldRefInfoFromFieldDefToken(uint32_t rowIndex, FieldRefInfo& ret) override; 27 | private: 28 | std::vector _il2cppTypeForTypeDefs; 29 | std::vector _typeDefs; 30 | 31 | std::vector< const Il2CppMethodDefinition*> _methodDefs; 32 | 33 | std::vector _fields; 34 | }; 35 | } 36 | } -------------------------------------------------------------------------------- /hybridclr/metadata/CustomAttributeDataWriter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BlobReader.h" 4 | 5 | #include "../CommonDef.h" 6 | 7 | #include "utils/MemoryRead.h" 8 | 9 | namespace hybridclr 10 | { 11 | namespace metadata 12 | { 13 | class CustomAttributeDataWriter 14 | { 15 | private: 16 | uint8_t* _data; 17 | uint32_t _capacity; 18 | uint32_t _size; 19 | 20 | public: 21 | CustomAttributeDataWriter(uint32_t capacity) : _capacity(Round2Exp(capacity)), _size(0) 22 | { 23 | _data = (uint8_t*)HYBRIDCLR_MALLOC_ZERO(_capacity); 24 | } 25 | 26 | ~CustomAttributeDataWriter() 27 | { 28 | HYBRIDCLR_FREE(_data); 29 | _data = nullptr; 30 | } 31 | 32 | uint32_t Size() const { return _size; } 33 | 34 | bool Empty() const { return _size == 0; } 35 | 36 | const uint8_t* Data() const { return _data; } 37 | 38 | const uint8_t* DataAt(uint32_t offset) { return _data + offset; } 39 | 40 | void Reset() 41 | { 42 | _size = 0; 43 | } 44 | 45 | void WriteAttributeCount(uint32_t count) 46 | { 47 | WriteCompressedUint32(count); 48 | } 49 | 50 | void Skip(int32_t skipBytes) 51 | { 52 | SureRemainSize(skipBytes); 53 | _size += skipBytes; 54 | } 55 | 56 | void WriteMethodIndex(int32_t offset, int32_t methodIndex) 57 | { 58 | *(int32_t*)(_data + offset) = methodIndex; 59 | } 60 | 61 | void WriteByte(uint8_t n) 62 | { 63 | SureRemainSize(1); 64 | _data[_size++] = n; 65 | } 66 | 67 | void WriteCompressedUint32(uint32_t n) 68 | { 69 | SureRemainSize(5); 70 | uint8_t* buf = _data + _size; 71 | if (n < 0x80) 72 | { 73 | buf[0] = (uint8_t)n; 74 | ++_size; 75 | } 76 | else if (n < 0x4000) 77 | { 78 | uint32_t v = n | 0x8000; 79 | buf[0] = uint8_t(v >> 8); 80 | buf[1] = uint8_t(v); 81 | _size += 2; 82 | } 83 | else if (n < 0x20000000) 84 | { 85 | uint32_t v = n | 0xC0000000; 86 | buf[0] = uint8_t(v >> 24); 87 | buf[1] = uint8_t(v >> 16); 88 | buf[2] = uint8_t(v >> 8); 89 | buf[3] = uint8_t(v); 90 | _size += 4; 91 | } 92 | else if (n < UINT32_MAX - 1) 93 | { 94 | buf[0] = 0xF0; 95 | buf[1] = uint8_t(n); 96 | buf[2] = uint8_t(n >> 8); 97 | buf[3] = uint8_t(n >> 16); 98 | buf[4] = uint8_t(n >> 24); 99 | _size += 5; 100 | } 101 | else if (n == UINT32_MAX - 1) 102 | { 103 | buf[0] = 0xFE; 104 | ++_size; 105 | } 106 | else 107 | { 108 | buf[0] = 0xFF; 109 | ++_size; 110 | } 111 | } 112 | 113 | void WriteUint32(uint32_t n) 114 | { 115 | WriteData(n); 116 | } 117 | 118 | void WriteCompressedInt32(int32_t n) 119 | { 120 | uint32_t v = n >= 0 ? (n << 1) : (((-(n + 1)) << 1) | 0x1U); 121 | WriteCompressedUint32(v); 122 | } 123 | 124 | template 125 | void WriteData(T x) 126 | { 127 | int32_t n = sizeof(T); 128 | SureRemainSize(n); 129 | std::memcpy(_data + _size, &x, n); 130 | _size += n; 131 | } 132 | 133 | void WriteBytes(const uint8_t* data, uint32_t len) 134 | { 135 | SureRemainSize(len); 136 | std::memcpy(_data + _size, data, len); 137 | _size += len; 138 | } 139 | 140 | void Write(const CustomAttributeDataWriter& writer) 141 | { 142 | SureRemainSize(writer._size); 143 | std::memcpy(_data + _size, writer._data, writer._size); 144 | _size += writer._size; 145 | } 146 | 147 | void Write(BlobReader& reader, int32_t count) 148 | { 149 | SureRemainSize(count); 150 | std::memcpy(_data + _size, reader.GetDataOfReadPosition(), count); 151 | _size += count; 152 | reader.SkipBytes(count); 153 | } 154 | 155 | void PopByte() 156 | { 157 | IL2CPP_ASSERT(_size > 0); 158 | --_size; 159 | } 160 | 161 | void ReplaceLastByte(byte x) 162 | { 163 | IL2CPP_ASSERT(_size > 0); 164 | _data[_size - 1] = x; 165 | } 166 | 167 | private: 168 | uint32_t Round2Exp(uint32_t n) 169 | { 170 | uint32_t s = 64; 171 | for (uint32_t s = 64; ; s *= 2) 172 | { 173 | if (s >= n) 174 | { 175 | return s; 176 | } 177 | } 178 | return n; 179 | } 180 | 181 | void SureRemainSize(uint32_t remainSize) 182 | { 183 | uint32_t newSize = _size + remainSize; 184 | if (newSize > _capacity) 185 | { 186 | Resize(newSize); 187 | } 188 | } 189 | 190 | void Resize(uint32_t newSize) 191 | { 192 | _capacity = newSize = Round2Exp(newSize); 193 | uint8_t* oldData = _data; 194 | _data = (uint8_t*)HYBRIDCLR_MALLOC(newSize); 195 | std::memcpy(_data, oldData, _size); 196 | HYBRIDCLR_FREE(oldData); 197 | } 198 | }; 199 | } 200 | } -------------------------------------------------------------------------------- /hybridclr/metadata/Image.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "vm/GlobalMetadataFileInternals.h" 8 | #include "vm/Assembly.h" 9 | #include "gc/GarbageCollector.h" 10 | #include "gc/Allocator.h" 11 | #include "gc/AppendOnlyGCHashMap.h" 12 | #include "utils/Il2CppHashMap.h" 13 | 14 | #include "RawImage.h" 15 | #include "VTableSetup.h" 16 | #include "MetadataUtil.h" 17 | #include "PDBImage.h" 18 | 19 | 20 | namespace hybridclr 21 | { 22 | namespace metadata 23 | { 24 | 25 | typedef std::tuple TokenGenericContextType; 26 | 27 | struct TokenGenericContextTypeHash { 28 | size_t operator()(const TokenGenericContextType x) const noexcept { 29 | return std::get<0>(x) * 0x9e3779b9 + (size_t)std::get<1>(x); 30 | } 31 | }; 32 | 33 | struct TokenGenericContextTypeEqual 34 | { 35 | bool operator()(const TokenGenericContextType a, const TokenGenericContextType b) const { 36 | return std::get<0>(a) == std::get<0>(b) && std::get<1>(a) == std::get<1>(b); 37 | } 38 | }; 39 | 40 | typedef Il2CppHashMap, void*, TokenGenericContextTypeHash, TokenGenericContextTypeEqual> Token2RuntimeHandleMap; 41 | 42 | class Image 43 | { 44 | public: 45 | 46 | RawImage& GetRawImage() const 47 | { 48 | return *_rawImage; 49 | } 50 | 51 | PDBImage* GetPDBImage() const 52 | { 53 | return _pdbImage; 54 | } 55 | 56 | LoadImageErrorCode LoadPDB(const void* pdbBytes, size_t pdbLength) 57 | { 58 | _pdbImage = new PDBImage(); 59 | LoadImageErrorCode err = _pdbImage->Load(pdbBytes, pdbLength); 60 | if (err != LoadImageErrorCode::OK) 61 | { 62 | delete _pdbImage; 63 | _pdbImage = nullptr; 64 | return LoadImageErrorCode::PDB_BAD_FILE; 65 | } 66 | return LoadImageErrorCode::OK; 67 | } 68 | 69 | // misc 70 | bool IsValueTypeFromToken(TableType tableType, uint32_t rowIndex); 71 | bool IsThreadStaticCtorToken(TableType tableType, uint32_t rowIndex); 72 | void ReadMemberRefParentFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, ResolveMemberRefParent& ret); 73 | const Il2CppType* ReadTypeFromMemberRefParent(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex); 74 | 75 | const Il2CppType* GetIl2CppType(uint32_t assemblyRefIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound); 76 | // type 77 | const Il2CppType* ReadType(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer); 78 | 79 | const Il2CppType* ReadTypeFromTypeDef(uint32_t rowIndex); 80 | const Il2CppType* ReadTypeFromTypeRef(uint32_t rowIndex); 81 | const Il2CppType* ReadTypeFromTypeSpec(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex); 82 | const Il2CppType* ReadTypeFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex); 83 | 84 | virtual const Il2CppType* ReadTypeFromResolutionScope(uint32_t scope, uint32_t typeNamespace, uint32_t typeName); 85 | 86 | const Il2CppType* ReadArrayType(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer); 87 | const Il2CppGenericClass* ReadGenericClass(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer); 88 | 89 | // signature 90 | void ReadMemberRefSig(const Il2CppGenericContainer* klassGenericContainer, TbMemberRef& data, ResolveMemberRefSig& signature); 91 | void ReadFieldRefSig(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, FieldRefSig& field); 92 | void ReadMethodRefSig(BlobReader& reader, MethodRefSig& method); 93 | const Il2CppGenericInst* ReadMethodSpecInstantiation(uint32_t signatureIdx, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer); 94 | void ReadLocalVarSig(BlobReader& reader, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, il2cpp::utils::dynamic_array& vars); 95 | void ReadStandAloneSig(uint32_t signatureIdx, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, ResolveStandAloneMethodSig& sig); 96 | 97 | // resolve from token 98 | void ReadResolveMemberRefFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, ResolveMemberRef& ret); 99 | void ReadMethodRefInfoFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, MethodRefInfo& ret); 100 | void ReadMethodRefInfoFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, MethodRefInfo& ret); 101 | const MethodInfo* ResolveMethodInfo(const Il2CppType* type, const char* resolveMethodName, const MethodRefSig& resolveSig, const Il2CppGenericInst* genericInstantiation, const Il2CppGenericContext* genericContext); 102 | 103 | const void* ReadRuntimeHandleFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, uint32_t rowIndex); 104 | 105 | void ReadFieldRefInfoFromMemberRef(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, uint32_t rowIndex, FieldRefInfo& ret); 106 | void ReadMethodBody(const Il2CppMethodDefinition& methodDef, const TbMethod& methodData, MethodBody& body); 107 | 108 | Il2CppString* GetIl2CppUserStringFromRawIndex(StringIndex index); 109 | Il2CppClass* GetClassFromToken(Token2RuntimeHandleMap& tokenCache, uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext); 110 | const FieldInfo* GetFieldInfoFromFieldRef(const Il2CppType& type, const Il2CppFieldDefinition* fieldDef); 111 | const void* GetRuntimeHandleFromToken(Token2RuntimeHandleMap& tokenCache, uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext); 112 | const MethodInfo* FindImplMethod(Il2CppClass* klass, const MethodInfo* matchMethod); 113 | const FieldInfo* GetFieldInfoFromToken(Token2RuntimeHandleMap& tokenCache, uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext); 114 | const MethodInfo* ReadMethodInfoFromToken(const Il2CppGenericContainer* klassGenericContainer, 115 | const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, const Il2CppGenericInst* genericInst, TableType tableType, uint32_t rowIndex); 116 | const MethodInfo* GetMethodInfoFromToken(Token2RuntimeHandleMap& tokenCache, uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext); 117 | const MethodInfo* GetMethodInfo(const Il2CppType* containerType, const Il2CppMethodDefinition* methodDef, const Il2CppGenericInst* instantiation, const Il2CppGenericContext* genericContext); 118 | void GetStandAloneMethodSigFromToken(uint32_t token, const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, const Il2CppGenericContext* genericContext, ResolveStandAloneMethodSig& methodSig); 119 | void ReadFieldRefInfoFromToken(const Il2CppGenericContainer* klassGenericContainer, const Il2CppGenericContainer* methodGenericContainer, TableType tableType, uint32_t rowIndex, FieldRefInfo& ret); 120 | 121 | virtual const Il2CppType* GetModuleIl2CppType(uint32_t moduleRowIndex, uint32_t typeNamespace, uint32_t typeName, bool raiseExceptionIfNotFound) = 0; 122 | virtual const Il2CppType* GetIl2CppTypeFromRawTypeDefIndex(uint32_t index) = 0; 123 | virtual Il2CppGenericContainer* GetGenericContainerByRawIndex(uint32_t index) = 0; 124 | virtual Il2CppGenericContainer* GetGenericContainerByTypeDefRawIndex(int32_t typeDefIndex) = 0; 125 | virtual const Il2CppMethodDefinition* GetMethodDefinitionFromRawIndex(uint32_t index) = 0; 126 | 127 | virtual MethodBody* GetMethodBody(uint32_t token) = 0; 128 | virtual void ReadFieldRefInfoFromFieldDefToken(uint32_t rowIndex, FieldRefInfo& ret) = 0; 129 | virtual void InitRuntimeMetadatas() = 0; 130 | protected: 131 | Image() : _rawImage(nullptr), _pdbImage(nullptr) 132 | { 133 | il2cpp::vm::AssemblyVector assemblies; 134 | il2cpp::vm::Assembly::GetAllAssemblies(assemblies); 135 | for (auto ass : assemblies) 136 | { 137 | _nameToAssemblies[ass->image->nameNoExt] = ass; 138 | } 139 | } 140 | 141 | virtual ~Image() 142 | { 143 | if (_rawImage) 144 | { 145 | delete _rawImage; 146 | _rawImage = nullptr; 147 | } 148 | if (_pdbImage) 149 | { 150 | delete _pdbImage; 151 | _pdbImage = nullptr; 152 | } 153 | } 154 | 155 | const Il2CppAssembly* GetLoadedAssembly(const char* assemblyName) 156 | { 157 | auto it = _nameToAssemblies.find(assemblyName); 158 | if (it != _nameToAssemblies.end()) 159 | { 160 | return it->second; 161 | } 162 | // relying assembly is loaded after self 163 | for (const Il2CppAssembly* ass : *il2cpp::vm::Assembly::GetAllAssemblies()) 164 | { 165 | if (!std::strcmp(ass->image->nameNoExt, assemblyName)) 166 | { 167 | _nameToAssemblies[ass->image->nameNoExt] = ass; 168 | return ass; 169 | } 170 | } 171 | return nullptr; 172 | } 173 | 174 | Il2CppClass* FindNetStandardExportedType(const char* namespaceStr, const char* nameStr); 175 | 176 | RawImage* _rawImage; 177 | PDBImage* _pdbImage; 178 | Il2CppHashMap _nameToAssemblies; 179 | il2cpp::gc::AppendOnlyGCHashMap> _il2cppStringCache; 180 | }; 181 | } 182 | } -------------------------------------------------------------------------------- /hybridclr/metadata/MetadataModule.cpp: -------------------------------------------------------------------------------- 1 | #include "MetadataModule.h" 2 | 3 | #include "os/Atomic.h" 4 | #include "os/Mutex.h" 5 | #include "os/File.h" 6 | #include "vm/Exception.h" 7 | #include "vm/String.h" 8 | #include "vm/Assembly.h" 9 | #include "vm/Class.h" 10 | #include "vm/Object.h" 11 | #include "vm/Image.h" 12 | #include "vm/MetadataLock.h" 13 | #include "utils/Logging.h" 14 | #include "utils/MemoryMappedFile.h" 15 | #include "utils/Memory.h" 16 | 17 | #include "../interpreter/InterpreterModule.h" 18 | 19 | #include "Assembly.h" 20 | #include "InterpreterImage.h" 21 | #include "ConsistentAOTHomologousImage.h" 22 | #include "SuperSetAOTHomologousImage.h" 23 | #include "MetadataPool.h" 24 | 25 | using namespace il2cpp; 26 | 27 | namespace hybridclr 28 | { 29 | 30 | namespace metadata 31 | { 32 | 33 | 34 | 35 | void MetadataModule::Initialize() 36 | { 37 | MetadataPool::Initialize(); 38 | InterpreterImage::Initialize(); 39 | Assembly::InitializePlaceHolderAssemblies(); 40 | } 41 | 42 | Image* MetadataModule::GetUnderlyingInterpreterImage(const MethodInfo* methodInfo) 43 | { 44 | return metadata::IsInterpreterMethod(methodInfo) ? hybridclr::metadata::MetadataModule::GetImage(methodInfo->klass) 45 | : (metadata::Image*)hybridclr::metadata::AOTHomologousImage::FindImageByAssembly( 46 | methodInfo->klass->rank ? il2cpp_defaults.corlib->assembly : methodInfo->klass->image->assembly); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /hybridclr/metadata/MetadataModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "InterpreterImage.h" 4 | #include "AOTHomologousImage.h" 5 | #include "Assembly.h" 6 | 7 | namespace hybridclr 8 | { 9 | 10 | namespace metadata 11 | { 12 | class MetadataModule 13 | { 14 | public: 15 | 16 | static void Initialize(); 17 | 18 | static InterpreterImage* GetImage(uint32_t imageIndex) 19 | { 20 | return InterpreterImage::GetImage(imageIndex); 21 | } 22 | 23 | static InterpreterImage* GetImage(const Il2CppImage* image) 24 | { 25 | return GetImage(DecodeImageIndex(image->token)); 26 | } 27 | 28 | static InterpreterImage* GetImage(const Il2CppClass* klass) 29 | { 30 | return GetImage(klass->image); 31 | } 32 | 33 | static InterpreterImage* GetImage(const Il2CppTypeDefinition* typeDef) 34 | { 35 | return GetImage(DecodeImageIndex(typeDef->byvalTypeIndex)); 36 | } 37 | 38 | static InterpreterImage* GetImage(const Il2CppMethodDefinition* method) 39 | { 40 | return GetImage(DecodeImageIndex(method->nameIndex)); 41 | } 42 | 43 | static InterpreterImage* GetImage(const MethodInfo* method) 44 | { 45 | return GetImage(method->klass->image); 46 | } 47 | 48 | static InterpreterImage* GetImageByEncodedIndex(uint32_t encodedIndex) 49 | { 50 | return GetImage(DecodeImageIndex(encodedIndex)); 51 | } 52 | 53 | static Image* GetUnderlyingInterpreterImage(const MethodInfo* method); 54 | 55 | 56 | static const char* GetStringFromEncodeIndex(StringIndex index) 57 | { 58 | uint32_t imageIndex = DecodeImageIndex(index); 59 | return GetImage(imageIndex)->GetStringFromRawIndex(DecodeMetadataIndex(index)); 60 | } 61 | 62 | static uint32_t GetTypeEncodeIndex(const Il2CppTypeDefinition* typeDef) 63 | { 64 | InterpreterImage* image = GetImage(typeDef); 65 | return hybridclr::metadata::EncodeImageAndMetadataIndex(image->GetIndex(), image->GetTypeRawIndex(typeDef)); 66 | } 67 | 68 | static Il2CppMetadataTypeHandle GetAssemblyTypeHandleFromRawIndex(const Il2CppImage* image, AssemblyTypeIndex index) 69 | { 70 | return GetImage(image)->GetAssemblyTypeHandleFromRawIndex(index); 71 | } 72 | 73 | static Il2CppMetadataTypeHandle GetAssemblyTypeHandleFromEncodeIndex(AssemblyTypeIndex index) 74 | { 75 | uint32_t imageIndex = DecodeImageIndex(index); 76 | return GetImage(imageIndex)->GetAssemblyTypeHandleFromRawIndex(DecodeMetadataIndex(index)); 77 | } 78 | 79 | static Il2CppMetadataTypeHandle GetAssemblyExportedTypeHandleFromEncodeIndex(AssemblyTypeIndex index) 80 | { 81 | uint32_t imageIndex = DecodeImageIndex(index); 82 | return GetImage(imageIndex)->GetAssemblyExportedTypeHandleFromRawIndex(DecodeMetadataIndex(index)); 83 | } 84 | 85 | static const Il2CppTypeDefinitionSizes* GetTypeDefinitionSizesFromEncodeIndex(TypeDefinitionIndex index) 86 | { 87 | uint32_t imageIndex = DecodeImageIndex(index); 88 | return GetImage(imageIndex)->GetTypeDefinitionSizesFromRawIndex(DecodeMetadataIndex(index)); 89 | } 90 | 91 | static const Il2CppType* GetIl2CppTypeFromEncodeIndex(uint32_t index) 92 | { 93 | uint32_t imageIndex = DecodeImageIndex(index); 94 | IL2CPP_ASSERT(imageIndex > 0); 95 | 96 | uint32_t rawIndex = DecodeMetadataIndex(index); 97 | return GetImage(imageIndex)->GetIl2CppTypeFromRawIndex(rawIndex); 98 | } 99 | 100 | static Il2CppClass* GetTypeInfoFromTypeDefinitionEncodeIndex(TypeDefinitionIndex index) 101 | { 102 | uint32_t imageIndex = DecodeImageIndex(index); 103 | IL2CPP_ASSERT(imageIndex > 0); 104 | 105 | uint32_t rawIndex = DecodeMetadataIndex(index); 106 | return GetImage(imageIndex)->GetTypeInfoFromTypeDefinitionRawIndex(rawIndex); 107 | } 108 | 109 | static const Il2CppFieldDefinition* GetFieldDefinitionFromEncodeIndex(uint32_t index) 110 | { 111 | uint32_t imageIndex = DecodeImageIndex(index); 112 | return GetImage(imageIndex)->GetFieldDefinitionFromRawIndex(DecodeMetadataIndex(index)); 113 | } 114 | 115 | static const Il2CppMethodDefinition* GetMethodDefinitionFromIndex(MethodIndex index) 116 | { 117 | uint32_t imageIndex = DecodeImageIndex(index); 118 | return GetImage(imageIndex)->GetMethodDefinitionFromRawIndex(DecodeMetadataIndex(index)); 119 | } 120 | 121 | static uint32_t GetFieldOffset(const Il2CppClass* klass, int32_t fieldIndexInType, FieldInfo* field) 122 | { 123 | return GetImage(klass)->GetFieldOffset(klass, fieldIndexInType); 124 | } 125 | 126 | static const MethodInfo* GetMethodInfoFromMethodDefinitionIndex(uint32_t index) 127 | { 128 | uint32_t imageIndex = DecodeImageIndex(index); 129 | return GetImage(imageIndex)->GetMethodInfoFromMethodDefinitionRawIndex(DecodeMetadataIndex(index)); 130 | } 131 | 132 | static const MethodInfo* GetMethodInfoFromMethodDefinition(const Il2CppMethodDefinition* methodDef) 133 | { 134 | uint32_t imageIndex = DecodeImageIndex(methodDef->nameIndex); 135 | return GetImage(imageIndex)->GetMethodInfoFromMethodDefinition(methodDef); 136 | } 137 | 138 | static const MethodInfo* GetMethodInfoFromVTableSlot(const Il2CppClass* klass, int32_t vTableSlot) 139 | { 140 | return GetImage(klass)->GetMethodInfoFromVTableSlot(klass, vTableSlot); 141 | } 142 | 143 | static const Il2CppMethodDefinition* GetMethodDefinitionFromVTableSlot(const Il2CppTypeDefinition* typeDefine, int32_t vTableSlot) 144 | { 145 | return GetImage(typeDefine)->GetMethodDefinitionFromVTableSlot(typeDefine, vTableSlot); 146 | } 147 | 148 | static Il2CppMethodPointer GetAdjustorThunk(const Il2CppImage* image, uint32_t token) 149 | { 150 | uint32_t imageIndex = DecodeImageIndex(image->token); 151 | return GetImage(imageIndex)->GetAdjustorThunk(token); 152 | } 153 | 154 | static Il2CppMethodPointer GetMethodPointer(const Il2CppImage* image, uint32_t token) 155 | { 156 | uint32_t imageIndex = DecodeImageIndex(image->token); 157 | return GetImage(imageIndex)->GetMethodPointer(token); 158 | } 159 | 160 | static InvokerMethod GetMethodInvoker(const Il2CppImage* image, uint32_t token) 161 | { 162 | uint32_t imageIndex = DecodeImageIndex(image->token); 163 | return GetImage(imageIndex)->GetMethodInvoker(token); 164 | } 165 | 166 | static const Il2CppParameterDefinition* GetParameterDefinitionFromIndex(const Il2CppImage* image, ParameterIndex index) 167 | { 168 | uint32_t imageIndex = DecodeImageIndex(image->token); 169 | return GetImage(imageIndex)->GetParameterDefinitionFromIndex(index); 170 | } 171 | 172 | static const Il2CppType* GetInterfaceFromIndex(const Il2CppClass* klass, TypeInterfaceIndex index) 173 | { 174 | return GetImage(klass)->GetInterfaceFromIndex(klass, index); 175 | } 176 | 177 | static const Il2CppType* GetInterfaceFromOffset(const Il2CppClass* klass, TypeInterfaceIndex offset) 178 | { 179 | return GetImage(klass)->GetInterfaceFromOffset(klass, offset); 180 | } 181 | 182 | static const Il2CppType* GetInterfaceFromOffset(const Il2CppTypeDefinition* typeDefine, TypeInterfaceIndex offset) 183 | { 184 | return GetImage(typeDefine)->GetInterfaceFromOffset(typeDefine, offset); 185 | } 186 | 187 | static Il2CppInterfaceOffsetInfo GetInterfaceOffsetInfo(const Il2CppTypeDefinition* typeDefine, TypeInterfaceOffsetIndex index) 188 | { 189 | return GetImage(typeDefine)->GetInterfaceOffsetInfo(typeDefine, index); 190 | } 191 | 192 | static Il2CppClass* GetNestedTypeFromOffset(const Il2CppClass* klass, TypeNestedTypeIndex offset) 193 | { 194 | return GetImage(klass)->GetNestedTypeFromOffset(klass, offset); 195 | } 196 | 197 | static Il2CppClass* GetNestedTypeFromOffset(const Il2CppTypeDefinition* typeDefinition, TypeNestedTypeIndex offset) 198 | { 199 | return GetImage(typeDefinition)->GetNestedTypeFromOffset(typeDefinition, offset); 200 | } 201 | 202 | static Il2CppMetadataTypeHandle GetNestedTypes(Il2CppMetadataTypeHandle handle, void** iter) 203 | { 204 | Il2CppTypeDefinition* typeDef = (Il2CppTypeDefinition*)handle; 205 | return (Il2CppMetadataTypeHandle)(GetImage(typeDef)->GetNestedTypes(typeDef, iter)); 206 | } 207 | 208 | static const Il2CppGenericContainer* GetGenericContainerFromEncodeIndex(uint32_t index) 209 | { 210 | return GetImage(DecodeImageIndex(index))->GetGenericContainerByRawIndex(DecodeMetadataIndex(index)); 211 | 212 | } 213 | 214 | static const Il2CppFieldDefaultValue* GetFieldDefaultValueEntry(uint32_t index) 215 | { 216 | return GetImage(DecodeImageIndex(index))->GetFieldDefaultValueEntryByRawIndex(DecodeMetadataIndex(index)); 217 | } 218 | 219 | static const uint8_t* GetFieldOrParameterDefalutValue(uint32_t index) 220 | { 221 | return GetImage(DecodeImageIndex(index))->GetFieldOrParameterDefalutValueByRawIndex(DecodeMetadataIndex(index)); 222 | } 223 | 224 | #if HYBRIDCLR_UNITY_2020 225 | static bool HasAttribute(const Il2CppImage* image, uint32_t token, Il2CppClass* attribute) 226 | { 227 | return GetImage(image)->HasAttributeByToken(token, attribute); 228 | } 229 | 230 | static std::tuple GetCustomAttributeDataRange(const Il2CppImage* image, uint32_t token) 231 | { 232 | return GetImage(image)->GetCustomAttributeDataRange(token); 233 | } 234 | #endif 235 | 236 | static bool IsImplementedByInterpreter(MethodInfo* method) 237 | { 238 | Il2CppClass* klass = method->klass; 239 | Il2CppClass* parent = klass->parent; 240 | if (parent != il2cpp_defaults.multicastdelegate_class && parent != il2cpp_defaults.delegate_class) 241 | { 242 | return AOTHomologousImage::FindImageByAssembly(klass->image->assembly); 243 | } 244 | else 245 | { 246 | return strcmp(method->name, "Invoke") == 0; 247 | } 248 | } 249 | private: 250 | 251 | }; 252 | } 253 | 254 | } -------------------------------------------------------------------------------- /hybridclr/metadata/MetadataPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CommonDef.h" 4 | 5 | #include "metadata/GenericMetadata.h" 6 | #include "vm/MetadataAlloc.h" 7 | 8 | namespace hybridclr 9 | { 10 | namespace metadata 11 | { 12 | 13 | template 14 | T* MetadataMallocT() 15 | { 16 | return (T*)HYBRIDCLR_METADATA_MALLOC(sizeof(T)); 17 | } 18 | 19 | template 20 | T* MetadataCallocT(size_t count) 21 | { 22 | return (T*)HYBRIDCLR_METADATA_CALLOC(count, sizeof(T)); 23 | } 24 | 25 | class MetadataPool 26 | { 27 | public: 28 | static void Initialize(); 29 | static const Il2CppType* GetPooledIl2CppType(const Il2CppType& type); 30 | static Il2CppType* ShallowCloneIl2CppType(const Il2CppType* type); 31 | static const Il2CppArrayType* GetPooledIl2CppArrayType(const Il2CppType* elementType, uint32_t rank); 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /hybridclr/metadata/MethodBodyCache.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "MethodBodyCache.h" 4 | 5 | #include "MetadataModule.h" 6 | #include "AOTHomologousImage.h" 7 | #include "Opcodes.h" 8 | #include "MetadataDef.h" 9 | 10 | #include "utils/HashUtils.h" 11 | #include "../RuntimeConfig.h" 12 | 13 | namespace hybridclr 14 | { 15 | namespace metadata 16 | { 17 | struct ImageTokenPair 18 | { 19 | hybridclr::metadata::Image* image; 20 | uint32_t token; 21 | }; 22 | 23 | struct ImageTokenPairHash 24 | { 25 | size_t operator()(const ImageTokenPair& s) const noexcept 26 | { 27 | return il2cpp::utils::HashUtils::Combine((size_t)s.image, (size_t)s.token); 28 | } 29 | }; 30 | 31 | struct ImageTokenPairEqualTo 32 | { 33 | bool operator()(const ImageTokenPair& p1, const ImageTokenPair& p2) const 34 | { 35 | return p1.image == p2.image && p1.token == p2.token; 36 | } 37 | }; 38 | 39 | enum class InlineMode : uint8_t 40 | { 41 | None, 42 | Inlineable, 43 | NotInlineable, 44 | }; 45 | 46 | struct MethodBodyCacheInfo 47 | { 48 | MethodBody* methodBody; 49 | int32_t accessVersion; 50 | uint16_t accessCount; 51 | InlineMode inlineMode; 52 | }; 53 | 54 | constexpr int32_t kMinShrinkMethodBodyCacheInterval = 256; 55 | static bool s_enableShrinkMethodBodyCache = true; 56 | static int32_t s_methodBodyCacheVersion = 0; 57 | static Il2CppHashMap s_methodBodyCache; 58 | 59 | 60 | static MethodBodyCacheInfo* GetOrInitMethodBodyCache(hybridclr::metadata::Image* image, uint32_t token) 61 | { 62 | ImageTokenPair key = { image, token }; 63 | auto it = s_methodBodyCache.find(key); 64 | if (it != s_methodBodyCache.end()) 65 | { 66 | return it->second; 67 | } 68 | MethodBody* methodBody = image->GetMethodBody(token); 69 | MethodBodyCacheInfo* ci = (MethodBodyCacheInfo*)HYBRIDCLR_MALLOC_ZERO(sizeof(MethodBodyCacheInfo)); 70 | *ci = { methodBody, s_methodBodyCacheVersion, 0, InlineMode::None}; 71 | s_methodBodyCache[key] = ci; 72 | return ci; 73 | } 74 | 75 | MethodBody* MethodBodyCache::GetMethodBody(hybridclr::metadata::Image* image, uint32_t token) 76 | { 77 | MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, token); 78 | ci->accessVersion = s_methodBodyCacheVersion; 79 | ++ci->accessCount; 80 | return ci->methodBody; 81 | } 82 | 83 | static void ShrinkMethodBodyCache(int32_t shrinkMethodBodyCacheInterval) 84 | { 85 | if (s_methodBodyCache.size() <= RuntimeConfig::GetMaxMethodBodyCacheSize()) 86 | { 87 | return; 88 | } 89 | 90 | int32_t expiredVersion = s_methodBodyCacheVersion - shrinkMethodBodyCacheInterval; 91 | for (auto it = s_methodBodyCache.begin(); it != s_methodBodyCache.end(); ) 92 | { 93 | MethodBodyCacheInfo* ci = it->second; 94 | // add extra interval when accessCount exceeded 1 95 | int32_t accessVersion = ci->accessVersion + (ci->accessCount - 1) * shrinkMethodBodyCacheInterval; 96 | if (accessVersion < expiredVersion) 97 | { 98 | if (ci->methodBody) 99 | { 100 | ci->methodBody->~MethodBody(); 101 | HYBRIDCLR_FREE(ci->methodBody); 102 | } 103 | HYBRIDCLR_FREE(ci); 104 | s_methodBodyCache.erase(it++); 105 | } 106 | else 107 | { 108 | ++it; 109 | } 110 | } 111 | } 112 | 113 | void MethodBodyCache::EnableShrinkMethodBodyCache(bool shrink) 114 | { 115 | s_enableShrinkMethodBodyCache = shrink; 116 | if (shrink) 117 | { 118 | ++s_methodBodyCacheVersion; 119 | 120 | int32_t shrinkMethodBodyCacheInterval = std::max(RuntimeConfig::GetMaxMethodBodyCacheSize() / 2, kMinShrinkMethodBodyCacheInterval); 121 | if (s_methodBodyCacheVersion % shrinkMethodBodyCacheInterval == 0) 122 | { 123 | ShrinkMethodBodyCache(shrinkMethodBodyCacheInterval); 124 | } 125 | } 126 | } 127 | 128 | static bool IsILCodeInlineable(const byte* ilcodeStart, uint32_t codeSize) 129 | { 130 | const byte* codeEnd = ilcodeStart + codeSize; 131 | const byte* ip = ilcodeStart; 132 | 133 | while (ip < codeEnd) 134 | { 135 | const OpCodeInfo* oc = DecodeOpCodeInfo(ip, codeEnd); 136 | IL2CPP_ASSERT(oc); 137 | int32_t opCodeSize = GetOpCodeSize(ip, oc); 138 | ip += opCodeSize; 139 | int32_t nextOffset = (int32_t)(ip - ilcodeStart); 140 | IL2CPP_ASSERT(nextOffset >= 0 && nextOffset <= (int32_t)codeSize); 141 | 142 | switch (oc->flow) 143 | { 144 | case FlowType::Branch: 145 | case FlowType::CondBranch: 146 | case FlowType::Throw: 147 | { 148 | return false; 149 | } 150 | default: break; 151 | } 152 | } 153 | IL2CPP_ASSERT(ip == codeEnd); 154 | return true; 155 | } 156 | 157 | static bool ComputeInlinable(metadata::Image* image, uint32_t token) 158 | { 159 | metadata::MethodBody* methodBody = MethodBodyCache::GetMethodBody(image, token); 160 | if (methodBody == nullptr || methodBody->ilcodes == nullptr) 161 | { 162 | return false; 163 | } 164 | 165 | if ((int32_t)methodBody->codeSize > RuntimeConfig::GetMaxInlineableMethodBodySize() || !methodBody->exceptionClauses.empty()) 166 | { 167 | return false; 168 | } 169 | 170 | return IsILCodeInlineable(methodBody->ilcodes, methodBody->codeSize); 171 | } 172 | 173 | bool MethodBodyCache::IsInlineable(const MethodInfo* methodInfo) 174 | { 175 | IL2CPP_ASSERT(methodInfo->isInterpterImpl); 176 | 177 | metadata::Image* image = MetadataModule::GetUnderlyingInterpreterImage(methodInfo); 178 | IL2CPP_ASSERT(image); 179 | MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, methodInfo->token); 180 | ci->accessVersion = s_methodBodyCacheVersion; 181 | ++ci->accessCount; 182 | if (ci->inlineMode != InlineMode::None) 183 | { 184 | return ci->inlineMode == InlineMode::Inlineable; 185 | } 186 | bool inlineable = ComputeInlinable(image, methodInfo->token); 187 | ci->inlineMode = inlineable ? InlineMode::Inlineable : InlineMode::NotInlineable; 188 | return inlineable; 189 | } 190 | 191 | void MethodBodyCache::DisableInline(const MethodInfo* methodInfo) 192 | { 193 | IL2CPP_ASSERT(methodInfo->isInterpterImpl); 194 | metadata::Image* image = MetadataModule::GetUnderlyingInterpreterImage(methodInfo); 195 | IL2CPP_ASSERT(image); 196 | MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, methodInfo->token); 197 | ci->inlineMode = InlineMode::NotInlineable; 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /hybridclr/metadata/MethodBodyCache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Image.h" 4 | 5 | namespace hybridclr 6 | { 7 | namespace metadata 8 | { 9 | class MethodBodyCache 10 | { 11 | public: 12 | static MethodBody* GetMethodBody(hybridclr::metadata::Image* image, uint32_t token); 13 | static void EnableShrinkMethodBodyCache(bool shrink); 14 | 15 | static bool IsInlineable(const MethodInfo* method); 16 | static void DisableInline(const MethodInfo* method); 17 | }; 18 | } 19 | } -------------------------------------------------------------------------------- /hybridclr/metadata/PDBImage.cpp: -------------------------------------------------------------------------------- 1 | #include "PDBImage.h" 2 | 3 | #include 4 | 5 | #include "vm/MetadataLock.h" 6 | 7 | #include "../interpreter/InterpreterDefs.h" 8 | 9 | #include "BlobReader.h" 10 | 11 | namespace hybridclr 12 | { 13 | namespace metadata 14 | { 15 | constexpr uint32_t kHiddenLine = 0xfeefee; 16 | 17 | LoadImageErrorCode PDBImage::LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) 18 | { 19 | entryPointToken = 0; 20 | metadataRva = 0; 21 | metadataSize = _imageLength; 22 | 23 | _sections.push_back({ 0, _imageLength, 0 }); 24 | return LoadImageErrorCode::OK; 25 | } 26 | 27 | uint32_t PDBImage::FindILOffsetByIROffset(const il2cpp::utils::dynamic_array& ilMapper, uint32_t irOffset) 28 | { 29 | auto it = std::upper_bound(ilMapper.begin(), ilMapper.end(), irOffset, [](uint32_t irOffset, const ILMapper& mapper) { return irOffset < mapper.irOffset; }); 30 | if (it != ilMapper.begin()) 31 | { 32 | auto next = it; 33 | if (next != ilMapper.end()) 34 | { 35 | IL2CPP_ASSERT(next->irOffset > irOffset); 36 | } 37 | --it; 38 | IL2CPP_ASSERT(it->irOffset <= irOffset); 39 | return it->ilOffset; 40 | } 41 | return 0; 42 | } 43 | 44 | const PDBImage::SymbolSequencePoint* PDBImage::FindSequencePoint(const il2cpp::utils::dynamic_array& sequencePoints, uint32_t ilOffset) 45 | { 46 | auto it = std::upper_bound(sequencePoints.begin(), sequencePoints.end(), ilOffset, [](uint32_t ilOffset, const SymbolSequencePoint& ssp) { return ilOffset < ssp.ilOffset; }); 47 | if (it != sequencePoints.begin()) 48 | { 49 | auto next = it; 50 | if (next != sequencePoints.end()) 51 | { 52 | IL2CPP_ASSERT(next->ilOffset > ilOffset); 53 | } 54 | --it; 55 | IL2CPP_ASSERT(it->ilOffset <= ilOffset); 56 | return &(*it); 57 | } 58 | return nullptr; 59 | } 60 | 61 | const PDBImage::SymbolDocumentData* PDBImage::GetDocument(uint32_t documentToken) 62 | { 63 | const Table& tableMeta = GetTable(TableType::DOCUMENT); 64 | uint32_t rowIndex = DecodeTokenRowIndex(documentToken); 65 | if (rowIndex == 0 || rowIndex > tableMeta.rowNum) 66 | { 67 | return nullptr; 68 | } 69 | 70 | auto it = _documents.find(documentToken); 71 | if (it != _documents.end()) 72 | { 73 | return it->second; 74 | } 75 | 76 | TbSymbolDocument document = ReadSymbolDocument(rowIndex); 77 | SymbolDocumentData* documentData = new (HYBRIDCLR_MALLOC_ZERO(sizeof(SymbolDocumentData))) SymbolDocumentData(); 78 | BlobReader reader = GetBlobReaderByRawIndex(document.name); 79 | 80 | // FIXME. this is a utf-8 char. 81 | char sep = (char)reader.ReadByte(); 82 | std::string sourceFileNames; 83 | bool first = true; 84 | while (reader.NonEmpty()) 85 | { 86 | if (sep && !first) 87 | { 88 | sourceFileNames.push_back(sep); 89 | } 90 | uint32_t sourceFileNameIndex = reader.ReadCompressedUint32(); 91 | if (sourceFileNameIndex > 0) 92 | { 93 | BlobReader sourceFileNameReader = GetBlobReaderByRawIndex(sourceFileNameIndex); 94 | sourceFileNames.append((const char*)sourceFileNameReader.GetData(), sourceFileNameReader.GetLength()); 95 | } 96 | first = false; 97 | } 98 | documentData->sourceFiles = CopyString(sourceFileNames.c_str()); 99 | 100 | _documents.add(documentToken, documentData); 101 | return documentData; 102 | } 103 | 104 | void PDBImage::SetupStackFrameInfo(const MethodInfo* method, const void* ip, Il2CppStackFrameInfo& stackFrame) 105 | { 106 | il2cpp::os::FastAutoLock lock(&il2cpp::vm::g_MetadataLock); 107 | auto it = _methodInfos.find(method); 108 | if (it == _methodInfos.end()) 109 | { 110 | return; 111 | } 112 | const SymbolMethodInfoData* methodInfoData = it->second; 113 | const SymbolMethodDefData* methodData = methodInfoData->methodData; 114 | const hybridclr::interpreter::InterpMethodInfo* imi = (const hybridclr::interpreter::InterpMethodInfo*)method->interpData; 115 | const byte* actualIp; 116 | if (ip >= imi->codes && ip < imi->codes + imi->codeLength) 117 | { 118 | actualIp = (const byte*)ip; 119 | } 120 | else 121 | { 122 | actualIp = *(byte**)ip; 123 | IL2CPP_ASSERT(actualIp >= imi->codes && actualIp < imi->codes + imi->codeLength); 124 | } 125 | 126 | uint32_t irOffset = (uint32_t)((uintptr_t)actualIp - (uintptr_t)imi->codes); 127 | uint32_t ilOffset = FindILOffsetByIROffset(methodInfoData->ilMapper, irOffset); 128 | // when call sub interpreter method, ip point to next instruction, so we need to adjust ilOffset. 129 | if (ilOffset > 0) 130 | { 131 | --ilOffset; 132 | } 133 | 134 | const SymbolSequencePoint* ssp = FindSequencePoint(methodData->sequencePoints, ilOffset); 135 | if (!ssp) 136 | { 137 | return; 138 | } 139 | 140 | stackFrame.ilOffset = ilOffset; 141 | stackFrame.sourceCodeLineNumber = ssp->line; 142 | 143 | stackFrame.filePath = GetDocumentName(ssp->document); 144 | } 145 | 146 | void PDBImage::SetMethodDebugInfo(const MethodInfo* method, const il2cpp::utils::dynamic_array& ilMapper) 147 | { 148 | IL2CPP_ASSERT(_methodInfos.find(method) == _methodInfos.end()); 149 | SymbolMethodDefData* methodData = GetMethodDataFromCache(method->token); 150 | if (!methodData) 151 | { 152 | return; 153 | } 154 | 155 | SymbolMethodInfoData* methodInfoData = new (HYBRIDCLR_MALLOC_ZERO(sizeof(SymbolMethodInfoData))) SymbolMethodInfoData(); 156 | methodInfoData->methodData = methodData; 157 | methodInfoData->ilMapper = ilMapper; 158 | _methodInfos.add(method, methodInfoData); 159 | } 160 | 161 | 162 | PDBImage::SymbolMethodDefData* PDBImage::GetMethodDataFromCache(uint32_t methodToken) 163 | { 164 | const Table& tableMeta = GetTable(TableType::METHODBODY); 165 | uint32_t rowIndex = hybridclr::metadata::DecodeTokenRowIndex(methodToken); 166 | if (rowIndex == 0 || rowIndex > tableMeta.rowNum) 167 | { 168 | return nullptr; 169 | } 170 | 171 | auto it = _methods.find(methodToken); 172 | if (it != _methods.end()) 173 | { 174 | return it->second; 175 | } 176 | 177 | SymbolMethodDefData* methodData = new (HYBRIDCLR_MALLOC_ZERO(sizeof(SymbolMethodDefData))) SymbolMethodDefData(); 178 | 179 | // see https://github.com/dotnet/runtime/blob/main/docs/design/specs/PortablePdb-Metadata.md 180 | TbSymbolMethodBody smb = ReadSymbolMethodBody(rowIndex); 181 | methodData->document = smb.document; 182 | if (smb.sequencePoints > 0) 183 | { 184 | auto& sequencePoints = methodData->sequencePoints; 185 | BlobReader reader = GetBlobReaderByRawIndex(smb.sequencePoints); 186 | uint32_t localSignature = reader.ReadCompressedUint32(); 187 | uint32_t document = smb.document ? smb.document : reader.ReadCompressedUint32(); 188 | int32_t prevStartLine = -1; 189 | int32_t prevStartColumn = -1; 190 | while (reader.NonEmpty()) 191 | { 192 | uint32_t deltaIlOffset = reader.ReadCompressedUint32(); 193 | // document record 194 | if (deltaIlOffset == 0 && !sequencePoints.empty()) 195 | { 196 | document = reader.ReadCompressedUint32(); 197 | continue; 198 | } 199 | uint32_t deltaLines = reader.ReadCompressedUint32(); 200 | int32_t deltaColumns = deltaLines == 0 ? reader.ReadCompressedUint32() : reader.ReadCompressedInt32(); 201 | 202 | uint32_t ilOffset = sequencePoints.empty() ? deltaIlOffset : sequencePoints.back().ilOffset + deltaIlOffset; 203 | 204 | SymbolSequencePoint ssp = {}; 205 | ssp.document = document; 206 | ssp.ilOffset = ilOffset; 207 | // hidden-sequence-point record 208 | if (deltaLines == 0 && deltaColumns == 0) 209 | { 210 | ssp.line = ssp.endLine = kHiddenLine; 211 | ssp.column = ssp.endColumn = 0; 212 | } 213 | else 214 | { 215 | // sequence-point record 216 | if (prevStartColumn < 0) 217 | { 218 | prevStartLine = reader.ReadCompressedUint32(); 219 | prevStartColumn = reader.ReadCompressedUint32(); 220 | } 221 | else 222 | { 223 | prevStartLine += reader.ReadCompressedInt32(); 224 | prevStartColumn += reader.ReadCompressedInt32(); 225 | } 226 | ssp.line = prevStartLine; 227 | ssp.endLine = prevStartLine + deltaLines; 228 | ssp.column = prevStartColumn; 229 | ssp.endColumn = prevStartColumn + deltaColumns; 230 | } 231 | sequencePoints.push_back(ssp); 232 | } 233 | } 234 | 235 | _methods.add(methodToken, methodData); 236 | return methodData; 237 | } 238 | } 239 | } 240 | 241 | 242 | -------------------------------------------------------------------------------- /hybridclr/metadata/PDBImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RawImageBase.h" 4 | 5 | namespace hybridclr 6 | { 7 | namespace metadata 8 | { 9 | struct ILMapper 10 | { 11 | uint32_t irOffset; 12 | uint32_t ilOffset; 13 | }; 14 | 15 | class PDBImage : public RawImageBase 16 | { 17 | public: 18 | PDBImage() : RawImageBase() 19 | { 20 | } 21 | 22 | LoadImageErrorCode LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) override; 23 | 24 | Il2CppString* GetUserStringBlogByIndex(uint32_t index) const override 25 | { 26 | RaiseExecutionEngineException("PDBImage::GetUserStringBlogByIndex Not implemented"); 27 | return nullptr; 28 | } 29 | 30 | void SetupStackFrameInfo(const MethodInfo* method, const void* ip, Il2CppStackFrameInfo& stackFrame); 31 | void SetMethodDebugInfo(const MethodInfo* method, const il2cpp::utils::dynamic_array& ilMapper); 32 | private: 33 | 34 | struct SymbolDocumentData 35 | { 36 | const char* sourceFiles; 37 | }; 38 | 39 | struct SymbolSequencePoint 40 | { 41 | uint32_t document; 42 | uint32_t ilOffset; 43 | uint32_t line; 44 | uint32_t column; 45 | uint32_t endLine; 46 | uint32_t endColumn; 47 | }; 48 | 49 | struct SymbolMethodDefData 50 | { 51 | uint32_t document; 52 | il2cpp::utils::dynamic_array sequencePoints; 53 | }; 54 | 55 | struct SymbolMethodInfoData 56 | { 57 | SymbolMethodDefData* methodData; 58 | il2cpp::utils::dynamic_array ilMapper; 59 | }; 60 | 61 | SymbolMethodDefData* GetMethodDataFromCache(uint32_t methodToken); 62 | static uint32_t FindILOffsetByIROffset(const il2cpp::utils::dynamic_array& ilMapper, uint32_t irOffset); 63 | static const SymbolSequencePoint* FindSequencePoint(const il2cpp::utils::dynamic_array& sequencePoints, uint32_t ilOffset); 64 | const SymbolDocumentData* GetDocument(uint32_t documentToken); 65 | const char* GetDocumentName(uint32_t documentToken) 66 | { 67 | const SymbolDocumentData* document = GetDocument(documentToken); 68 | return document ? document->sourceFiles : nullptr; 69 | } 70 | 71 | typedef Il2CppHashMap> SymbolMethodDataMap; 72 | SymbolMethodDataMap _methods; 73 | 74 | typedef Il2CppHashMap> SymbolDocumentDataMap; 75 | SymbolDocumentDataMap _documents; 76 | 77 | typedef Il2CppHashMap> SymbolMethodInfoDataMap; 78 | SymbolMethodInfoDataMap _methodInfos; 79 | }; 80 | } 81 | } -------------------------------------------------------------------------------- /hybridclr/metadata/RawImage.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RawImage.h" 3 | 4 | #include 5 | #include 6 | 7 | #include "MetadataUtil.h" 8 | #include "Opcodes.h" 9 | 10 | namespace hybridclr 11 | { 12 | namespace metadata 13 | { 14 | 15 | const int kOptionalHeaderSize32 = 224; 16 | const int kOptionalHeaderSize64 = 240; 17 | const int kCliHeaderOffset32 = 208; 18 | const int kCliHeaderOffset64 = 224; 19 | 20 | LoadImageErrorCode RawImage::LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) 21 | { 22 | const byte* imageData = _imageData; 23 | const byte* ptr_lfanew = imageData + 0x3c; 24 | uint32_t lfanew = *(uint32_t*)ptr_lfanew; 25 | if (lfanew >= _imageLength) 26 | { 27 | return LoadImageErrorCode::BAD_IMAGE; 28 | } 29 | 30 | const byte* ptrSig = imageData + lfanew; 31 | /*if (ptr_sig[0] != 'P' || ptr_sig[1] != 'E' || ptr_sig[2] != 0 || ptr_sig[3] != 0)*/ 32 | if (std::strncmp((const char*)ptrSig, "PE\0\0", 4)) 33 | { 34 | return LoadImageErrorCode::BAD_IMAGE; 35 | } 36 | 37 | PEHeader* peHeader = (PEHeader*)(ptrSig + 4); 38 | 39 | bool isDll = (peHeader->characteristics & 0x2000); 40 | // std::cout << "load " << (_isDll ? "dll" : "exe") << std::endl; 41 | 42 | // optional size may be 224(32bit matchine) or 240 (64bit) 43 | if (peHeader->optionalHeadersize != kOptionalHeaderSize32 && peHeader->optionalHeadersize != kOptionalHeaderSize64) 44 | { 45 | return LoadImageErrorCode::BAD_IMAGE; 46 | } 47 | bool is32BitFormat = peHeader->optionalHeadersize == kOptionalHeaderSize32; 48 | 49 | 50 | PESectionHeader* _peSectionHeaders = (PESectionHeader*)((byte*)peHeader + 20 + peHeader->optionalHeadersize); 51 | 52 | for (uint16_t secIdx = 0; secIdx < peHeader->sections; secIdx++) 53 | { 54 | const PESectionHeader* ph = _peSectionHeaders + secIdx; 55 | if ((byte*)ph >= _ptrRawDataEnd) 56 | { 57 | return LoadImageErrorCode::BAD_IMAGE; 58 | } 59 | _sections.push_back({ ph->virtualAddress, ph->virtualAddress + ph->virtualSize, ph->ptrRawData - ph->virtualAddress }); 60 | } 61 | 62 | 63 | const PEDirEntry* ptrCLIHeaderEntry = (PEDirEntry*)(((byte*)peHeader) 64 | + 20 /* pe header size */ 65 | + (is32BitFormat ? kCliHeaderOffset32 : kCliHeaderOffset64) /* pe optional header -> pe header data directories -> cli header */); 66 | uint32_t cLIHeaderOffset; 67 | if (!TranslateRVAToImageOffset(ptrCLIHeaderEntry->rva, cLIHeaderOffset)) 68 | { 69 | return LoadImageErrorCode::BAD_IMAGE; 70 | } 71 | if (cLIHeaderOffset >= _imageLength) 72 | { 73 | return LoadImageErrorCode::BAD_IMAGE; 74 | } 75 | 76 | const CLIHeader* ptrCLIHeader = (const CLIHeader*)(imageData + cLIHeaderOffset); 77 | entryPointToken = ptrCLIHeader->entryPointToken; 78 | metadataRva = ptrCLIHeader->metaData.rva; 79 | metadataSize = ptrCLIHeader->metaData.size; 80 | 81 | return LoadImageErrorCode::OK; 82 | } 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /hybridclr/metadata/RawImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RawImageBase.h" 4 | 5 | namespace hybridclr 6 | { 7 | namespace metadata 8 | { 9 | 10 | class RawImage : public RawImageBase 11 | { 12 | public: 13 | RawImage(): RawImageBase() 14 | { 15 | 16 | } 17 | 18 | LoadImageErrorCode LoadCLIHeader(uint32_t& entryPointToken, uint32_t& metadataRva, uint32_t& metadataSize) override; 19 | 20 | Il2CppString* GetUserStringBlogByIndex(uint32_t index) const override 21 | { 22 | IL2CPP_ASSERT(index >= 0 && (uint32_t)index < _streamUS.size); 23 | const byte* str = _streamUS.data + index; 24 | uint32_t lengthSize; 25 | uint32_t stringLength = BlobReader::ReadCompressedUint32(str, lengthSize); 26 | return CreateUserString((const char*)(str + lengthSize), stringLength); 27 | } 28 | 29 | 30 | private: 31 | 32 | 33 | }; 34 | } 35 | } -------------------------------------------------------------------------------- /hybridclr/metadata/SuperSetAOTHomologousImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AOTHomologousImage.h" 4 | #include "utils/Il2CppHashMap.h" 5 | #include "utils/HashUtils.h" 6 | 7 | namespace hybridclr 8 | { 9 | namespace metadata 10 | { 11 | 12 | struct SuperSetTypeIntermediateInfo 13 | { 14 | bool inited; 15 | //uint32_t homoRowIndex; 16 | uint32_t homoParentRowIndex; 17 | uint32_t homoMethodStartIndex; // start from 1 18 | uint32_t homoFieldStartIndex; // start from 1 19 | //const char* name; 20 | //const char* namespaze; 21 | //int32_t aotTypeIndex; // il2cpp type index 22 | const Il2CppType* aotIl2CppType; 23 | const Il2CppTypeDefinition* aotTypeDef; 24 | //const Il2CppClass* aotKlass; 25 | }; 26 | 27 | struct SuperSetTypeDefDetail 28 | { 29 | //bool inited; 30 | //uint32_t homoRowIndex; 31 | //uint32_t homoParentRowIndex; 32 | //uint32_t homoMethodStartIndex; // start from 1 33 | //uint32_t homoFieldStartIndex; // start from 1 34 | //const char* name; 35 | //const char* namespaze; 36 | //int32_t aotTypeIndex; // il2cpp type index 37 | const Il2CppType* aotIl2CppType; 38 | //const Il2CppTypeDefinition* aotTypeDef; 39 | //const Il2CppClass* aotKlass; 40 | }; 41 | 42 | struct SuperSetMethodDefDetail 43 | { 44 | //uint32_t homoRowIndex; 45 | //MethodRefSig signature; 46 | //const Il2CppTypeDefinition* declaringTypeDef; 47 | //const Il2CppClass* declaringKlass; 48 | //const char* name; 49 | const Il2CppMethodDefinition* aotMethodDef; 50 | }; 51 | 52 | struct SuperSetFieldDefDetail 53 | { 54 | //uint32_t homoRowIndex; 55 | //const char* name; 56 | //Il2CppType type; 57 | //const Il2CppTypeDefinition* declaringTypeDef; 58 | const Il2CppType* declaringIl2CppType; 59 | const Il2CppFieldDefinition* aotFieldDef; 60 | }; 61 | 62 | class SuperSetAOTHomologousImage : public AOTHomologousImage 63 | { 64 | public: 65 | SuperSetAOTHomologousImage() : AOTHomologousImage() {} 66 | 67 | void InitRuntimeMetadatas() override; 68 | 69 | const Il2CppType* ReadTypeFromResolutionScope(uint32_t scope, uint32_t typeNamespace, uint32_t typeName) override; 70 | MethodBody* GetMethodBody(uint32_t token) override; 71 | const Il2CppType* GetIl2CppTypeFromRawTypeDefIndex(uint32_t index) override; 72 | Il2CppGenericContainer* GetGenericContainerByRawIndex(uint32_t index) override; 73 | Il2CppGenericContainer* GetGenericContainerByTypeDefRawIndex(int32_t typeDefIndex) override; 74 | const Il2CppMethodDefinition* GetMethodDefinitionFromRawIndex(uint32_t index) override; 75 | void ReadFieldRefInfoFromFieldDefToken(uint32_t rowIndex, FieldRefInfo& ret) override; 76 | private: 77 | 78 | void InitTypes0(std::vector& typeIntermediateInfos); 79 | void InitNestedClass(std::vector& typeIntermediateInfos); 80 | void InitType(std::vector& typeIntermediateInfos, SuperSetTypeIntermediateInfo& type); 81 | void InitTypes1(std::vector& typeIntermediateInfos); 82 | void ReadMethodDefSig(BlobReader& reader, MethodRefSig& method); 83 | void InitMethods(std::vector& typeIntermediateInfos); 84 | void InitFields(std::vector& typeIntermediateInfos); 85 | 86 | const Il2CppType* _defaultIl2CppType; 87 | 88 | std::vector _typeDefs; 89 | Il2CppHashMap> _aotTypeIndex2TypeDefs; 90 | 91 | Il2CppHashMap> _token2MethodDefs; 92 | std::vector _methodDefs; 93 | 94 | std::vector _fields; 95 | }; 96 | } 97 | } -------------------------------------------------------------------------------- /hybridclr/metadata/Tables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace hybridclr 5 | { 6 | namespace metadata 7 | { 8 | 9 | enum class TableType 10 | { 11 | MODULE, 12 | TYPEREF, 13 | TYPEDEF, 14 | FIELD_POINTER, 15 | FIELD, 16 | METHOD_POINTER, 17 | METHOD, 18 | PARAM_POINTER, 19 | PARAM, 20 | INTERFACEIMPL, 21 | MEMBERREF, /* 0xa */ 22 | CONSTANT, 23 | CUSTOMATTRIBUTE, 24 | FIELDMARSHAL, 25 | DECLSECURITY, 26 | CLASSLAYOUT, 27 | FIELDLAYOUT, /* 0x10 */ 28 | STANDALONESIG, 29 | EVENTMAP, 30 | EVENT_POINTER, 31 | EVENT, 32 | PROPERTYMAP, 33 | PROPERTY_POINTER, 34 | PROPERTY, 35 | METHODSEMANTICS, 36 | METHODIMPL, 37 | MODULEREF, /* 0x1a */ 38 | TYPESPEC, 39 | IMPLMAP, 40 | FIELDRVA, 41 | UNUSED6, 42 | UNUSED7, 43 | ASSEMBLY, /* 0x20 */ 44 | ASSEMBLYPROCESSOR, 45 | ASSEMBLYOS, 46 | ASSEMBLYREF, 47 | ASSEMBLYREFPROCESSOR, 48 | ASSEMBLYREFOS, 49 | FILE, 50 | EXPORTEDTYPE, 51 | MANIFESTRESOURCE, 52 | NESTEDCLASS, 53 | GENERICPARAM, /* 0x2a */ 54 | METHODSPEC, 55 | GENERICPARAMCONSTRAINT, 56 | UNUSED8, 57 | UNUSED9, 58 | UNUSED10, 59 | /* Portable PDB tables */ 60 | DOCUMENT, /* 0x30 */ 61 | METHODBODY, 62 | LOCALSCOPE, 63 | LOCALVARIABLE, 64 | LOCALCONSTANT, 65 | IMPORTSCOPE, 66 | STATEMACHINEMETHOD, 67 | CUSTOMDEBUGINFORMATION, 68 | }; 69 | 70 | 71 | // 0 72 | struct TbModule 73 | { 74 | uint16_t generation; 75 | uint32_t name; 76 | uint32_t mvid; 77 | uint32_t encid; 78 | uint32_t encBaseId; 79 | }; 80 | 81 | // 1 82 | struct TbTypeRef 83 | { 84 | uint32_t resolutionScope; 85 | uint32_t typeName; 86 | uint32_t typeNamespace; 87 | }; 88 | 89 | // 2 90 | struct TbTypeDef 91 | { 92 | uint32_t flags; 93 | uint32_t typeName; 94 | uint32_t typeNamespace; 95 | uint32_t extends; 96 | uint32_t fieldList; 97 | uint32_t methodList; 98 | }; 99 | 100 | // 3 FIELD_POINTER 101 | 102 | // 4 103 | struct TbField 104 | { 105 | uint32_t flags; 106 | uint32_t name; 107 | uint32_t signature; 108 | }; 109 | 110 | // 5 METHOD_POINTER 111 | 112 | // 6 113 | struct TbMethod 114 | { 115 | uint32_t rva; 116 | uint16_t implFlags; 117 | uint16_t flags; 118 | uint32_t name; 119 | uint32_t signature; 120 | uint32_t paramList; 121 | }; 122 | 123 | // 7 PARAM_POINTER 124 | 125 | // 8 126 | struct TbParam 127 | { 128 | uint16_t flags; 129 | uint16_t sequence; 130 | uint32_t name; 131 | }; 132 | 133 | // 9 134 | struct TbInterfaceImpl 135 | { 136 | uint32_t classIdx; 137 | uint32_t interfaceIdx; 138 | }; 139 | 140 | // 0xa 141 | struct TbMemberRef 142 | { 143 | uint32_t classIdx; 144 | uint32_t name; 145 | uint32_t signature; 146 | }; 147 | 148 | struct TbConstant 149 | { 150 | uint8_t type; // 实际上占2字节 151 | uint32_t parent; 152 | uint32_t value; 153 | }; 154 | 155 | struct TbCustomAttribute 156 | { 157 | uint32_t parent; 158 | uint32_t type; 159 | uint32_t value; 160 | }; 161 | 162 | struct TbFieldMarshal 163 | { 164 | uint32_t parent; 165 | uint32_t nativeType; 166 | }; 167 | 168 | struct TbDeclSecurity 169 | { 170 | uint16_t action; 171 | uint32_t parent; 172 | uint32_t permissionSet; 173 | }; 174 | 175 | struct TbClassLayout 176 | { 177 | uint16_t packingSize; 178 | uint32_t classSize; 179 | uint32_t parent; 180 | }; 181 | 182 | // 0x10 183 | struct TbFieldLayout 184 | { 185 | uint32_t offset; 186 | uint32_t field; 187 | }; 188 | 189 | struct TbStandAloneSig 190 | { 191 | uint32_t signature; // 指向 blob heap的位置 192 | }; 193 | 194 | struct TbEventMap 195 | { 196 | uint32_t parent; 197 | uint32_t eventList; 198 | }; 199 | 200 | // 0x13 EVENT_POINTER 201 | 202 | // 0x14 203 | struct TbEvent 204 | { 205 | uint16_t eventFlags; 206 | uint32_t name; 207 | uint32_t eventType; 208 | }; 209 | 210 | struct TbPropertyMap 211 | { 212 | uint32_t parent; 213 | uint32_t propertyList; 214 | }; 215 | 216 | // PROPERTY_POINTER 217 | 218 | struct TbProperty 219 | { 220 | uint16_t flags; 221 | uint32_t name; 222 | uint32_t type; 223 | }; 224 | 225 | struct TbMethodSemantics 226 | { 227 | uint16_t semantics; 228 | uint32_t method; 229 | uint32_t association; 230 | }; 231 | 232 | struct TbMethodImpl 233 | { 234 | uint32_t classIdx; 235 | uint32_t methodBody; 236 | uint32_t methodDeclaration; 237 | }; 238 | 239 | struct TbModuleRef 240 | { 241 | uint32_t name; 242 | }; 243 | 244 | struct TbTypeSpec 245 | { 246 | uint32_t signature; 247 | }; 248 | 249 | struct TbImplMap 250 | { 251 | uint16_t mappingFlags; 252 | uint32_t memberForwarded; 253 | uint32_t importName; 254 | uint32_t importScope; 255 | }; 256 | 257 | struct TbFieldRVA 258 | { 259 | uint32_t rva; 260 | uint32_t field; 261 | }; 262 | 263 | // UNUSED 6 264 | // UNUSED 7 265 | 266 | struct TbAssembly 267 | { 268 | uint32_t hashAlgId; 269 | uint16_t majorVersion; 270 | uint16_t minorVersion; 271 | uint16_t buildNumber; 272 | uint16_t revisionNumber; 273 | uint32_t flags; 274 | uint32_t publicKey; 275 | uint32_t name; 276 | uint32_t culture; 277 | }; 278 | 279 | struct TbAssemblyProcessor 280 | { 281 | uint32_t processor; 282 | }; 283 | 284 | struct TbAssemblyOS 285 | { 286 | uint32_t osPlatformID; 287 | uint32_t osMajorVersion; 288 | uint32_t osMinorVersion; 289 | }; 290 | 291 | struct TbAssemblyRef 292 | { 293 | uint16_t majorVersion; 294 | uint16_t minorVersion; 295 | uint16_t buildNumber; 296 | uint16_t revisionNumber; 297 | uint32_t flags; 298 | uint32_t publicKeyOrToken; 299 | uint32_t name; 300 | uint32_t culture; 301 | uint32_t hashValue; 302 | }; 303 | 304 | struct TbAssemblyRefProcessor 305 | { 306 | uint32_t processor; 307 | uint32_t assemblyRef; 308 | }; 309 | 310 | struct TbAssemblyRefOS 311 | { 312 | uint32_t osPlatformID; 313 | uint32_t osMajorVersion; 314 | uint32_t osMinorVersion; 315 | uint32_t assemblyRef; 316 | }; 317 | 318 | struct TbFile 319 | { 320 | uint32_t flags; 321 | uint32_t name; 322 | uint32_t hashValue; 323 | }; 324 | 325 | struct TbExportedType 326 | { 327 | uint32_t flags; 328 | uint32_t typeDefId; 329 | uint32_t typeName; 330 | uint32_t typeNamespace; 331 | uint32_t implementation; 332 | }; 333 | 334 | struct TbManifestResource 335 | { 336 | uint32_t offset; 337 | uint32_t flags; 338 | uint32_t name; 339 | uint32_t implementation; 340 | }; 341 | 342 | struct TbNestedClass 343 | { 344 | uint32_t nestedClass; 345 | uint32_t enclosingClass; 346 | }; 347 | 348 | struct TbGenericParam 349 | { 350 | uint16_t number; 351 | uint16_t flags; 352 | uint32_t owner; 353 | uint32_t name; 354 | }; 355 | 356 | struct TbMethodSpec 357 | { 358 | uint32_t method; 359 | uint32_t instantiation; 360 | }; 361 | 362 | struct TbGenericParamConstraint 363 | { 364 | uint32_t owner; 365 | uint32_t constraint; 366 | }; 367 | 368 | // 以下这些都不是tables的类型 369 | // 但mono特殊处理一下,额外也加到这个表中 370 | 371 | struct TbSymbolDocument 372 | { 373 | uint32_t name; 374 | uint32_t hashAlgorithm; 375 | uint32_t hash; 376 | uint32_t language; 377 | }; 378 | 379 | struct TbSymbolMethodBody 380 | { 381 | uint32_t document; 382 | uint32_t sequencePoints; 383 | }; 384 | 385 | struct TbSymbolLocalScope 386 | { 387 | uint32_t method; 388 | uint32_t importScope; 389 | uint32_t variables; 390 | uint32_t constants; 391 | uint32_t startOffset; 392 | uint32_t length; 393 | }; 394 | 395 | struct TbSymbolLocalVariable 396 | { 397 | uint16_t attributes; 398 | uint16_t index; 399 | uint32_t name; 400 | }; 401 | 402 | struct TbSymbolConstant 403 | { 404 | uint32_t name; 405 | uint32_t signature; 406 | }; 407 | 408 | struct TbSymbolImportScope 409 | { 410 | uint32_t parent; 411 | uint32_t imports; 412 | }; 413 | 414 | 415 | struct TbSymbolStateMachineMethod 416 | { 417 | uint32_t moveNextMethod; 418 | uint32_t kickoffMethod; 419 | }; 420 | 421 | struct TbSymbolCustomDebugInformation 422 | { 423 | uint32_t parent; 424 | uint32_t kind; 425 | uint32_t value; 426 | }; 427 | 428 | } 429 | 430 | } -------------------------------------------------------------------------------- /hybridclr/metadata/VTableSetup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "metadata/Il2CppTypeHash.h" 6 | #include "metadata/Il2CppTypeCompare.h" 7 | 8 | #include "../CommonDef.h" 9 | #include "MetadataUtil.h" 10 | 11 | namespace hybridclr 12 | { 13 | namespace metadata 14 | { 15 | struct GenericClassMethod 16 | { 17 | const Il2CppType* type; 18 | const Il2CppMethodDefinition* method; 19 | const char* name; // TODO remove 20 | }; 21 | 22 | struct VirtualMethodImpl 23 | { 24 | const Il2CppMethodDefinition* method; 25 | const Il2CppType* type; 26 | uint16_t slot; 27 | //const char* name; // TODO for debug 28 | }; 29 | 30 | class VTableSetUp; 31 | 32 | struct RawInterfaceOffsetInfo 33 | { 34 | const Il2CppType* type; 35 | VTableSetUp* tree; 36 | uint32_t offset; 37 | }; 38 | 39 | typedef Il2CppHashMap Il2CppType2TypeDeclaringTreeMap; 40 | 41 | class VTableSetUp 42 | { 43 | public: 44 | typedef Il2CppHashMap> Int32ToUin16Map; 45 | typedef Il2CppHashSet> Uin16Set; 46 | 47 | static VTableSetUp* BuildByType(Il2CppType2TypeDeclaringTreeMap& cache, const Il2CppType* type); 48 | static VTableSetUp* InflateVts(Il2CppType2TypeDeclaringTreeMap& cache, VTableSetUp* genericType, const Il2CppType* type); 49 | 50 | VTableSetUp() 51 | { 52 | 53 | } 54 | 55 | const VTableSetUp* GetParent() const { return _parent; } 56 | const Il2CppType* FindImplType(const Il2CppMethodDefinition* methodDef); 57 | const VTableSetUp* FindAncestorTypeTree(const Il2CppType* implType); 58 | const GenericClassMethod* FindImplMethod(const Il2CppType* containerType, const Il2CppMethodDefinition* methodDef, bool throwExceptionIfNotFind = true); 59 | const std::vector& GetInterfaceOffsetInfos() const { return _interfaceOffsetInfos; } 60 | const std::vector& GetVirtualMethodImpls() const { return _methodImpls; } 61 | const Il2CppType* GetType() const { return _type; } 62 | uint32_t GetTypeIndex() const { return _typeDef->byvalTypeIndex; } 63 | bool IsInterType() const { return hybridclr::metadata::IsInterpreterType(_typeDef); } 64 | private: 65 | 66 | void ComputeVtables(Il2CppType2TypeDeclaringTreeMap& cache); 67 | void ComputAotTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache); 68 | void InitInterfaceVTable(uint16_t& curOffset, std::vector& implInterfaceOffsetIdxs); 69 | void ComputeExplicitImpls(const std::vector& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots); 70 | void ApplyTypeExplicitImpls(const Il2CppType* type, const VTableSetUp* tree, const std::vector& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots); 71 | void ComputeOverrideParentVirtualMethod(uint16_t& curOffset, const std::vector& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots); 72 | void ComputeInterfaceOverrideByParentVirtualMethod(const std::vector& implInterfaceOffsetIdxs); 73 | void ComputeInterpTypeVtables(Il2CppType2TypeDeclaringTreeMap& cache); 74 | void ComputeInterfaceVtables(Il2CppType2TypeDeclaringTreeMap& cache); 75 | 76 | bool isExplicitImplInterfaceSlot(uint16_t slot) const { return _explicitImplSlots.find(slot) != _explicitImplSlots.end(); } 77 | uint16_t FindDefaultOverrideExplicitInterfaceSlot(GenericClassMethod& gcm, const Uin16Set& explicitImplSlots, const std::vector& implInterfaceOffsetIdxs); 78 | uint16_t FindExplicitOverrideInterfaceSlot(GenericClassMethod& gcm, const Int32ToUin16Map& explicitImplSlots); 79 | void ApplyOverrideMethod(const GenericClassMethod* beOverrideParentMethod, const Il2CppMethodDefinition* overrideMethodDef, uint16_t checkOverrideMaxIdx); 80 | void ApplyExplicitOverride(const std::vector& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots, const Il2CppType* declaringType, 81 | const Il2CppMethodDefinition* decalringMethod, const Il2CppType* implType, const Il2CppMethodDefinition* implMethod); 82 | void ApplyAOTInterfaceExplicitOverride(const std::vector& implInterfaceOffsetIdxs, Int32ToUin16Map& explicitImplToken2Slots, const Il2CppType* intfType, 83 | const Il2CppType* implType, const Il2CppMethodDefinition* implMethod); 84 | 85 | VTableSetUp* _parent; 86 | std::vector _interfaces; 87 | std::vector _interfaceOffsetInfos; 88 | 89 | const Il2CppType* _type; 90 | const Il2CppTypeDefinition* _typeDef; 91 | const char* _name; // TODO remove 92 | 93 | std::vector _virtualMethods; 94 | std::vector _methodImpls; 95 | 96 | Uin16Set _explicitImplSlots;; 97 | }; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /hybridclr/transform/BasicBlockSpliter.cpp: -------------------------------------------------------------------------------- 1 | #include "BasicBlockSpliter.h" 2 | 3 | #include "../metadata/Opcodes.h" 4 | #include "../metadata/MetadataUtil.h" 5 | 6 | using namespace hybridclr::metadata; 7 | 8 | namespace hybridclr 9 | { 10 | namespace transform 11 | { 12 | 13 | void BasicBlockSpliter::SplitNormal(const byte* ilcodeStart, uint32_t codeSize, Uin32Set& ilOffsets) 14 | { 15 | const byte* codeEnd = ilcodeStart + codeSize; 16 | const byte* ip = ilcodeStart; 17 | 18 | while (ip < codeEnd) 19 | { 20 | ilOffsets.insert((uint32_t)(ip - ilcodeStart)); 21 | const OpCodeInfo* oc = DecodeOpCodeInfo(ip, codeEnd); 22 | IL2CPP_ASSERT(oc); 23 | int32_t opCodeSize = GetOpCodeSize(ip, oc); 24 | const byte* nextIp = ip + opCodeSize; 25 | int32_t nextOffset = (int32_t)(nextIp - ilcodeStart); 26 | IL2CPP_ASSERT(nextOffset >= 0 && nextOffset <= (int32_t)codeSize); 27 | 28 | switch (oc->inlineType) 29 | { 30 | case ArgType::None: 31 | case ArgType::Data: 32 | { 33 | break; 34 | } 35 | case ArgType::StaticBranch: 36 | { 37 | _splitOffsets.insert(nextOffset); 38 | break; 39 | } 40 | case ArgType::BranchTarget: 41 | { 42 | int32_t offset; 43 | switch (oc->inlineParam) 44 | { 45 | case 1: 46 | { 47 | offset = GetI1(ip + 1); 48 | break; 49 | } 50 | case 4: 51 | { 52 | offset = GetI4LittleEndian(ip + 1); 53 | break; 54 | } 55 | default: 56 | { 57 | RaiseExecutionEngineException("invalid BranchTarget param"); 58 | offset = -1; 59 | } 60 | } 61 | // don't split 0 offset br 62 | if (offset != 0 || (oc->baseOpValue == OpcodeValue::LEAVE || oc->baseOpValue == OpcodeValue::LEAVE_S)) 63 | { 64 | _splitOffsets.insert(nextOffset); 65 | _splitOffsets.insert(nextOffset + offset); 66 | } 67 | break; 68 | } 69 | case ArgType::Switch: 70 | { 71 | uint32_t caseNum = GetI4LittleEndian(ip + 1); 72 | bool splitAny = false; 73 | for (uint32_t caseIdx = 0; caseIdx < caseNum; caseIdx++) 74 | { 75 | int32_t caseOffset = GetI4LittleEndian(ip + 5 + caseIdx * 4); 76 | if (caseOffset != 0) 77 | { 78 | _splitOffsets.insert(nextOffset + caseOffset); 79 | splitAny = true; 80 | } 81 | } 82 | if (splitAny) 83 | { 84 | _splitOffsets.insert(nextOffset); 85 | } 86 | break; 87 | } 88 | default: 89 | { 90 | RaiseExecutionEngineException("unknown inline type"); 91 | nextOffset = -1; 92 | } 93 | } 94 | ip = nextIp; 95 | } 96 | IL2CPP_ASSERT(ip == codeEnd); 97 | } 98 | 99 | void BasicBlockSpliter::SplitExceptionHandles(const byte* ilcodeStart, uint32_t codeSize, const std::vector& exceptionClauses) 100 | { 101 | for (auto& eh : exceptionClauses) 102 | { 103 | _splitOffsets.insert(eh.tryOffset); 104 | _splitOffsets.insert(eh.tryOffset + eh.tryLength); 105 | _splitOffsets.insert(eh.handlerOffsets); 106 | _splitOffsets.insert(eh.handlerOffsets + eh.handlerLength); 107 | if (eh.flags == CorILExceptionClauseType::Filter) 108 | { 109 | _splitOffsets.insert(eh.classTokenOrFilterOffset); 110 | } 111 | } 112 | } 113 | 114 | void BasicBlockSpliter::SplitBasicBlocks() 115 | { 116 | const byte* ilcodeStart = _body.ilcodes; 117 | 118 | uint32_t codeSize = _body.codeSize; 119 | 120 | Uin32Set ilOffsets(codeSize); 121 | ilOffsets.insert(codeSize); 122 | 123 | SplitNormal(ilcodeStart, codeSize, ilOffsets); 124 | SplitExceptionHandles(ilcodeStart, codeSize, _body.exceptionClauses); 125 | 126 | /*if (_splitOffsets.find(0) != _splitOffsets.end()) 127 | { 128 | _splitOffsets.erase(0); 129 | }*/ 130 | #if DEBUG 131 | for (uint32_t offset : _splitOffsets) 132 | { 133 | IL2CPP_ASSERT(ilOffsets.find(offset) != ilOffsets.end()); 134 | } 135 | IL2CPP_ASSERT(_splitOffsets.find(codeSize) != _splitOffsets.end()); 136 | #endif 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /hybridclr/transform/BasicBlockSpliter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../CommonDef.h" 6 | #include "../metadata/MetadataDef.h" 7 | 8 | namespace hybridclr 9 | { 10 | namespace transform 11 | { 12 | class BasicBlockSpliter 13 | { 14 | public: 15 | typedef Il2CppHashSet> Uin32Set; 16 | 17 | BasicBlockSpliter(const metadata::MethodBody& body) : _body(body) { } 18 | 19 | void SplitBasicBlocks(); 20 | 21 | const std::set& GetSplitOffsets() const { return _splitOffsets; } 22 | private: 23 | const metadata::MethodBody& _body; 24 | std::set _splitOffsets; 25 | 26 | void SplitNormal(const byte* ilcodeStart, uint32_t codeSize, Uin32Set& ilOffsets); 27 | void SplitExceptionHandles(const byte* ilcodeStart, uint32_t codeSize, const std::vector& exceptionClauses); 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /hybridclr/transform/TemporaryMemoryArena.cpp: -------------------------------------------------------------------------------- 1 | #include "TemporaryMemoryArena.h" 2 | 3 | namespace hybridclr 4 | { 5 | namespace transform 6 | { 7 | 8 | TemporaryMemoryArena::Block TemporaryMemoryArena::AllocBlock(size_t size) 9 | { 10 | void* data = HYBRIDCLR_MALLOC(size); 11 | return { data, size }; 12 | } 13 | 14 | void TemporaryMemoryArena::Begin() 15 | { 16 | IL2CPP_ASSERT(_buf == nullptr); 17 | IL2CPP_ASSERT(_size == 0); 18 | IL2CPP_ASSERT(_pos == 0); 19 | RequireSize(kMinBlockSize); 20 | } 21 | 22 | void TemporaryMemoryArena::End() 23 | { 24 | if (_buf) 25 | { 26 | HYBRIDCLR_FREE(_buf); 27 | //_buf = nullptr; 28 | //_size = _pos = 0; 29 | } 30 | for (auto& block : _useOuts) 31 | { 32 | HYBRIDCLR_FREE(block.data); 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /hybridclr/transform/TemporaryMemoryArena.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../CommonDef.h" 8 | 9 | namespace hybridclr 10 | { 11 | namespace transform 12 | { 13 | const size_t kMinBlockSize = 8 * 1024; 14 | 15 | class TemporaryMemoryArena 16 | { 17 | public: 18 | 19 | TemporaryMemoryArena() : _buf(nullptr), _size(0), _pos(0) 20 | { 21 | Begin(); 22 | } 23 | ~TemporaryMemoryArena() 24 | { 25 | End(); 26 | } 27 | 28 | static size_t AligndSize(size_t size) 29 | { 30 | return (size + 7) & ~7; 31 | } 32 | 33 | template 34 | T* AllocIR() 35 | { 36 | const size_t aligndSize = AligndSize(sizeof(T)); 37 | if (_pos + aligndSize <= _size) 38 | { 39 | T* ir = (T*)(_buf + _pos); 40 | *ir = {}; 41 | _pos += aligndSize; 42 | return ir; 43 | } 44 | 45 | RequireSize(aligndSize); 46 | 47 | T* ir = (T*)(_buf + _pos); 48 | *ir = {}; 49 | _pos += aligndSize; 50 | return ir; 51 | } 52 | 53 | template 54 | T* NewAny() 55 | { 56 | const size_t needSize = AligndSize(sizeof(T)); 57 | if (_pos + needSize <= _size) 58 | { 59 | T* ir = new (_buf + _pos) T(); 60 | *ir = {}; 61 | _pos += needSize; 62 | return ir; 63 | } 64 | 65 | RequireSize(needSize); 66 | 67 | T* ir = new (_buf + _pos) T(); 68 | *ir = {}; 69 | _pos += needSize; 70 | return ir; 71 | } 72 | 73 | template 74 | T* NewNAny(int n) 75 | { 76 | if (n > 0) 77 | { 78 | size_t bytes = AligndSize(sizeof(T) * n); 79 | if (_pos + bytes > _size) 80 | { 81 | RequireSize(bytes); 82 | } 83 | T* ret = new (_buf + _pos) T[n]; 84 | _pos += bytes; 85 | return ret; 86 | } 87 | else 88 | { 89 | return nullptr; 90 | } 91 | } 92 | 93 | void Begin(); 94 | 95 | void End(); 96 | 97 | private: 98 | struct Block 99 | { 100 | void* data; 101 | size_t size; 102 | }; 103 | 104 | void RequireSize(size_t size) 105 | { 106 | if (_buf) 107 | { 108 | _useOuts.push_back({ (void*)_buf, _size}); 109 | } 110 | 111 | Block newBlock = AllocBlock(std::max(size, kMinBlockSize)); 112 | _buf = (byte*)newBlock.data; 113 | _size = newBlock.size; 114 | _pos = 0; 115 | } 116 | 117 | static Block AllocBlock(size_t size); 118 | 119 | std::vector _useOuts; 120 | 121 | byte* _buf; 122 | size_t _size; 123 | size_t _pos; 124 | }; 125 | } 126 | } -------------------------------------------------------------------------------- /hybridclr/transform/Transform.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Transform.h" 3 | 4 | #include 5 | 6 | #include "TransformContext.h" 7 | 8 | #include "../metadata/MethodBodyCache.h" 9 | 10 | namespace hybridclr 11 | { 12 | namespace transform 13 | { 14 | 15 | InterpMethodInfo* HiTransform::Transform(const MethodInfo* methodInfo) 16 | { 17 | TemporaryMemoryArena pool; 18 | 19 | metadata::Image* image = metadata::MetadataModule::GetUnderlyingInterpreterImage(methodInfo); 20 | IL2CPP_ASSERT(image); 21 | 22 | metadata::MethodBodyCache::EnableShrinkMethodBodyCache(false); 23 | metadata::MethodBody* methodBody = metadata::MethodBodyCache::GetMethodBody(image, methodInfo->token); 24 | if (methodBody == nullptr || methodBody->ilcodes == nullptr) 25 | { 26 | TEMP_FORMAT(errMsg, "Method body is null. %s.%s::%s", methodInfo->klass->namespaze, methodInfo->klass->name, methodInfo->name); 27 | il2cpp::vm::Exception::Raise(il2cpp::vm::Exception::GetExecutionEngineException(errMsg)); 28 | } 29 | InterpMethodInfo* result = new (HYBRIDCLR_METADATA_MALLOC(sizeof(InterpMethodInfo))) InterpMethodInfo; 30 | il2cpp::utils::dynamic_array resolveDatas; 31 | TransformContext ctx(image, methodInfo, *methodBody, pool, resolveDatas); 32 | 33 | ctx.TransformBody(0, 0, *result); 34 | metadata::MethodBodyCache::EnableShrinkMethodBodyCache(true); 35 | return result; 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /hybridclr/transform/Transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BasicBlockSpliter.h" 4 | 5 | #include "../metadata/Image.h" 6 | #include "../interpreter/Instruction.h" 7 | #include "../interpreter/Engine.h" 8 | #include "../interpreter/InterpreterDefs.h" 9 | 10 | namespace hybridclr 11 | { 12 | namespace transform 13 | { 14 | class HiTransform 15 | { 16 | public: 17 | static interpreter::InterpMethodInfo* Transform(const MethodInfo* methodInfo); 18 | }; 19 | } 20 | } -------------------------------------------------------------------------------- /hybridclr/transform/TransformContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "TemporaryMemoryArena.h" 7 | 8 | #include "../metadata/Image.h" 9 | #include "../interpreter/Instruction.h" 10 | #include "../interpreter/Engine.h" 11 | #include "../metadata/MetadataUtil.h" 12 | #include "../metadata/Opcodes.h" 13 | #include "../metadata/MetadataModule.h" 14 | #include "../interpreter/Instruction.h" 15 | #include "../interpreter/Interpreter.h" 16 | #include "../interpreter/InterpreterModule.h" 17 | 18 | #include "Transform.h" 19 | 20 | namespace hybridclr 21 | { 22 | namespace transform 23 | { 24 | using namespace hybridclr::metadata; 25 | using namespace hybridclr::interpreter; 26 | 27 | struct IRBasicBlock 28 | { 29 | bool visited; 30 | bool inPending; 31 | uint32_t ilOffset; 32 | uint32_t codeOffset; 33 | std::vector insts; 34 | }; 35 | 36 | struct ArgVarInfo 37 | { 38 | const Il2CppType* type; 39 | Il2CppClass* klass; 40 | int32_t argOffset; // StackObject index 41 | int32_t argLocOffset; 42 | }; 43 | 44 | struct LocVarInfo 45 | { 46 | const Il2CppType* type; 47 | Il2CppClass* klass; 48 | int32_t locOffset; 49 | }; 50 | 51 | enum class EvalStackReduceDataType 52 | { 53 | I4, 54 | I8, 55 | R4, 56 | R8, 57 | Other, 58 | }; 59 | 60 | struct EvalStackVarInfo 61 | { 62 | EvalStackReduceDataType reduceType; 63 | int32_t byteSize; 64 | int32_t locOffset; 65 | }; 66 | 67 | #if HYBRIDCLR_ARCH_64 68 | #define NATIVE_INT_OP opI8 69 | constexpr EvalStackReduceDataType NATIVE_INT_REDUCE_TYPE = EvalStackReduceDataType::I8; 70 | #else 71 | #define NATIVE_INT_OP opI4 72 | constexpr EvalStackReduceDataType NATIVE_INT_REDUCE_TYPE = EvalStackReduceDataType::I4; 73 | #endif 74 | 75 | #define CreateIR(varName, typeName) IR##typeName* varName = pool.AllocIR(); varName->type = HiOpcodeEnum::typeName; 76 | #define CreateAddIR(varName, typeName) IR##typeName* varName = pool.AllocIR(); varName->type = HiOpcodeEnum::typeName; curbb->insts.push_back(varName); if (ir2offsetMap) { ir2offsetMap->add(varName, ipOffset); } 77 | 78 | enum class LocationDescType 79 | { 80 | I1, 81 | U1, 82 | I2, 83 | U2, 84 | I4, 85 | I8, 86 | Ref, 87 | S, 88 | StructContainsRef, 89 | }; 90 | 91 | #if HYBRIDCLR_ARCH_64 92 | #define NATIVE_INT_DESC_TYPE LocationDescType::I8 93 | #define ARCH_ARGUMENT(x32, x64) x64 94 | #else 95 | #define NATIVE_INT_DESC_TYPE LocationDescType::I4 96 | #define ARCH_ARGUMENT(x32, x64) x32 97 | #endif 98 | 99 | struct LocationDescInfo 100 | { 101 | LocationDescType type; 102 | int32_t size; 103 | }; 104 | 105 | struct FlowInfo 106 | { 107 | uint32_t curStackSize; 108 | uint32_t offset; 109 | il2cpp::utils::dynamic_array evalStack; 110 | }; 111 | 112 | typedef Il2CppHashMap> IR2OffsetMap; 113 | 114 | LocationDescInfo ComputLocationDescInfo(const Il2CppType* type); 115 | 116 | class TransformContext 117 | { 118 | private: 119 | metadata::Image* image; 120 | const MethodInfo* methodInfo; 121 | metadata::MethodBody& body; 122 | 123 | 124 | TemporaryMemoryArena& pool; 125 | 126 | int32_t actualParamCount; 127 | 128 | std::set splitOffsets; 129 | IRBasicBlock** ip2bb; 130 | IRBasicBlock* curbb; 131 | 132 | ArgVarInfo* args; 133 | LocVarInfo* locals; 134 | EvalStackVarInfo* evalStack; 135 | int32_t evalStackTop; 136 | int32_t evalStackBaseOffset; 137 | int32_t maxStackSize; 138 | int32_t curStackSize; 139 | 140 | il2cpp::utils::dynamic_array& resolveDatas; 141 | Il2CppHashMap> token2DataIdxs; 142 | Il2CppHashMap> ptr2DataIdxs; 143 | std::vector relocationOffsets; 144 | std::vector> switchOffsetsInResolveData; 145 | std::vector pendingFlows; 146 | int32_t nextFlowIdx; 147 | 148 | const byte* ipBase; 149 | const byte* ip; 150 | uint32_t ipOffset; 151 | IR2OffsetMap* ir2offsetMap; 152 | 153 | int32_t prefixFlags; 154 | 155 | const MethodInfo* shareMethod; 156 | 157 | std::vector irbbs; 158 | il2cpp::utils::dynamic_array exClauses; 159 | 160 | uint32_t totalIRSize; 161 | int32_t totalArgSize; 162 | int32_t totalArgLocalSize; 163 | bool initLocals; 164 | 165 | public: 166 | 167 | TransformContext(hybridclr::metadata::Image* image, const MethodInfo* methodInfo, metadata::MethodBody& body, TemporaryMemoryArena& pool, il2cpp::utils::dynamic_array& resolveDatas); 168 | ~TransformContext(); 169 | 170 | static void InitializeInstinctHandlers(); 171 | 172 | uint32_t GetOrAddResolveDataIndex(const void* ptr); 173 | 174 | TemporaryMemoryArena& GetPool() const 175 | { 176 | return pool; 177 | } 178 | 179 | int32_t GetEvalStackTop() const 180 | { 181 | return evalStackTop; 182 | } 183 | 184 | IRBasicBlock* GetCurbb() const 185 | { 186 | return curbb; 187 | } 188 | 189 | uint32_t GetIpOffset() const 190 | { 191 | return ipOffset; 192 | } 193 | 194 | IR2OffsetMap* GetIr2offsetMap() const 195 | { 196 | return ir2offsetMap; 197 | } 198 | 199 | int32_t GetArgOffset(int32_t idx) const 200 | { 201 | return args[idx].argOffset; 202 | } 203 | 204 | int32_t GetArgLocOffset(int32_t idx) const 205 | { 206 | return args[idx].argLocOffset; 207 | } 208 | 209 | int32_t GetLocOffset(int32_t idx) const 210 | { 211 | return locals[idx].locOffset; 212 | } 213 | 214 | int32_t GetEvalStackOffset(int32_t idx) const 215 | { 216 | return idx < evalStackTop ? evalStack[idx].locOffset : curStackSize; 217 | } 218 | 219 | int32_t GetEvalStackTopOffset() const 220 | { 221 | return evalStackTop > 0 ? evalStack[evalStackTop - 1].locOffset : curStackSize; 222 | } 223 | 224 | int32_t GetEvalStackNewTopOffset() const 225 | { 226 | return curStackSize; 227 | } 228 | 229 | int32_t GetEvalStackOffset_5() const 230 | { 231 | return evalStack[evalStackTop - 5].locOffset; 232 | } 233 | 234 | int32_t GetEvalStackOffset_4() const 235 | { 236 | return evalStack[evalStackTop - 4].locOffset; 237 | } 238 | 239 | int32_t GetEvalStackOffset_3() const 240 | { 241 | return evalStack[evalStackTop - 3].locOffset; 242 | } 243 | 244 | int32_t GetEvalStackOffset_2() const 245 | { 246 | return evalStack[evalStackTop - 2].locOffset; 247 | } 248 | 249 | int32_t GetEvalStackOffset_1() const 250 | { 251 | return evalStack[evalStackTop - 1].locOffset; 252 | } 253 | 254 | void PushStackByType(const Il2CppType* type); 255 | 256 | void PushStackByReduceType(EvalStackReduceDataType t); 257 | 258 | void DuplicateStack(); 259 | 260 | void PopStack(); 261 | 262 | void PopStackN(int32_t n); 263 | 264 | void PopAllStack(); 265 | 266 | void InsertMemoryBarrier(); 267 | 268 | void ResetPrefixFlags(); 269 | 270 | void Add_ldind(HiOpcodeEnum opCode, EvalStackReduceDataType dataType); 271 | 272 | void Add_stind(HiOpcodeEnum opCode); 273 | 274 | void PushOffset(int32_t* offsetPtr); 275 | 276 | void PushBranch(int32_t targetOffset); 277 | 278 | bool FindNextFlow(); 279 | 280 | void AddInst(IRCommon* ir); 281 | 282 | void AddInst_ldarg(int32_t argIdx); 283 | 284 | bool IsCreateNotNullObjectInstrument(IRCommon* ir); 285 | 286 | IRCommon* GetLastInstrument() 287 | { 288 | return curbb->insts.empty() ? nullptr : curbb->insts.back(); 289 | } 290 | 291 | void RemoveLastInstrument(); 292 | 293 | void AddInst_ldarga(int32_t argIdx); 294 | 295 | void AddInst_starg(int32_t argIdx); 296 | 297 | void CreateAddInst_ldloc(int32_t locIdx); 298 | 299 | void CreateAddInst_stloc(int32_t locIdx); 300 | 301 | void CreateAddInst_ldloca(int32_t locIdx); 302 | 303 | void CreateAddInst_ldc4(int32_t c, EvalStackReduceDataType rtype); 304 | 305 | void CreateAddInst_ldc8(int64_t c, EvalStackReduceDataType rtype); 306 | 307 | void Add_brtruefalse(bool c, int32_t targetOffset); 308 | 309 | void Add_bc(int32_t ipOffset, int32_t brOffset, int32_t opSize, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8); 310 | 311 | void Add_conv(int32_t dstTypeSize, EvalStackReduceDataType dstReduceType, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8); 312 | 313 | void Add_conv_ovf(int32_t dstTypeSize, EvalStackReduceDataType dstReduceType, HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8); 314 | 315 | void Add_binop(HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8); 316 | 317 | void Add_shiftop(HiOpcodeEnum opI4I4, HiOpcodeEnum opI4I8, HiOpcodeEnum opI8I4, HiOpcodeEnum opI8I8); 318 | 319 | void Add_compare(HiOpcodeEnum opI4, HiOpcodeEnum opI8, HiOpcodeEnum opR4, HiOpcodeEnum opR8); 320 | 321 | void Add_ldelem(EvalStackReduceDataType resultType, HiOpcodeEnum opI4); 322 | void Add_stelem(HiOpcodeEnum opI4); 323 | 324 | bool FindFirstLeaveHandlerIndex(const std::vector& exceptionClauses, uint32_t leaveOffset, uint32_t targetOffset, uint16_t& index); 325 | 326 | bool IsLeaveInTryBlock(const std::vector& exceptionClauses, uint32_t leaveOffset); 327 | 328 | void Add_leave(uint32_t targetOffset); 329 | 330 | uint16_t FindFirstThrowHandlerIndex(const std::vector& exceptionClauses, uint32_t throwOffset); 331 | 332 | bool TryAddInstinctInstruments(const MethodInfo* method) 333 | { 334 | return TryAddInstinctInstrumentsByName(method) || TryAddArrayInstinctInstruments(method); 335 | } 336 | 337 | bool TryAddInstinctInstrumentsByName(const MethodInfo* method); 338 | bool TryAddArrayInstinctInstruments(const MethodInfo* method); 339 | 340 | bool TryAddInstinctCtorInstruments(const MethodInfo* method); 341 | 342 | bool TryAddCallCommonInstruments(const MethodInfo* method, uint32_t methodDataIndex) 343 | { 344 | bool resolvedIsInstanceMethod = IsInstanceMethod(method); 345 | bool add = resolvedIsInstanceMethod ? TryAddCallCommonInstanceInstruments(method, methodDataIndex) 346 | : TryAddCallCommonStaticInstruments(method, methodDataIndex); 347 | if (add) 348 | { 349 | int32_t resolvedTotalArgNum = method->parameters_count + resolvedIsInstanceMethod; 350 | PopStackN(resolvedTotalArgNum); 351 | if (method->return_type->type != IL2CPP_TYPE_VOID) 352 | { 353 | PushStackByType(method->return_type); 354 | } 355 | return true; 356 | } 357 | return false; 358 | } 359 | 360 | bool TryAddCallCommonInstanceInstruments(const MethodInfo* method, uint32_t methodDataIndex); 361 | bool TryAddCallCommonStaticInstruments(const MethodInfo* method, uint32_t methodDataIndex); 362 | 363 | 364 | HiOpcodeEnum CalcGetMdArrElementVarVarOpcode(const Il2CppType* type); 365 | 366 | void TransformBody(int32_t depth, int32_t localVarOffset, interpreter::InterpMethodInfo& result); 367 | 368 | private: 369 | void TransformBodyImpl(int32_t depth, int32_t localVarOffset); 370 | void BuildInterpMethodInfo(interpreter::InterpMethodInfo& result); 371 | static bool TransformSubMethodBody(TransformContext& callingCtx, const MethodInfo* subMethod, int32_t depth, int32_t localVarOffset); 372 | }; 373 | } 374 | } -------------------------------------------------------------------------------- /hybridclr/transform/TransformModule.cpp: -------------------------------------------------------------------------------- 1 | #include "TransformModule.h" 2 | #include "TransformContext.h" 3 | 4 | namespace hybridclr 5 | { 6 | namespace transform 7 | { 8 | void TransformModule::Initialize() 9 | { 10 | TransformContext::InitializeInstinctHandlers(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /hybridclr/transform/TransformModule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace hybridclr 4 | { 5 | namespace transform 6 | { 7 | class TransformModule 8 | { 9 | public: 10 | static void Initialize(); 11 | }; 12 | } 13 | } --------------------------------------------------------------------------------