1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Generic parameter substitution and type signature resolution for the emulation context.
//!
//! Provides conversion of `TypeSignature` to metadata tokens and substitution of
//! generic type/method parameters in method signatures.
use crate::{
emulation::{
engine::{context::EmulationContext, generics::GenericRegistry},
tokens,
},
metadata::{
signatures::{SignatureMethod, SignatureParameter, TypeSignature},
token::Token,
typesystem::CilPrimitiveKind,
},
};
impl EmulationContext {
/// Converts a `TypeSignature` to a metadata `Token`.
///
/// Maps primitive type signatures to their well-known `CilPrimitiveKind` tokens
/// (`0xF000_xxxx`), concrete class/value type references to their tokens,
/// and generic instantiations to synthetic tokens via `GenericRegistry`.
///
/// Generic parameters (`GenericParamType`/`GenericParamMethod`) are resolved
/// from the provided type/method argument lists when available.
///
/// # Arguments
///
/// * `sig` - The type signature to resolve
/// * `type_args` - Type-level generic arguments (`!0`, `!1`, ...) if available
/// * `method_args` - Method-level generic arguments (`!!0`, `!!1`, ...) if available
/// * `generics` - Generic registry for creating synthetic instantiation tokens
#[must_use]
pub fn type_signature_to_token(
&self,
sig: &TypeSignature,
type_args: Option<&[Token]>,
method_args: Option<&[Token]>,
generics: &GenericRegistry,
) -> Option<Token> {
match sig {
// Primitive types → well-known tokens
TypeSignature::Void => Some(CilPrimitiveKind::Void.token()),
TypeSignature::Boolean => Some(CilPrimitiveKind::Boolean.token()),
TypeSignature::Char => Some(CilPrimitiveKind::Char.token()),
TypeSignature::I1 => Some(CilPrimitiveKind::I1.token()),
TypeSignature::U1 => Some(CilPrimitiveKind::U1.token()),
TypeSignature::I2 => Some(CilPrimitiveKind::I2.token()),
TypeSignature::U2 => Some(CilPrimitiveKind::U2.token()),
TypeSignature::I4 => Some(CilPrimitiveKind::I4.token()),
TypeSignature::U4 => Some(CilPrimitiveKind::U4.token()),
TypeSignature::I8 => Some(CilPrimitiveKind::I8.token()),
TypeSignature::U8 => Some(CilPrimitiveKind::U8.token()),
TypeSignature::R4 => Some(CilPrimitiveKind::R4.token()),
TypeSignature::R8 => Some(CilPrimitiveKind::R8.token()),
TypeSignature::I => Some(CilPrimitiveKind::I.token()),
TypeSignature::U => Some(CilPrimitiveKind::U.token()),
TypeSignature::String => Some(CilPrimitiveKind::String.token()),
TypeSignature::Object => Some(CilPrimitiveKind::Object.token()),
TypeSignature::TypedByRef => Some(CilPrimitiveKind::TypedReference.token()),
// Concrete class or value type → direct token
TypeSignature::Class(token) | TypeSignature::ValueType(token) => Some(*token),
// Generic type parameter (!0, !1, ...) → resolve from type args
TypeSignature::GenericParamType(index) => {
type_args.and_then(|args| args.get(*index as usize).copied())
}
// Generic method parameter (!!0, !!1, ...) → resolve from method args
TypeSignature::GenericParamMethod(index) => {
method_args.and_then(|args| args.get(*index as usize).copied())
}
// Generic instantiation (e.g., List<int>) → register in GenericRegistry
TypeSignature::GenericInst(base, args) => {
let base_token =
self.type_signature_to_token(base, type_args, method_args, generics)?;
let arg_tokens: Vec<Token> = args
.iter()
.filter_map(|a| {
self.type_signature_to_token(a, type_args, method_args, generics)
})
.collect();
if arg_tokens.len() != args.len() {
return None; // Could not resolve all args
}
Some(generics.get_or_create_type(base_token, arg_tokens))
}
// SzArray (T[]) → encode as an SzArray primitive token that preserves
// the array-ness. For primitive element types (byte, int, etc.), the token
// is SZARRAY_PRIMITIVE_BASE | element_kind_id. This allows GetTypeFromHandle
// and GetElementType to correctly handle typeof(byte[]).GetElementType()→byte.
TypeSignature::SzArray(sz_array) => {
let elem_token =
self.type_signature_to_token(&sz_array.base, type_args, method_args, generics)?;
// For primitive element types (0xF000_00xx), encode as SzArray primitive
let elem_value = elem_token.value();
if elem_value & 0xFFFF_FF00 == 0xF000_0000 {
let kind_id = elem_value & 0xFF;
Some(Token::new(tokens::ranges::SZARRAY_PRIMITIVE_BASE | kind_id))
} else {
// Non-primitive array types (e.g., object[]) — register in
// GenericRegistry with a well-known sentinel base
let sentinel = Token::new(tokens::ranges::SZARRAY_PRIMITIVE_BASE);
Some(generics.get_or_create_type(sentinel, vec![elem_token]))
}
}
// ByRef — unwrap and return inner token
TypeSignature::ByRef(inner) => {
self.type_signature_to_token(inner, type_args, method_args, generics)
}
// Ptr — unwrap and return inner token
TypeSignature::Ptr(ptr) => {
self.type_signature_to_token(&ptr.base, type_args, method_args, generics)
}
// Pinned — unwrap and return inner token
TypeSignature::Pinned(inner) => {
self.type_signature_to_token(inner, type_args, method_args, generics)
}
// Types that don't map cleanly to a single token
_ => None,
}
}
/// Substitutes generic type parameters in a method signature.
///
/// Walks the method's parameter and return type signatures, replacing
/// `GenericParamType(n)` with `type_args[n]` and `GenericParamMethod(n)`
/// with `method_args[n]`. This is needed for correct signature matching
/// when dispatching generic method instantiations.
///
/// # Arguments
///
/// * `sig` - The method signature to substitute
/// * `type_args` - Type-level generic arguments (`!0`, `!1`, ...)
/// * `method_args` - Method-level generic arguments (`!!0`, `!!1`, ...)
#[must_use]
pub fn substitute_generic_params(
sig: &SignatureMethod,
type_args: Option<&[Token]>,
method_args: Option<&[Token]>,
) -> SignatureMethod {
let substitute_type_sig = |ts: &TypeSignature| -> TypeSignature {
Self::substitute_type_signature(ts, type_args, method_args)
};
let new_params: Vec<SignatureParameter> = sig
.params
.iter()
.map(|p| SignatureParameter {
base: substitute_type_sig(&p.base),
by_ref: p.by_ref,
modifiers: p.modifiers.clone(),
})
.collect();
let new_return = SignatureParameter {
base: substitute_type_sig(&sig.return_type.base),
by_ref: sig.return_type.by_ref,
modifiers: sig.return_type.modifiers.clone(),
};
let mut result = sig.clone();
result.return_type = new_return;
result.params = new_params;
result
}
/// Substitutes generic parameters in a single type signature.
fn substitute_type_signature(
sig: &TypeSignature,
type_args: Option<&[Token]>,
method_args: Option<&[Token]>,
) -> TypeSignature {
match sig {
TypeSignature::GenericParamType(index) => {
if let Some(token) = type_args.and_then(|args| args.get(*index as usize)) {
TypeSignature::Class(*token)
} else {
sig.clone()
}
}
TypeSignature::GenericParamMethod(index) => {
if let Some(token) = method_args.and_then(|args| args.get(*index as usize)) {
TypeSignature::Class(*token)
} else {
sig.clone()
}
}
TypeSignature::GenericInst(base, args) => {
let new_base = Self::substitute_type_signature(base, type_args, method_args);
let new_args: Vec<TypeSignature> = args
.iter()
.map(|a| Self::substitute_type_signature(a, type_args, method_args))
.collect();
TypeSignature::GenericInst(Box::new(new_base), new_args)
}
TypeSignature::SzArray(sz) => {
let new_elem = Self::substitute_type_signature(&sz.base, type_args, method_args);
TypeSignature::SzArray(crate::metadata::signatures::SignatureSzArray {
base: Box::new(new_elem),
modifiers: sz.modifiers.clone(),
})
}
TypeSignature::ByRef(inner) => TypeSignature::ByRef(Box::new(
Self::substitute_type_signature(inner, type_args, method_args),
)),
TypeSignature::Pinned(inner) => TypeSignature::Pinned(Box::new(
Self::substitute_type_signature(inner, type_args, method_args),
)),
_ => sig.clone(),
}
}
}