├── .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 | [](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE)
7 |
8 | 
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 | 
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 | [](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE)
8 |
9 | 
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 | 
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 | }
--------------------------------------------------------------------------------