Skip to content

Commit d2d4ca1

Browse files
committed
Added support for creating function pointers
1 parent ace2a3f commit d2d4ca1

File tree

13 files changed

+214
-55
lines changed

13 files changed

+214
-55
lines changed

cargo_tests/build_core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ edition = "2021"
88
[dependencies]
99
mycorrhiza = {path="../../mycorrhiza"}
1010
[workspace]
11-
11+
[profile.release.build-override]
1212
codegen-units = 1

cargo_tests/build_core/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
use mycorrhiza::{start,panic_handler};
66
panic_handler!{}
77
start!{}
8-
//#[lang = "eh_personality"]
9-
//fn rust_eh_personality() {}
8+
#[lang = "eh_personality"]
9+
fn rust_eh_personality() {}
1010
fn main() {
1111
let sb = mycorrhiza::system::text::StringBuilder::empty();
1212
sb.append_char('H');

src/assembly.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ impl Assembly {
415415
//FIXME:This is inefficient.
416416
self.methods().any(|m| m.name() == name)
417417
}
418+
/// Returns true if assembly contains function named `name`
419+
pub fn contains_fn(&self, site: &CallSite) -> bool {
420+
self.functions.contains_key(site)
421+
}
418422
/// Adds a method to the assebmly.
419423
pub fn add_method(&mut self, mut method: Method) {
420424
method.allocate_temporaries();

src/assembly_exporter/ilasm_op.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,35 @@ pub fn op_cli(op: &crate::cil::CILOp) -> Cow<'static, str> {
4949
.into()
5050
}
5151
}
52+
CILOp::LDFtn(call_site)=>{
53+
//assert!(sig.inputs.is_empty());
54+
let mut inputs_iter = call_site.explicit_inputs().iter();
55+
let mut input_string = String::new();
56+
if let Some(firts_arg) = inputs_iter.next() {
57+
input_string.push_str(&non_void_type_cil(firts_arg));
58+
}
59+
for arg in inputs_iter {
60+
input_string.push(',');
61+
input_string.push_str(&non_void_type_cil(arg));
62+
}
63+
let prefix = if call_site.is_static() {
64+
""
65+
} else {
66+
"instance"
67+
};
68+
let owner_name = match call_site.class() {
69+
Some(owner) => {
70+
format!("{}::", type_cil(&owner.clone().into()))
71+
}
72+
None => String::new(),
73+
};
74+
format!(
75+
"ldftn {prefix} {output} {owner_name} {function_name}({input_string})",
76+
function_name = call_site.name(),
77+
output = type_cil(call_site.signature().output())
78+
)
79+
.into()
80+
}
5281
CILOp::CallVirt(call_site) => {
5382
if call_site.is_nop() {
5483
"".into()
@@ -400,6 +429,18 @@ pub fn non_void_type_cil(tpe: &Type) -> Cow<'static, str> {
400429
}
401430
pub fn type_cil(tpe: &Type) -> Cow<'static, str> {
402431
match tpe {
432+
Type::DelegatePtr(sig)=>{
433+
let mut inputs_iter = sig.inputs().iter();
434+
let mut input_string = String::new();
435+
if let Some(firts_arg) = inputs_iter.next() {
436+
input_string.push_str(&non_void_type_cil(firts_arg));
437+
}
438+
for arg in inputs_iter {
439+
input_string.push(',');
440+
input_string.push_str(&non_void_type_cil(arg));
441+
}
442+
format!("method {output}*({input_string})",output = type_cil(sig.output())).into()
443+
}
403444
Type::FnDef(name) => format!("valuetype fn_{name}").into(),
404445
Type::Void => "void".into(),
405446
Type::I8 => "int8".into(),

src/bin/linker.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn autopatch(asm: &mut Assembly) {
9696
let call_sites = asm
9797
.call_sites()
9898
.filter(|call| call.is_static() && call.class().is_none())
99-
.filter(|call| !asm.contains_fn_named(call.name()));
99+
.filter(|call| !asm.contains_fn(call));
100100
let mut patched = std::collections::HashMap::new();
101101
for call in call_sites {
102102
if !patched.contains_key(call) {

src/bin/rustflags.rs

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,64 @@
11
fn main() {
22
let build_env = rustc_codegen_clr::compile_test::cargo_build_env();
3-
println!("In order to compile cargo crates with `rustc_codegen_clr`, please set the RUSTFLAGS enviorment variable to:");
3+
let print_raw_env = std::env::args().any(|arg| arg == "--print_raw_env");
4+
let setup_command = std::env::args().any(|arg| arg == "--setup_command");
5+
if print_raw_env{
6+
println!("\"{build_env}\"");
7+
return;
8+
}
9+
if setup_command{
10+
#[cfg(target_family = "unix")]
11+
println!("export RUSTFLAGS=\"{build_env}\"");
12+
#[cfg(target_family = "windows")]
13+
println!("$Env:RUSTFLAGS = '{build_env}'");
14+
return
15+
}
16+
println!("Welcome to the `rustc_codegen_clr` environment setup helper!");
17+
println!("This tool will help you use the codegen to compile Rust projects.");
18+
println!("WARNING: Please note, the project is currently in the early stages of development. Bugs, crashes and miscompilations will occur.");
19+
println!("Currently, there is no way to permanently install the codegen. It is enabled on a per-shell-session basis (enabled for your particular command prompt window).");
20+
println!("");
21+
println!("In order to compile cargo crates with `rustc_codegen_clr`, please set the RUSTFLAGS environment variable to:");
422
println!();
5-
println!("\"{build_env}\"");
6-
println!();
7-
println!("On linux, you may use the following commmand to quickly set the required enviroment variables:");
8-
println!();
9-
println!("export RUSTFLAGS=\"{build_env}\"");
1023
println!();
11-
println!("On windows(powershell), you may use the following commmand to quickly set the required enviroment variables:");
12-
println!();
13-
println!("$Env:RUSTFLAGS = '{build_env}'");
14-
println!();
15-
println!("After you are done working with `rustc_codegen_clr` either unset the enviroment variable OR restart your shell(close the command prompt window).");
16-
println!("On linux, you may use the following commmand to quickly unset the required enviroment variables:");
24+
println!("\"{build_env}\"");
1725
println!();
18-
println!("unset RUSTFLAGS");
1926
println!();
20-
println!("Please note that those varaibles may change when the codegen is updated/rebuilt.");
21-
println!("After each time the codegen is rebuilt, please use this tool again to get updated build enviroment variables.");
27+
#[cfg(target_family = "unix")]{
28+
println!("You may use the following command to quickly set the required environment variables:");
29+
println!();
30+
println!();
31+
println!("export RUSTFLAGS=\"{build_env}\"");
32+
println!();
33+
println!();
34+
}
35+
#[cfg(target_family = "windows")]{
36+
println!("You may use the following command to quickly set the required environment variables:");
37+
println!();
38+
println!();
39+
println!("$Env:RUSTFLAGS = '{build_env}'");
40+
println!();
41+
println!();
42+
}
43+
println!("After you are done working with `rustc_codegen_clr` either unset the environment variable OR restart your shell (close the command prompt window).");
44+
#[cfg(target_family = "unix")]{
45+
println!("You may use the following command to quickly unset the required environment variables:");
46+
println!();
47+
println!();
48+
println!("unset RUSTFLAGS");
49+
println!();
50+
println!();
51+
}
52+
#[cfg(target_family = "windows")]{
53+
println!();
54+
}
55+
println!("Please note that those variables may change when the codegen is updated/rebuilt.");
56+
println!("After each time the codegen is rebuilt, please use this tool again to get updated build environment variables.");
2257
println!();
2358
println!("If you are using the project, please remember to:");
2459
println!("1. Update BOTH rustc and the project on a regular basis.");
25-
println!("2. Report compiler bugs to the maintainers of `rustc_codegen_clr` not the maintainers of the compiler as a whole.");
26-
println!(" In 99.999% of the cases, the bug is wihin this project and not the compiler.");
60+
println!("2. Report compiler bugs to the maintainers of `rustc_codegen_clr`, and not the maintainers of the Rust compiler as a whole.");
61+
println!(" In 99.999% of the cases, the bug is within this project and not the Rust compiler.");
62+
println!("");
63+
// std::env::set_var("RUSTFLAGS", build_env);
2764
}

src/cil/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ pub enum CILOp {
9696
LdcF64(f64),
9797
/// Load string literal
9898
LdStr(IString),
99+
/// Load the address of a function
100+
LDFtn(Box<CallSite>),
99101
/// Load null reference
100102
LdNull,
101103
/// Signed intieger convertions
@@ -252,12 +254,13 @@ impl CILOp {
252254
_ => (),
253255
}
254256
}
255-
/// If the cil op is a call, virtual call or new object cosntructor, returns the [`CallSite`] representing the called function.
257+
/// If the cil op is a call, virtual call, new object cosntructor OR it loads a pointer to a function, returns the [`CallSite`] representing this function.
256258
pub fn call(&self) -> Option<&CallSite> {
257259
match self {
258260
Self::Call(site) => Some(site),
259261
Self::CallVirt(site) => Some(site),
260262
Self::NewObj(site) => Some(site),
263+
Self::LDFtn(site)=>Some(site),
261264
_ => None,
262265
}
263266
}
@@ -444,6 +447,7 @@ impl CILOp {
444447
| CILOp::LoadAdressUnderTMPLocal(_)
445448
| CILOp::LoadTMPLocal => 1,
446449
CILOp::SetTMPLocal => -1,
450+
CILOp::LDFtn(_) => 1,
447451
CILOp::LoadGlobalAllocPtr { alloc_id: _ } => 1,
448452
}
449453
}

src/compile_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,9 +545,10 @@ test_lib! {libc}
545545

546546
test_lib! {references}
547547
//test_lib! {structs}
548-
548+
test_lib! {empty_string_slice}
549549
test_lib! {types}
550550
test_lib! {recursive}
551+
test_lib! {fn_ptr}
551552
test_lib! {tuple}
552553

553554
run_test! {arthm,add}

src/constant.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,23 @@ fn create_const_from_slice<'ctx>(
195195
)),
196196
CILOp::ConvUSize(false),
197197
],
198-
_ => todo!("Can't yet load const value of type {int:?} with bytes:{bytes:?}"),
198+
IntTy::I128=>{
199+
let value = u128::from_ne_bytes(bytes[..std::mem::size_of::<i128>()].try_into().expect("Invalid slice!"));
200+
let low = (value & u128::from(u64::MAX)) as u64;
201+
let high = (value << 64) as u64;
202+
let low = i64::from_ne_bytes(low.to_ne_bytes());
203+
let high = i64::from_ne_bytes(high.to_ne_bytes());
204+
let ctor_sig =
205+
crate::function_sig::FnSig::new(&[Type::U64, Type::U64], &Type::Void);
206+
vec![CILOp::LdcI64(high),
207+
CILOp::LdcI64(low),
208+
CILOp::NewObj(CallSite::boxed(
209+
Some(DotnetTypeRef::int_128()),
210+
".ctor".into(),
211+
ctor_sig,
212+
true,
213+
))]
214+
}
199215
},
200216
TyKind::Uint(int) => match int {
201217
UintTy::U8 => vec![
@@ -224,7 +240,23 @@ fn create_const_from_slice<'ctx>(
224240
)),
225241
CILOp::ConvUSize(false),
226242
],
227-
_ => todo!("Can't yet load const value of type {int:?} with bytes:{bytes:?}"),
243+
UintTy::U128=>{
244+
let value = u128::from_ne_bytes(bytes[..std::mem::size_of::<u128>()].try_into().expect("Invalid slice!"));
245+
let low = (value & u128::from(u64::MAX)) as u64;
246+
let high = (value << 64) as u64;
247+
let low = i64::from_ne_bytes(low.to_ne_bytes());
248+
let high = i64::from_ne_bytes(high.to_ne_bytes());
249+
let ctor_sig =
250+
crate::function_sig::FnSig::new(&[Type::U64, Type::U64], &Type::Void);
251+
vec![CILOp::LdcI64(high),
252+
CILOp::LdcI64(low),
253+
CILOp::NewObj(CallSite::boxed(
254+
Some(DotnetTypeRef::uint_128()),
255+
".ctor".into(),
256+
ctor_sig,
257+
true,
258+
))]
259+
}
228260
},
229261
TyKind::RawPtr(type_and_mut) => match type_and_mut.ty.kind() {
230262
TyKind::Slice(_) => {

src/rvalue.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,30 @@ pub fn handle_rvalue<'tcx>(
351351
}
352352
ops
353353
}
354+
Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer), operand,target)=>{
355+
let operand_ty = operand.ty(method,tyctx);
356+
operand.constant().expect("function must be constant in order to take its adress!");
357+
let operand_ty = crate::utilis::monomorphize(&method_instance, operand_ty, tyctx);
358+
let target = crate::utilis::monomorphize(&method_instance, *target, tyctx);
359+
let (instance, subst_ref) = if let TyKind::FnDef(def_id, subst_ref) = operand_ty.kind() {
360+
let subst = crate::utilis::monomorphize(&method_instance, *subst_ref, tyctx);
361+
let env = ParamEnv::reveal_all();
362+
let Some(instance) =
363+
Instance::resolve(tyctx, env, *def_id, subst).expect("Invalid function def")
364+
else {
365+
panic!("ERROR: Could not get function instance. fn type:{operand_ty:?}")
366+
};
367+
368+
(instance, subst_ref)
369+
} else {
370+
todo!("Trying to call a type which is not a function definition!");
371+
};
372+
let function_name = crate::utilis::function_name(tyctx.symbol_name(instance));
373+
let function_sig = FnSig::sig_from_instance_(instance,tyctx,tycache).expect("Could not get function signature when trying to get a function pointer!");
374+
//FIXME: propely handle `#[track_caller]`
375+
let call_site = CallSite::new(None,function_name,function_sig,true);
376+
vec![CILOp::LDFtn(call_site.into())]
377+
}
354378
Rvalue::Cast(kind, _operand, _) => todo!("Unhandled cast kind {kind:?}, rvalue:{rvalue:?}"),
355379
Rvalue::Discriminant(place) => {
356380
let mut ops =
@@ -430,6 +454,7 @@ pub fn handle_rvalue<'tcx>(
430454
ops.push(CILOp::FreeTMPLocal);
431455
ops
432456
}
457+
433458
_ => rustc_middle::ty::print::with_no_trimmed_paths! {todo!("Unhandled RValue {rvalue:?}")},
434459
};
435460
res

src/type/tycache.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,6 @@ impl TyCache {
255255
}
256256
TyKind::Never => Type::Void,
257257
TyKind::RawPtr(type_and_mut) => {
258-
let (metadata, fat_if_not_sized) =
259-
type_and_mut.ty.ptr_metadata_ty(tyctx, |mut ty| {
260-
method.inspect(|method| {
261-
ty = crate::utilis::monomorphize(method, ty, tyctx);
262-
});
263-
ty
264-
});
265-
//TODO: fat_if_not_sized is suposed to tell me if a pointer being fat depends on if the type is sized.
266-
// I am not sure how this is suposed to work exactly, so it gets ignored for now.
267-
let is_sized = type_and_mut.ty.is_sized(tyctx, ParamEnv::reveal_all());
268258
if super::pointer_to_is_fat(type_and_mut.ty, tyctx, method) {
269259
let inner = match type_and_mut.ty.kind() {
270260
TyKind::Slice(inner) => {
@@ -302,16 +292,8 @@ impl TyCache {
302292
Type::Unresolved
303293
}
304294
TyKind::Ref(_region, inner, _mut) => {
305-
let (metadata, fat_if_not_sized) = inner.ptr_metadata_ty(tyctx, |mut ty| {
306-
method.inspect(|method| {
307-
ty = crate::utilis::monomorphize(method, ty, tyctx);
308-
});
309-
ty
310-
});
311-
//TODO: fat_if_not_sized is suposed to tell me if a pointer being fat depends on if the type is sized.
312-
// I am not sure how this is suposed to work exactly, so it gets ignored for now.
313-
let is_sized = inner.is_sized(tyctx, ParamEnv::reveal_all());
314-
if !is_sized {
295+
296+
if super::pointer_to_is_fat(*inner, tyctx, method) {
315297
let inner = match inner.kind() {
316298
TyKind::Slice(inner) => {
317299
let inner = if let Some(method) = method {
@@ -352,9 +334,17 @@ impl TyCache {
352334
Type::Foreign
353335
}
354336
TyKind::Bound(_, _inner) => Type::Foreign,
355-
TyKind::FnPtr(_) => Type::USize,
356-
TyKind::Slice(_inner) => {
357-
todo!("Slice!")
337+
TyKind::FnPtr(sig)=> {
338+
let sig = if let Some(method) = method {
339+
crate::utilis::monomorphize(&method, *sig, tyctx)
340+
} else {
341+
*sig
342+
};
343+
let sig = sig.skip_binder();
344+
let output = self.type_from_cache(sig.output(), tyctx, method);
345+
let inputs:Box<[Type]> = sig.inputs().iter().map(|input|self.type_from_cache(*input, tyctx, method)).collect();
346+
let sig = FnSig::new(&inputs,&output);
347+
Type::DelegatePtr(sig.into())
358348
}
359349
TyKind::FnDef(did, subst) => {
360350
let instance = Instance::resolve(tyctx, ParamEnv::reveal_all(), *did, subst)

0 commit comments

Comments
 (0)