Skip to content

Commit 2b4bbba

Browse files
committed
Ensure debugger doesn't crash and pass type down to BuildCall
1 parent adc3c95 commit 2b4bbba

File tree

11 files changed

+148
-72
lines changed

11 files changed

+148
-72
lines changed

sources/LLVMSharp.Interop/Extensions/LLVMTypeRef.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public LLVMTypeRef(IntPtr handle)
5151

5252
public LLVMContextRef Context => (Handle != IntPtr.Zero) ? LLVM.GetTypeContext(this) : default;
5353

54-
public LLVMTypeRef ElementType => ((Kind == LLVMTypeKind.LLVMPointerTypeKind) || (Kind == LLVMTypeKind.LLVMArrayTypeKind) || (Kind == LLVMTypeKind.LLVMVectorTypeKind)) ? LLVM.GetElementType(this) : default;
54+
public LLVMTypeRef ElementType => (((Kind == LLVMTypeKind.LLVMPointerTypeKind) && (SubtypesCount != 0)) || (Kind == LLVMTypeKind.LLVMArrayTypeKind) || (Kind == LLVMTypeKind.LLVMVectorTypeKind)) ? LLVM.GetElementType(this) : default;
5555

5656
public uint IntWidth => (Kind == LLVMTypeKind.LLVMIntegerTypeKind) ? LLVM.GetIntTypeWidth(this) : default;
5757

sources/LLVMSharp.Interop/Extensions/LLVMValueRef.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public LLVMDLLStorageClass DLLStorageClass
9393
}
9494
}
9595

96-
public LLVMBasicBlockRef EntryBasicBlock => (IsAFunction != null) ? LLVM.GetEntryBasicBlock(this) : default;
96+
public LLVMBasicBlockRef EntryBasicBlock => ((IsAFunction != null) && (BasicBlocksCount != 0)) ? LLVM.GetEntryBasicBlock(this) : default;
9797

9898
public LLVMRealPredicate FCmpPredicate => (Handle != IntPtr.Zero) ? LLVM.GetFCmpPredicate(this) : default;
9999

@@ -147,6 +147,8 @@ public string GC
147147

148148
public bool HasMetadata => (IsAInstruction != null) && LLVM.HasMetadata(this) != 0;
149149

150+
public bool HasPersonalityFn => (IsAFunction != null) && LLVM.HasPersonalityFn(this) != 0;
151+
150152
public bool HasUnnamedAddr
151153
{
152154
get
@@ -360,7 +362,7 @@ public uint InstructionCallConv
360362

361363
public LLVMValueRef IsASwitchInst => LLVM.IsASwitchInst(this);
362364

363-
public LLVMValueRef IsATerminatorInst => LLVM.IsATerminatorInst(this);
365+
public LLVMValueRef IsATerminatorInst => (IsAInstruction != null) ? LLVM.IsATerminatorInst(this) : default;
364366

365367
public LLVMValueRef IsATruncInst => LLVM.IsATruncInst(this);
366368

@@ -500,7 +502,7 @@ public LLVMValueRef[] MDNodeOperands
500502
}
501503
}
502504

503-
public uint MDNodeOperandsCount => (Kind != LLVMValueKind.LLVMMetadataAsValueValueKind) ? LLVM.GetMDNodeNumOperands(this) : default;
505+
public uint MDNodeOperandsCount => (Kind == LLVMValueKind.LLVMMetadataAsValueValueKind) ? LLVM.GetMDNodeNumOperands(this) : default;
504506

505507
public string Name
506508
{
@@ -567,7 +569,7 @@ public LLVMValueRef PersonalityFn
567569
{
568570
get
569571
{
570-
return (IsAFunction != null) ? LLVM.GetPersonalityFn(this) : default;
572+
return HasPersonalityFn ? LLVM.GetPersonalityFn(this) : default;
571573
}
572574

573575
set
Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,64 @@
11
// Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
22

33
using System;
4-
using System.Buffers;
4+
using System.Runtime.InteropServices;
55

66
namespace LLVMSharp.Interop;
77

88
public unsafe struct MarshaledArray<T, U> : IDisposable
9+
where U : unmanaged
910
{
1011
public MarshaledArray(ReadOnlySpan<T> inputs, Func<T, U> marshal)
1112
{
12-
if (inputs.IsEmpty)
13+
int length;
14+
U* value;
15+
16+
if (inputs.Length == 0)
1317
{
14-
Count = 0;
15-
Values = null;
18+
length = 0;
19+
value = null;
1620
}
1721
else
1822
{
19-
Count = inputs.Length;
20-
Values = ArrayPool<U>.Shared.Rent(Count);
23+
length = inputs.Length;
24+
25+
#if NET6_0_OR_GREATER
26+
value = (U*)NativeMemory.Alloc((uint)(length * sizeof(U)));
27+
#else
28+
value = (U*)Marshal.AllocHGlobal(length * sizeof(U));
29+
#endif
2130

22-
for (int i = 0; i < Count; i++)
31+
for (int i = 0; i < inputs.Length; i++)
2332
{
24-
Values[i] = marshal(inputs[i]);
33+
var input = inputs[i];
34+
value[i] = marshal(input);
2535
}
2636
}
37+
38+
Length = length;
39+
Value = value;
2740
}
2841

29-
public int Count { get; private set; }
42+
public ReadOnlySpan<U> AsSpan() => new ReadOnlySpan<U>(Value, Length);
3043

31-
public U[]? Values { get; private set; }
44+
public int Length { get; private set; }
3245

33-
public static implicit operator ReadOnlySpan<U>(in MarshaledArray<T, U> value) => value.Values;
46+
public U* Value { get; private set; }
47+
48+
public static implicit operator U*(MarshaledArray<T, U> value) => value.Value;
3449

3550
public void Dispose()
3651
{
37-
if (Values != null)
52+
if (Value != null)
3853
{
39-
ArrayPool<U>.Shared.Return(Values);
54+
#if NET6_0_OR_GREATER
55+
NativeMemory.Free(Value);
56+
#else
57+
Marshal.FreeHGlobal((IntPtr)Value);
58+
#endif
59+
60+
Value = null;
61+
Length = 0;
4062
}
4163
}
4264
}

sources/LLVMSharp.Interop/Internals/MarshaledString.cs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,62 @@ namespace LLVMSharp.Interop;
88

99
public unsafe struct MarshaledString : IDisposable
1010
{
11+
public MarshaledString(string? input) : this(input.AsSpan())
12+
{
13+
}
14+
1115
public MarshaledString(ReadOnlySpan<char> input)
1216
{
13-
if (input.IsEmpty)
14-
{
15-
var value = Marshal.AllocHGlobal(1);
16-
Marshal.WriteByte(value, 0, 0);
17+
int length = input.Length;
18+
sbyte* value;
1719

18-
Length = 0;
19-
Value = (sbyte*)value;
20+
if (length != 0)
21+
{
22+
length = Encoding.UTF8.GetMaxByteCount(input.Length);
2023
}
21-
else
24+
25+
#if NET6_0_OR_GREATER
26+
value = (sbyte*)NativeMemory.Alloc((uint)(length) + 1);
27+
#else
28+
value = (sbyte*)Marshal.AllocHGlobal(length + 1);
29+
#endif
30+
31+
if (length != 0)
2232
{
23-
var valueBytes = Encoding.UTF8.GetBytes(input.ToString());
24-
var length = valueBytes.Length;
25-
var value = Marshal.AllocHGlobal(length + 1);
26-
Marshal.Copy(valueBytes, 0, value, length);
27-
Marshal.WriteByte(value, length, 0);
28-
29-
Length = length;
30-
Value = (sbyte*)value;
33+
fixed (char* pInput = input)
34+
{
35+
length = Encoding.UTF8.GetBytes(pInput, input.Length, (byte*)value, length);
36+
}
3137
}
38+
value[length] = 0;
39+
40+
Length = length;
41+
Value = value;
3242
}
3343

44+
public ReadOnlySpan<byte> AsSpan() => new ReadOnlySpan<byte>(Value, Length);
45+
3446
public int Length { get; private set; }
3547

3648
public sbyte* Value { get; private set; }
3749

50+
public static implicit operator sbyte*(MarshaledString value) => value.Value;
51+
3852
public void Dispose()
3953
{
4054
if (Value != null)
4155
{
56+
#if NET6_0_OR_GREATER
57+
NativeMemory.Free(Value);
58+
#else
4259
Marshal.FreeHGlobal((IntPtr)Value);
60+
#endif
61+
4362
Value = null;
4463
Length = 0;
4564
}
4665
}
4766

48-
public static implicit operator sbyte*(in MarshaledString value) => value.Value;
49-
5067
public override string ToString()
5168
{
5269
var span = new ReadOnlySpan<byte>(Value, Length);

sources/LLVMSharp.Interop/Internals/MarshaledStringArray.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,49 @@
44

55
namespace LLVMSharp.Interop;
66

7-
public unsafe struct MarshaledStringArray : IDisposable
7+
public unsafe ref struct MarshaledStringArray
88
{
9+
private MarshaledString[]? _values;
10+
911
public MarshaledStringArray(ReadOnlySpan<string> inputs)
1012
{
11-
if (inputs.IsEmpty)
13+
if (inputs.Length == 0)
1214
{
13-
Count = 0;
14-
Values = null;
15+
_values = null;
1516
}
1617
else
1718
{
18-
Count = inputs.Length;
19-
Values = new MarshaledString[Count];
19+
_values = new MarshaledString[inputs.Length];
2020

21-
for (int i = 0; i < Count; i++)
21+
for (var i = 0; i < inputs.Length; i++)
2222
{
23-
Values[i] = new MarshaledString(inputs[i].AsSpan());
23+
_values[i] = new MarshaledString(inputs[i]);
2424
}
2525
}
2626
}
2727

28-
public int Count { get; private set; }
28+
public int Count => (_values is not null) ? _values.Length : 0;
2929

30-
public MarshaledString[]? Values { get; private set; }
30+
public ReadOnlySpan<MarshaledString> Values => _values;
3131

3232
public void Dispose()
3333
{
34-
if (Values is not null)
34+
if (_values != null)
3535
{
36-
for (int i = 0; i < Values.Length; i++)
36+
for (var i = 0; i < _values.Length; i++)
3737
{
38-
Values[i].Dispose();
38+
_values[i].Dispose();
3939
}
4040

41-
Values = null;
42-
Count = 0;
41+
_values = null;
4342
}
4443
}
4544

4645
public void Fill(sbyte** pDestination)
4746
{
48-
if (Values is not null)
47+
if (_values != null)
4948
{
50-
for (int i = 0; i < Count; i++)
49+
for (var i = 0; i < _values.Length; i++)
5150
{
5251
pDestination[i] = Values[i];
5352
}

sources/LLVMSharp.Interop/Internals/SpanExtensions.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
// Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
22

33
using System;
4+
using System.Runtime.InteropServices;
45
using System.Text;
56

67
namespace LLVMSharp.Interop;
78

89
public static unsafe class SpanExtensions
910
{
11+
public static string AsString(sbyte* pStr)
12+
{
13+
#if NET6_0_OR_GREATER
14+
var span = MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)(pStr));
15+
#else
16+
var span = new ReadOnlySpan<byte>(pStr, int.MaxValue);
17+
span = span.Slice(0, span.IndexOf((byte)'\0'));
18+
#endif
19+
return span.AsString();
20+
}
21+
1022
public static string AsString(this Span<byte> self) => AsString((ReadOnlySpan<byte>)self);
1123

1224
public static string AsString(this ReadOnlySpan<byte> self)
@@ -21,4 +33,30 @@ public static string AsString(this ReadOnlySpan<byte> self)
2133
return Encoding.UTF8.GetString(pSelf, self.Length);
2234
}
2335
}
36+
37+
public static string AsString(this ReadOnlySpan<ushort> self)
38+
{
39+
if (self.IsEmpty)
40+
{
41+
return string.Empty;
42+
}
43+
44+
fixed (ushort* pSelf = self)
45+
{
46+
return Encoding.Unicode.GetString((byte*)pSelf, self.Length * 2);
47+
}
48+
}
49+
50+
public static string AsString(this ReadOnlySpan<uint> self)
51+
{
52+
if (self.IsEmpty)
53+
{
54+
return string.Empty;
55+
}
56+
57+
fixed (uint* pSelf = self)
58+
{
59+
return Encoding.UTF32.GetString((byte*)pSelf, self.Length * 4);
60+
}
61+
}
2462
}

sources/LLVMSharp/IRBuilder.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public Value CreateAddrSpaceCast(Value v, Type destTy, ReadOnlySpan<char> name)
3232
public ReturnInst CreateAggregateRet(ReadOnlySpan<Value> retVals)
3333
{
3434
using var retValHandles = new MarshaledArray<Value, LLVMValueRef>(retVals, (value) => value.Handle);
35-
var handle = Handle.BuildAggregateRet(retValHandles);
35+
var handle = Handle.BuildAggregateRet(retValHandles.AsSpan());
3636
return Context.GetOrCreate<ReturnInst>(handle);
3737
}
3838

@@ -93,7 +93,7 @@ public BranchInst CreateBr(BasicBlock dest)
9393
public CallInst CreateCall(FunctionType fTy, Value callee, ReadOnlySpan<Value> args, ReadOnlySpan<char> name)
9494
{
9595
using var argHandles = new MarshaledArray<Value, LLVMValueRef>(args, (value) => value.Handle);
96-
var handle = Handle.BuildCall2(fTy.Handle, callee.Handle, argHandles, name);
96+
var handle = Handle.BuildCall2(fTy.Handle, callee.Handle, argHandles.AsSpan(), name);
9797
return Context.GetOrCreate<CallInst>(handle);
9898
}
9999

@@ -252,7 +252,7 @@ public Value CreateFSub(Value l, Value r, ReadOnlySpan<char> name)
252252
public Value CreateGEP(Type ty, Value ptr, ReadOnlySpan<Value> idxList, ReadOnlySpan<char> name)
253253
{
254254
using var idxListHandles = new MarshaledArray<Value, LLVMValueRef>(idxList, (value) => value.Handle);
255-
var handle = Handle.BuildGEP2(ty.Handle, ptr.Handle, idxListHandles, name);
255+
var handle = Handle.BuildGEP2(ty.Handle, ptr.Handle, idxListHandles.AsSpan(), name);
256256
return Context.GetOrCreate(handle);
257257
}
258258

@@ -277,7 +277,7 @@ public Value CreateICmp(CmpInst.Predicate p, Value lhs, Value rhs, ReadOnlySpan<
277277
public Value CreateInBoundsGEP(Type ty, Value ptr, ReadOnlySpan<Value> idxList, ReadOnlySpan<char> name)
278278
{
279279
using var idxListHandles = new MarshaledArray<Value, LLVMValueRef>(idxList, (value) => value.Handle);
280-
var handle = Handle.BuildInBoundsGEP2(ty.Handle, ptr.Handle, idxListHandles, name);
280+
var handle = Handle.BuildInBoundsGEP2(ty.Handle, ptr.Handle, idxListHandles.AsSpan(), name);
281281
return Context.GetOrCreate(handle);
282282
}
283283

@@ -324,7 +324,7 @@ public Value CreateIntToPtr(Value v, Type destTy, ReadOnlySpan<char> name)
324324
public InvokeInst CreateInvoke(FunctionType ty, Value callee, BasicBlock normalDest, BasicBlock unwindDest, ReadOnlySpan<Value> args, ReadOnlySpan<char> name)
325325
{
326326
using var argHandles = new MarshaledArray<Value, LLVMValueRef>(args, (value) => value.Handle);
327-
var handle = Handle.BuildInvoke2(ty.Handle, callee.Handle, argHandles, normalDest.Handle, unwindDest.Handle, name);
327+
var handle = Handle.BuildInvoke2(ty.Handle, callee.Handle, argHandles.AsSpan(), normalDest.Handle, unwindDest.Handle, name);
328328
return Context.GetOrCreate<InvokeInst>(handle);
329329
}
330330

sources/LLVMSharp/Values/Users/Constants/ConstantAggregates/ConstantStruct.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal ConstantStruct(LLVMValueRef handle) : base(handle.IsAConstantStruct, LL
1616
public static Constant GetAnon(LLVMContext ctx, ReadOnlySpan<Constant> v, bool packed)
1717
{
1818
using var marshaledV = new MarshaledArray<Constant, LLVMValueRef>(v, (value) => value.Handle);
19-
var handle = ctx.Handle.GetConstStruct(marshaledV, packed);
19+
var handle = ctx.Handle.GetConstStruct(marshaledV.AsSpan(), packed);
2020
return ctx.GetOrCreate<Constant>(handle);
2121
}
2222
}

tests/LLVMSharp.UnitTests/Examples.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public void Intro()
1616
{
1717
using var module = LLVMModuleRef.CreateWithName("LLVMSharpIntro");
1818

19-
var def = module.AddFunction(
19+
(_, var def) = module.AddFunction(
2020
LLVMTypeRef.Int32, "sum", new[] { LLVMTypeRef.Int32, LLVMTypeRef.Int32 }, (f, b) =>
2121
{
2222
var p1 = f.Params[0];

0 commit comments

Comments
 (0)