diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs index de79dd67f..98f862c54 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs @@ -9,7 +9,6 @@ using ILCompiler.Compiler.CppCodeGen; using Internal.TypeSystem; using LLVMSharp; using ILCompiler.CodeGen; -using System.Collections.Generic; namespace Internal.IL { @@ -87,7 +86,7 @@ namespace Internal.IL /// Position where to insert public void InsertAt(T v, int pos) { - Debug.Assert(pos <= _top, "Invalid insertion point"); + Debug.Assert(pos < _top, "Invalid insertion point"); if (_top >= _stack.Length) { @@ -167,20 +166,6 @@ namespace Internal.IL } } - class LLVMTypeRefEqualityComparer : IEqualityComparer - { - public static LLVMTypeRefEqualityComparer Instance = new LLVMTypeRefEqualityComparer(); - public bool Equals(LLVMTypeRef x, LLVMTypeRef y) - { - return x.Pointer.Equals(y.Pointer); - } - - public int GetHashCode(LLVMTypeRef obj) - { - return obj.Pointer.GetHashCode(); - } - } - /// /// Abstract representation of a stack entry /// @@ -196,53 +181,18 @@ namespace Internal.IL /// public TypeDesc Type { get; } - Dictionary _castValues = new Dictionary(LLVMTypeRefEqualityComparer.Instance); - - public LLVMValueRef ValueAsType(LLVMTypeRef type, LLVMBuilderRef builder) - { - return ValueAsTypeInternal(type, builder, false); - } - - public LLVMValueRef ValueAsType(TypeDesc type, LLVMBuilderRef builder) - { - return ValueAsType(ILImporter.GetLLVMTypeForTypeDesc(type), builder); - } - - public LLVMValueRef ValueForStackKind(StackValueKind kind, LLVMBuilderRef builder, bool signExtend) - { - if (kind == StackValueKind.Int32) - return ValueAsInt32(builder, signExtend); - else if (kind == StackValueKind.Int64) - return ValueAsInt64(builder, signExtend); - else if (kind == StackValueKind.Float) - return ValueAsType(LLVM.FloatType(), builder); - else if (kind == StackValueKind.NativeInt || kind == StackValueKind.ByRef || kind == StackValueKind.ObjRef) - return ValueAsInt32(builder, false); - else - throw new NotImplementedException(); - } - - public LLVMValueRef ValueAsInt32(LLVMBuilderRef builder, bool signExtend) - { - return ValueAsTypeInternal(LLVM.Int32Type(), builder, signExtend); - } - - public LLVMValueRef ValueAsInt64(LLVMBuilderRef builder, bool signExtend) - { - return ValueAsTypeInternal(LLVM.Int32Type(), builder, signExtend); - } - - protected abstract LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend); + public LLVMValueRef LLVMValue { get; set; } /// /// Initializes a new instance of StackEntry. /// /// Kind of entry. /// Type if any of entry. - protected StackEntry(StackValueKind kind, TypeDesc type = null) + protected StackEntry(StackValueKind kind, LLVMValueRef llvmValue, TypeDesc type = null) { Kind = kind; Type = type; + LLVMValue = llvmValue; } /// @@ -256,6 +206,45 @@ namespace Internal.IL /// /// A new instance of the same type as the current entry. public abstract StackEntry Duplicate(); + + /// + /// Overridden and sealed to force descendants to override . + /// + /// String representation of current entry + public override sealed string ToString() + { + StringBuilder s = new StringBuilder(); + BuildRepresentation(s); + return s.ToString(); + } + + /// + /// Build a representation of current entry in . + /// + /// StringBuilder where representation will be saved. + protected virtual void BuildRepresentation(StringBuilder s) + { + Debug.Assert(s != null, "StringBuilder is null."); + if (Type != null) + { + s.Append(Type); + if (Kind != StackValueKind.Unknown) + { + s.Append('('); + s.Append(Kind); + s.Append(')'); + } + } + else if (Kind != StackValueKind.Unknown) + { + if (Kind != StackValueKind.Unknown) + { + s.Append('('); + s.Append(Kind); + s.Append(')'); + } + } + } } /// @@ -263,7 +252,7 @@ namespace Internal.IL /// internal abstract class ConstantEntry : StackEntry { - protected ConstantEntry(StackValueKind kind, TypeDesc type = null) : base(kind, type) + protected ConstantEntry(StackValueKind kind, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, llvmValue, type) { } @@ -282,38 +271,28 @@ namespace Internal.IL { public T Value { get; } - protected ConstantEntry(StackValueKind kind, T value, TypeDesc type = null) : base(kind, type) + protected ConstantEntry(StackValueKind kind, T value, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, llvmValue, type) { Value = value; } + + protected override void BuildRepresentation(StringBuilder s) + { + base.BuildRepresentation(s); + if (s.Length > 0) + { + s.Append(' '); + } + s.Append(Value); + } } internal class Int32ConstantEntry : ConstantEntry { - public Int32ConstantEntry(int value, TypeDesc type = null) : base(StackValueKind.Int32, value, type) + public Int32ConstantEntry(int value, TypeDesc type = null) : base(StackValueKind.Int32, value, LLVM.ConstInt(LLVM.Int32Type(), (ulong)value, LLVMMisc.False), type) { } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - if (type.TypeKind == LLVMTypeKind.LLVMPointerTypeKind && Value == 0) - { - return LLVM.ConstPointerNull(type); - } - else if (type.TypeKind == LLVMTypeKind.LLVMPointerTypeKind && Value != 0) - { - return LLVM.ConstIntToPtr(LLVM.ConstInt(LLVM.Int32Type(), (ulong)Value, LLVMMisc.False), type); - } - else if (type.TypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - { - throw new NotImplementedException(); - } - else - { - return LLVM.ConstInt(type, (ulong)Value, LLVMMisc.False); - } - } - public override StackEntry Duplicate() { return new Int32ConstantEntry(Value, Type); @@ -345,7 +324,7 @@ namespace Internal.IL internal class Int64ConstantEntry : ConstantEntry { - public Int64ConstantEntry(long value, TypeDesc type = null) : base(StackValueKind.Int64, value, type) + public Int64ConstantEntry(long value, TypeDesc type = null) : base(StackValueKind.Int64, value, LLVM.ConstInt(LLVM.Int64Type(), (ulong)value, LLVMMisc.False), type) { } @@ -354,26 +333,6 @@ namespace Internal.IL return new Int64ConstantEntry(Value, Type); } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - if (type.TypeKind == LLVMTypeKind.LLVMPointerTypeKind && Value == 0) - { - return LLVM.ConstPointerNull(type); - } - else if (type.TypeKind == LLVMTypeKind.LLVMPointerTypeKind && Value != 0) - { - return LLVM.ConstIntToPtr(LLVM.ConstInt(LLVM.Int64Type(), (ulong)Value, LLVMMisc.False), type); - } - else if (type.TypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - { - throw new NotImplementedException(); - } - else - { - return LLVM.ConstInt(type, (ulong)Value, LLVMMisc.False); - } - } - public override bool IsCastNecessary(TypeDesc destType) { switch (destType.UnderlyingType.Category) @@ -404,15 +363,10 @@ namespace Internal.IL internal class FloatConstantEntry : ConstantEntry { - public FloatConstantEntry(double value, TypeDesc type = null) : base(StackValueKind.Float, value, type) + public FloatConstantEntry(double value, TypeDesc type = null) : base(StackValueKind.Float, value, LLVM.ConstReal(LLVM.FloatType(), value), type) { } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - return LLVM.ConstReal(type, Value); - } - public override StackEntry Duplicate() { return new FloatConstantEntry(Value, Type); @@ -428,77 +382,34 @@ namespace Internal.IL /// String representation of current expression /// public string Name { get; set; } - public LLVMValueRef RawLLVMValue { get; set; } + /// /// Initializes new instance of ExpressionEntry /// /// Kind of entry /// String representation of entry /// Type if any of entry - public ExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, type) + public ExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, llvmValue, type) { Name = name; - RawLLVMValue = llvmValue; } public override StackEntry Duplicate() { - return new ExpressionEntry(Kind, Name, RawLLVMValue, Type); + return new ExpressionEntry(Kind, Name, LLVMValue, Type); } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) + protected override void BuildRepresentation(StringBuilder s) { - //TODO: deal with sign extension here - return ILImporter.CastIfNecessary(builder, RawLLVMValue, type); + base.BuildRepresentation(s); + if (s.Length > 0) + { + s.Append(' '); + } + s.Append(Name); } } - - internal class LoadExpressionEntry : ExpressionEntry - { - /// - /// Initializes new instance of ExpressionEntry - /// - /// Kind of entry - /// String representation of entry - /// Type if any of entry - public LoadExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type) - { - } - - public override StackEntry Duplicate() - { - return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type); - } - - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - return ILImporter.LoadValue(builder, RawLLVMValue, Type, type, signExtend); - } - } - - internal class AddressExpressionEntry : ExpressionEntry - { - /// - /// Initializes new instance of ExpressionEntry - /// - /// Kind of entry - /// String representation of entry - /// Type if any of entry - public AddressExpressionEntry(StackValueKind kind, string name, LLVMValueRef llvmValue, TypeDesc type = null) : base(kind, name, llvmValue, type) - { - } - - public override StackEntry Duplicate() - { - return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type); - } - - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - return ILImporter.CastIfNecessary(builder, RawLLVMValue, type); - } - } - + /// /// Entry representing some token (either of TypeDesc, MethodDesc or FieldDesc) along with its string representation /// @@ -506,19 +417,21 @@ namespace Internal.IL { public T LdToken { get; } - public LdTokenEntry(StackValueKind kind, string name, T token, TypeDesc type = null) : base(kind, name, default(LLVMValueRef), type) + public LdTokenEntry(StackValueKind kind, string name, T token, LLVMValueRef value, TypeDesc type = null) : base(kind, name, value, type) { LdToken = token; } public override StackEntry Duplicate() { - return new LdTokenEntry(Kind, Name, LdToken, Type); + return new LdTokenEntry(Kind, Name, LdToken, LLVMValue, Type); } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) + protected override void BuildRepresentation(StringBuilder s) { - return ILImporter.CastIfNecessary(builder, RawLLVMValue, type); + base.BuildRepresentation(s); + s.Append(' '); + s.Append(LdToken); } } @@ -529,7 +442,7 @@ namespace Internal.IL /// public static InvalidEntry Entry = new InvalidEntry(); - protected InvalidEntry() : base(StackValueKind.Unknown, null) + protected InvalidEntry() : base(StackValueKind.Unknown, default(LLVMValueRef), null) { } @@ -538,33 +451,9 @@ namespace Internal.IL return this; } - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) + protected override void BuildRepresentation(StringBuilder s) { - throw new InvalidOperationException(); - } - } - - /// - /// Entry representing a writable sharable stack entry that can survive from one basic block to another - /// - internal class SpilledExpressionEntry : ExpressionEntry - { - public int LocalIndex; - private ILImporter _importer; - public SpilledExpressionEntry(StackValueKind kind, string name, TypeDesc type, int localIndex, ILImporter importer) : base(kind, name, new LLVMValueRef(IntPtr.Zero), type) - { - LocalIndex = localIndex; - _importer = importer; - } - - protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend) - { - return _importer.LoadTemp(LocalIndex, type); - } - - public override StackEntry Duplicate() - { - return new SpilledExpressionEntry(Kind, Name, Type, LocalIndex, _importer); + s.Append("Invalid Entry"); } } } diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs index c41d66da7..8c7886288 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs @@ -19,13 +19,6 @@ namespace Internal.IL // backend before the actual compilation happens to gain insights into the code. partial class ILImporter { - public enum LocalVarKind - { - Argument, - Local, - Temp - } - ArrayBuilder _dependencies = new ArrayBuilder(); public IEnumerable GetDependencies() { @@ -42,7 +35,6 @@ namespace Internal.IL private LLVMBasicBlockRef _curBasicBlock; private LLVMBuilderRef _builder; private readonly LocalVariableDefinition[] _locals; - private List _spilledExpressions = new List(); private readonly byte[] _ilBytes; @@ -162,30 +154,6 @@ namespace Internal.IL return llvmFunction; } - private LLVMValueRef GetOrCreateLLVMFunction(string mangledName, LLVMTypeRef functionType) - { - LLVMValueRef llvmFunction = LLVM.GetNamedFunction(Module, mangledName); - - if (llvmFunction.Pointer == IntPtr.Zero) - { - return LLVM.AddFunction(Module, mangledName, functionType); - } - return llvmFunction; - } - - private void ImportCallMemset(LLVMValueRef targetPointer, byte value, int length) - { - LLVMValueRef objectSizeValue = BuildConstInt32(length); - var memsetSignature = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[] { LLVM.PointerType(LLVM.Int8Type(), 0), LLVM.Int8Type(), LLVM.Int32Type(), LLVM.Int32Type(), LLVM.Int1Type() }, false); - LLVM.BuildCall(_builder, GetOrCreateLLVMFunction("llvm.memset.p0i8.i32", memsetSignature), new LLVMValueRef[] { targetPointer, BuildConstInt8(value), objectSizeValue, BuildConstInt32(1), BuildConstInt1(0) }, String.Empty); - } - - private void PushLoadExpression(StackValueKind kind, string name, LLVMValueRef rawLLVMValue, TypeDesc type) - { - Debug.Assert(kind != StackValueKind.Unknown, "Unknown stack kind"); - _stack.Push(new LoadExpressionEntry(kind, name, rawLLVMValue, type)); - } - /// /// Push an expression named of kind . /// @@ -226,6 +194,45 @@ namespace Internal.IL _stack.Push(new ExpressionEntry(kind, name, llvmValue, type)); } + + + /// + /// Generate a cast in case the stack type of source is not identical or compatible with destination type. + /// + /// Type of destination + /// Source entry from stack + private void AppendCastIfNecessary(TypeDesc destType, StackEntry srcEntry) + { + ConstantEntry constant = srcEntry as ConstantEntry; + if ((constant != null) && (constant.IsCastNecessary(destType)) || !destType.IsValueType || destType != srcEntry.Type) + { + throw new NotImplementedException(); + /* + Append("("); + Append(GetSignatureTypeNameAndAddReference(destType)); + Append(")");*/ + } + } + + private void AppendCastIfNecessary(StackValueKind dstType, TypeDesc srcType) + { + if (dstType == StackValueKind.ByRef) + { + + throw new NotImplementedException(); + /* + Append("("); + Append(GetSignatureTypeNameAndAddReference(srcType)); + Append(")");*/ + } + else + if (srcType.IsPointer) + { + throw new NotImplementedException(); + //Append("(intptr_t)"); + } + } + private void MarkInstructionBoundary() { @@ -274,8 +281,6 @@ namespace Internal.IL var terminator = basicBlock.Block.GetBasicBlockTerminator(); if (terminator.Pointer == IntPtr.Zero) { - if (_basicBlocks[_currentOffset].StartOffset == 0) - throw new InvalidProgramException(); LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(_basicBlocks[_currentOffset])); } } @@ -298,73 +303,14 @@ namespace Internal.IL } private void ImportLoadVar(int index, bool argument) - { - LLVMValueRef typedLoadLocation = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out TypeDesc type); - PushLoadExpression(GetStackValueKind(type), "ld" + (argument ? "arg" : "loc") + index + "_", typedLoadLocation, type); - } - - private LLVMValueRef LoadTemp(int index) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - return LLVM.BuildLoad(_builder, CastToPointerToTypeDesc(address, type), "ldtemp"); - } - - internal LLVMValueRef LoadTemp(int index, LLVMTypeRef asType) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - return LLVM.BuildLoad(_builder, CastIfNecessary(address, LLVM.PointerType(asType, 0)), "ldtemp"); - } - - private void StoreTemp(int index, LLVMValueRef value) - { - LLVMValueRef address = LoadVarAddress(index, LocalVarKind.Temp, out TypeDesc type); - LLVM.BuildStore(_builder, CastToTypeDesc(value, type), CastToPointerToTypeDesc(address, type)); - } - - internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend) - { - if (targetType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind && sourceType.IsPrimitive && !sourceType.IsPointer) - { - var sourceLLVMType = ILImporter.GetLLVMTypeForTypeDesc(sourceType); - var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(sourceLLVMType, 0)); - return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, "ldvalue"), targetType, signExtend); - } - else - { - var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(targetType, 0)); - return LLVM.BuildLoad(builder, typedAddress, "ldvalue"); - } - } - - private static LLVMValueRef CastIntValue(LLVMBuilderRef builder, LLVMValueRef value, LLVMTypeRef type, bool signExtend) - { - if (LLVM.TypeOf(value).Pointer == type.Pointer) - { - return value; - } - else if (signExtend && type.GetIntTypeWidth() > LLVM.TypeOf(value).GetIntTypeWidth()) - { - return LLVM.BuildSExtOrBitCast(builder, value, type, "SExtOrBitCast"); - } - else if (LLVM.TypeOf(value).TypeKind == LLVMTypeKind.LLVMPointerTypeKind) - { - return LLVM.BuildPtrToInt(builder, value, type, "intcast"); - } - else - { - Debug.Assert(LLVM.TypeOf(value).TypeKind == LLVMTypeKind.LLVMIntegerTypeKind); - return LLVM.BuildIntCast(builder, value, type, "intcast"); - } - } - - private LLVMValueRef LoadVarAddress(int index, LocalVarKind kind, out TypeDesc type) { int varBase; int varCountBase; int varOffset; LLVMTypeRef valueType; + TypeDesc type; - if (kind == LocalVarKind.Argument) + if (argument) { varCountBase = 0; varBase = 0; @@ -389,25 +335,21 @@ namespace Internal.IL } valueType = GetLLVMTypeForTypeDesc(type); } - else if (kind == LocalVarKind.Local) + else { varBase = GetTotalParameterOffset(); GetLocalSizeAndOffsetAtIndex(index, out int localSize, out varOffset); valueType = GetLLVMTypeForTypeDesc(_locals[index].Type); type = _locals[index].Type; } - else - { - varBase = GetTotalRealLocalOffset(); - GetSpillSizeAndOffsetAtIndex(index, out int localSize, out varOffset); - valueType = GetLLVMTypeForTypeDesc(_spilledExpressions[index].Type); - type = _spilledExpressions[index].Type; - } - return LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), + var loadLocation = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)(varBase + varOffset), LLVMMisc.False) }, String.Empty); + var typedLoadLocation = LLVM.BuildPointerCast(_builder, loadLocation, LLVM.PointerType(valueType, 0), "typedLoadLocation"); + var loadResult = LLVM.BuildLoad(_builder, typedLoadLocation, "ld" + (argument ? "arg" : "loc") + index + "_"); + PushExpression(GetStackValueKind(type), String.Empty, loadResult, type); } private StackValueKind GetStackValueKind(TypeDesc type) @@ -453,16 +395,24 @@ namespace Internal.IL private void ImportStoreVar(int index, bool argument) { - TypeDesc varType; - StackEntry toStore = _stack.Pop(); - LLVMValueRef varAddress = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out varType); - CastingStore(varAddress, toStore, varType); + if(argument) + { + throw new NotImplementedException("storing to argument"); + } + + GetLocalSizeAndOffsetAtIndex(index, out int localSize, out int localOffset); + + LLVMValueRef toStore = _stack.Pop().LLVMValue; + + LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_locals[index].Type); + + ImportStoreHelper(toStore, valueType, LLVM.GetFirstParam(_llvmFunction), (uint)(GetTotalParameterOffset() + localOffset)); } private void ImportStoreHelper(LLVMValueRef toStore, LLVMTypeRef valueType, LLVMValueRef basePtr, uint offset) { LLVMValueRef typedToStore = CastIfNecessary(toStore, valueType); - + var storeLocation = LLVM.BuildGEP(_builder, basePtr, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), offset, LLVMMisc.False) }, String.Empty); @@ -470,33 +420,7 @@ namespace Internal.IL LLVM.BuildStore(_builder, typedToStore, typedStoreLocation); } - private LLVMValueRef CastToRawPointer(LLVMValueRef source) - { - return CastIfNecessary(source, LLVM.PointerType(LLVM.Int8Type(), 0)); - } - - private LLVMValueRef CastToTypeDesc(LLVMValueRef source, TypeDesc type) - { - return CastIfNecessary(source, GetLLVMTypeForTypeDesc(type)); - } - - private LLVMValueRef CastToPointerToTypeDesc(LLVMValueRef source, TypeDesc type) - { - return CastIfNecessary(source, LLVM.PointerType(GetLLVMTypeForTypeDesc(type), 0)); - } - - private void CastingStore(LLVMValueRef address, StackEntry value, TypeDesc targetType) - { - var typedStoreLocation = CastToPointerToTypeDesc(address, targetType); - LLVM.BuildStore(_builder, value.ValueAsType(targetType, _builder), typedStoreLocation); - } - private LLVMValueRef CastIfNecessary(LLVMValueRef source, LLVMTypeRef valueType) - { - return CastIfNecessary(_builder, source, valueType); - } - - internal static LLVMValueRef CastIfNecessary(LLVMBuilderRef builder, LLVMValueRef source, LLVMTypeRef valueType) { LLVMTypeRef sourceType = LLVM.TypeOf(source); if (sourceType.Pointer == valueType.Pointer) @@ -508,19 +432,11 @@ namespace Internal.IL LLVMValueRef typedToStore = source; if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) { - typedToStore = LLVM.BuildPointerCast(builder, source, valueType, "CastIfNecessaryPtr"); + typedToStore = LLVM.BuildPointerCast(_builder, source, valueType, "CastIfNecessaryPtr"); } else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMIntegerTypeKind) { - typedToStore = LLVM.BuildPtrToInt(builder, source, valueType, "CastIfNecessaryInt"); - } - else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMArrayTypeKind) - { - typedToStore = LLVM.BuildLoad(builder, CastIfNecessary(builder, source, LLVM.PointerType(valueType, 0)), "CastIfNecessaryArrayLoad"); - } - else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind == LLVMTypeKind.LLVMArrayTypeKind) - { - typedToStore = LLVM.BuildLoad(builder, CastIfNecessary(builder, source, LLVM.PointerType(valueType, 0)), "CastIfNecessaryArrayLoad"); + typedToStore = LLVM.BuildPtrToInt(_builder, source, valueType, "CastIfNecessaryInt"); } else if (toStoreKind == LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind != LLVMTypeKind.LLVMIntegerTypeKind) { @@ -528,7 +444,7 @@ namespace Internal.IL } else if (toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) { - typedToStore = LLVM.BuildIntToPtr(builder, source, valueType, "CastIfNecessaryPtr"); + typedToStore = LLVM.BuildIntToPtr(_builder, source, valueType, "CastIfNecessaryPtr"); } else if (toStoreKind != LLVMTypeKind.LLVMIntegerTypeKind && valueTypeKind == LLVMTypeKind.LLVMPointerTypeKind) { @@ -541,21 +457,13 @@ namespace Internal.IL else if (toStoreKind == valueTypeKind && toStoreKind == LLVMTypeKind.LLVMIntegerTypeKind) { Debug.Assert(toStoreKind != LLVMTypeKind.LLVMPointerTypeKind && valueTypeKind != LLVMTypeKind.LLVMPointerTypeKind); - typedToStore = LLVM.BuildIntCast(builder, source, valueType, "CastIfNecessaryInt"); - } - else if (toStoreKind == LLVMTypeKind.LLVMFloatTypeKind && valueTypeKind != LLVMTypeKind.LLVMFloatTypeKind) - { - typedToStore = LLVM.BuildIntCast(builder, source, valueType, "CastIfNecessaryFloat"); - } - else if (toStoreKind != LLVMTypeKind.LLVMFloatTypeKind && valueTypeKind == LLVMTypeKind.LLVMFloatTypeKind) - { - typedToStore = LLVM.BuildFPCast(builder, source, valueType, "CastIfNecessaryFloat"); + typedToStore = LLVM.BuildIntCast(_builder, source, valueType, "CastIfNecessaryInt"); } return typedToStore; } - internal static LLVMTypeRef GetLLVMTypeForTypeDesc(TypeDesc type) + private LLVMTypeRef GetLLVMTypeForTypeDesc(TypeDesc type) { switch (type.Category) { @@ -573,9 +481,9 @@ namespace Internal.IL case TypeFlags.Int32: case TypeFlags.UInt32: - return LLVM.Int32Type(); case TypeFlags.IntPtr: case TypeFlags.UIntPtr: + return LLVM.Int32Type(); case TypeFlags.Array: case TypeFlags.SzArray: case TypeFlags.ByRef: @@ -584,7 +492,7 @@ namespace Internal.IL return LLVM.PointerType(LLVM.Int8Type(), 0); case TypeFlags.Pointer: - return LLVM.PointerType(type.GetParameterType().IsVoid ? LLVM.Int8Type() : GetLLVMTypeForTypeDesc(type.GetParameterType()), 0); + return LLVM.PointerType(GetLLVMTypeForTypeDesc(type.GetParameterType()), 0); case TypeFlags.Int64: case TypeFlags.UInt64: @@ -612,16 +520,6 @@ namespace Internal.IL } private int GetTotalLocalOffset() - { - int offset = GetTotalRealLocalOffset(); - for (int i = 0; i < _spilledExpressions.Count; i++) - { - offset += _spilledExpressions[i].Type.GetElementSize().AsInt; - } - return offset; - } - - private int GetTotalRealLocalOffset() { int offset = 0; for (int i = 0; i < _locals.Length; i++) @@ -694,23 +592,22 @@ namespace Internal.IL } } - private void GetSpillSizeAndOffsetAtIndex(int index, out int size, out int offset) - { - SpilledExpressionEntry spill = _spilledExpressions[index]; - size = spill.Type.GetElementSize().AsInt; - - offset = 0; - for (int i = 0; i < index; i++) - { - offset += _spilledExpressions[i].Type.GetElementSize().AsInt; - } - } - private void ImportAddressOfVar(int index, bool argument) { - TypeDesc type; - LLVMValueRef typedLoadLocation = LoadVarAddress(index, argument ? LocalVarKind.Argument : LocalVarKind.Local, out type); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldloca", typedLoadLocation, type.MakePointerType())); + if (argument) + { + throw new NotImplementedException("ldarga"); + } + + int localOffset = GetTotalParameterOffset(); + GetLocalSizeAndOffsetAtIndex(index, out int size, out int offset); + localOffset += offset; + + var localPtr = LLVM.BuildGEP(_builder, LLVM.GetFirstParam(_llvmFunction), + new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (uint)localOffset, LLVMMisc.False) }, "ldloca"); + //var typedLocalPtr = LLVM.BuildPointerCast(_builder, localPtr, GetLLVMTypeForTypeDesc(_locals[index].Type.MakePointerType()), "ldloca"); + + _stack.Push(new ExpressionEntry(StackValueKind.ByRef, "ldloca", localPtr, _locals[index].Type.MakePointerType())); } private void ImportDup() @@ -743,7 +640,8 @@ namespace Internal.IL { StackEntry retVal = _stack.Pop(); LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType); - ImportStoreHelper(retVal.ValueAsType(valueType, _builder), valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0); + + ImportStoreHelper(retVal.LLVMValue, valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0); } LLVM.BuildRetVoid(_builder); @@ -752,6 +650,7 @@ namespace Internal.IL private void ImportCall(ILOpcode opcode, int token) { MethodDesc callee = (MethodDesc)_methodIL.GetObject(token); + if (callee.IsIntrinsic) { if (ImportIntrinsicCall(callee)) @@ -766,29 +665,8 @@ namespace Internal.IL return; } - if (opcode == ILOpcode.newobj) - { - if (callee.OwningType.IsString) - { - // String constructors actually look like regular method calls - IMethodNode node = _compilation.NodeFactory.StringAllocator(callee); - _dependencies.Add(node); - callee = node.Method; - opcode = ILOpcode.call; - } - else - { - StackEntry newObjResult = AllocateObject(callee.OwningType); - //one for the real result and one to be consumed by ctor - if (callee.Signature.Length > _stack.Length) //System.Reflection.MemberFilter.ctor - throw new InvalidProgramException(); - _stack.InsertAt(newObjResult, _stack.Top - callee.Signature.Length); - _stack.InsertAt(newObjResult, _stack.Top - callee.Signature.Length); - } - } - // we don't really have virtual call support, but we'll treat it as direct for now - if (opcode != ILOpcode.call && opcode != ILOpcode.callvirt && opcode != ILOpcode.newobj) + if (opcode != ILOpcode.call && opcode != ILOpcode.callvirt) { throw new NotImplementedException(); } @@ -800,45 +678,6 @@ namespace Internal.IL HandleCall(callee); } - private ExpressionEntry AllocateObject(TypeDesc type) - { - MetadataType metadataType = (MetadataType)type; - int objectSize = metadataType.InstanceByteCount.AsInt; - LLVMValueRef allocatedMemory = LLVM.BuildMalloc(_builder, LLVM.ArrayType(LLVM.Int8Type(), (uint)objectSize), "newobj"); - LLVMValueRef castMemory = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.Int8Type(), 0), "castnewobj"); - ImportCallMemset(castMemory, 0, objectSize); - LLVMValueRef eeTypePointer = GetEETypeForTypeDesc(type); - LLVMValueRef objectHeaderPtr = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.TypeOf(eeTypePointer), 0), "objectHeaderPtr"); - LLVM.BuildStore(_builder, eeTypePointer, objectHeaderPtr); - return new ExpressionEntry(StackValueKind.ObjRef, "newobj", castMemory, type); - } - - private static LLVMValueRef BuildConstInt1(int number) - { - Debug.Assert(number == 0 || number == 1, "Non-boolean int1"); - return LLVM.ConstInt(LLVM.Int1Type(), (ulong)number, LLVMMisc.False); - } - - private static LLVMValueRef BuildConstInt8(byte number) - { - return LLVM.ConstInt(LLVM.Int8Type(), number, LLVMMisc.False); - } - - private static LLVMValueRef BuildConstInt32(int number) - { - return LLVM.ConstInt(LLVM.Int32Type(), (ulong)number, LLVMMisc.False); - } - - private LLVMValueRef GetEETypeForTypeDesc(TypeDesc target) - { - ISymbolNode node = _compilation.NodeFactory.ConstructedTypeSymbol(target); - LLVMValueRef eeTypePointer = LoadAddressOfSymbolNode(node); - _dependencies.Add(node); - var eeTypePtrType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr"); - var ptrPtrType = LLVM.PointerType(GetLLVMTypeForTypeDesc(eeTypePtrType), 0); - return LLVM.BuildPointerCast(_builder, eeTypePointer, ptrPtrType, "castEETypePtr"); - } - /// /// Implements intrinsic methods instread of calling them /// @@ -896,16 +735,16 @@ namespace Internal.IL } // The last argument is the top of the stack. We need to reverse them and store starting at the first argument - StackEntry[] argumentValues = new StackEntry[callee.Signature.Length + instanceAdjustment]; + LLVMValueRef[] argumentValues = new LLVMValueRef[callee.Signature.Length + instanceAdjustment]; for(int i = 0; i < argumentValues.Length; i++) { - argumentValues[argumentValues.Length - i - 1] = _stack.Pop(); + argumentValues[argumentValues.Length - i - 1] = _stack.Pop().LLVMValue; } for (int index = 0; index < argumentValues.Length; index++) { - StackEntry toStore = argumentValues[index]; + LLVMValueRef toStore = argumentValues[index]; TypeDesc argType; if (index == 0 && !callee.Signature.IsStatic) @@ -919,7 +758,7 @@ namespace Internal.IL LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType); - ImportStoreHelper(toStore.ValueAsType(valueType, _builder), valueType, castShadowStack, argOffset); + ImportStoreHelper(toStore, valueType, castShadowStack, argOffset); argOffset += (uint)argType.GetElementSize().AsInt; } @@ -933,7 +772,8 @@ namespace Internal.IL { LLVMTypeRef returnLLVMType = GetLLVMTypeForTypeDesc(callee.Signature.ReturnType); LLVMValueRef returnLLVMPointer = LLVM.BuildPointerCast(_builder, returnAddress, LLVM.PointerType(returnLLVMType, 0), "castreturnpointer"); - PushLoadExpression(GetStackValueKind(callee.Signature.ReturnType), String.Empty, returnLLVMPointer, callee.Signature.ReturnType); + LLVMValueRef loadResult = LLVM.BuildLoad(_builder, returnLLVMPointer, String.Empty); + PushExpression(GetStackValueKind(callee.Signature.ReturnType), String.Empty, loadResult, callee.Signature.ReturnType); } } @@ -946,11 +786,6 @@ namespace Internal.IL { LLVMValueRef nativeFunc = LLVM.GetNamedFunction(Module, method.Name); - //emscripten dies if this is output because its expected to have i32, i32, i64. But the runtime has defined it as i8*, i8*, i64 - if (method.Name == "memmove") - throw new NotImplementedException(); - - // Create an import if we haven't already if (nativeFunc.Pointer == IntPtr.Zero) { @@ -971,17 +806,24 @@ namespace Internal.IL LLVMValueRef[] arguments = new LLVMValueRef[method.Signature.Length]; for(int i = 0; i < arguments.Length; i++) { + LLVMValueRef argValue = _stack.Pop().LLVMValue; + // Arguments are reversed on the stack // Coerce pointers to the native type TypeDesc signatureType = method.Signature[arguments.Length - i - 1]; - arguments[arguments.Length - i - 1] = _stack.Pop().ValueAsType(GetLLVMTypeForTypeDesc(signatureType), _builder); + LLVMValueRef typedValue = argValue; + if (signatureType.IsPointer) + { + LLVMTypeRef signatureLlvmType = GetLLVMTypeForTypeDesc(signatureType); + typedValue = LLVM.BuildPointerCast(_builder, argValue, signatureLlvmType, "castarg"); + } + arguments[arguments.Length - i - 1] = typedValue; } - //dont name the return value if the function returns void, its invalid - var returnValue = LLVM.BuildCall(_builder, nativeFunc, arguments, !method.Signature.ReturnType.IsVoid ? "call" : string.Empty); + var returnValue = LLVM.BuildCall(_builder, nativeFunc, arguments, "call"); if(!method.Signature.ReturnType.IsVoid) - PushExpression(GetStackValueKind(method.Signature.ReturnType), "retval", returnValue, method.Signature.ReturnType); + PushExpression(GetStackValueKind(method.Signature.ReturnType), String.Empty, returnValue, method.Signature.ReturnType); } private void ImportCalli(int token) @@ -1020,10 +862,6 @@ namespace Internal.IL { if (opcode == ILOpcode.br) { - ImportFallthrough(target); - //TODO: why does this illegal branch happen in System.Reflection.MemberFilter.ctor - if (target.StartOffset == 0) - throw new InvalidProgramException(); LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(target)); } else @@ -1033,10 +871,11 @@ namespace Internal.IL if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue) { var op = _stack.Pop(); - LLVMValueRef value = op.ValueAsInt32(_builder, false); - - if (LLVM.TypeOf(value).TypeKind != LLVMTypeKind.LLVMIntegerTypeKind) - throw new InvalidProgramException("branch on non integer"); + LLVMValueRef value = op.LLVMValue; + if (LLVM.GetTypeKind(LLVM.TypeOf(value)) == LLVMTypeKind.LLVMPointerTypeKind) + { + value = LLVM.BuildPtrToInt(_builder, value, LLVM.Int32Type(), String.Empty); + } if (opcode == ILOpcode.brfalse) { @@ -1064,8 +903,21 @@ namespace Internal.IL kind = op2.Kind; } - LLVMValueRef left = op1.ValueForStackKind(kind, _builder, false); - LLVMValueRef right = op2.ValueForStackKind(kind, _builder, false); + LLVMValueRef left = op1.LLVMValue; + LLVMValueRef right = op2.LLVMValue; + + if (kind == StackValueKind.NativeInt || kind == StackValueKind.ObjRef || kind == StackValueKind.ByRef) + { + if (LLVM.GetTypeKind(LLVM.TypeOf(left)) == LLVMTypeKind.LLVMPointerTypeKind) + { + left = LLVM.BuildPtrToInt(_builder, left, LLVM.Int32Type(), "lptrasint"); + } + if (LLVM.GetTypeKind(LLVM.TypeOf(right)) == LLVMTypeKind.LLVMPointerTypeKind) + { + right = LLVM.BuildPtrToInt(_builder, right, LLVM.Int32Type(), "rptrasint"); + } + } + switch (opcode) { @@ -1107,17 +959,19 @@ namespace Internal.IL if (target.StartOffset == 0) throw new NotImplementedException("cant branch to entry basic block"); - ImportFallthrough(target); - ImportFallthrough(fallthrough); LLVM.BuildCondBr(_builder, condition, GetLLVMBasicBlockForBlock(target), GetLLVMBasicBlockForBlock(fallthrough)); + + ImportFallthrough(fallthrough); } + + ImportFallthrough(target); } private void ImportSwitchJump(int jmpBase, int[] jmpDelta, BasicBlock fallthrough) { var operand = _stack.Pop(); - var @switch = LLVM.BuildSwitch(_builder, operand.ValueAsInt32(_builder, false), GetLLVMBasicBlockForBlock(fallthrough), (uint)jmpDelta.Length); + var @switch = LLVM.BuildSwitch(_builder, operand.LLVMValue, GetLLVMBasicBlockForBlock(fallthrough), (uint)jmpDelta.Length); for (var i = 0; i < jmpDelta.Length; i++) { var target = _basicBlocks[_currentOffset + jmpDelta[i]]; @@ -1135,13 +989,22 @@ namespace Internal.IL private void ImportLoadIndirect(TypeDesc type) { - var pointer = _stack.Pop(); - Debug.Assert(pointer is ExpressionEntry || pointer is ConstantEntry); - var expressionPointer = pointer as ExpressionEntry; - TypeDesc pointerElementType = pointer.Type.GetParameterType(); - LLVMValueRef rawValue = expressionPointer?.RawLLVMValue ?? LLVM.ConstNull(GetLLVMTypeForTypeDesc(pointerElementType)); - _stack.Push(new LoadExpressionEntry(type != null ? GetStackValueKind(type) : StackValueKind.ByRef, "ldind", - rawValue, pointer.Type.GetParameterType())); + StackEntry pointer = _stack.Pop(); + LLVMTypeRef loadType = GetLLVMTypeForTypeDesc(type); + LLVMTypeRef pointerType = LLVM.PointerType(loadType, 0); + + LLVMValueRef typedPointer; + if (LLVM.GetTypeKind(LLVM.TypeOf(pointer.LLVMValue)) != LLVMTypeKind.LLVMPointerTypeKind) + { + typedPointer = LLVM.BuildIntToPtr(_builder, pointer.LLVMValue, pointerType, "ldindintptrcast"); + } + else + { + typedPointer = LLVM.BuildPointerCast(_builder, pointer.LLVMValue, pointerType, "ldindptrcast"); + } + + LLVMValueRef load = LLVM.BuildLoad(_builder, typedPointer, "ldind"); + PushExpression(GetStackValueKind(type), "ldlind", load, type); } private void ImportStoreIndirect(int token) @@ -1153,18 +1016,29 @@ namespace Internal.IL { StackEntry value = _stack.Pop(); StackEntry destinationPointer = _stack.Pop(); - LLVMValueRef typedValue; - LLVMValueRef typedPointer; + LLVMTypeRef requestedPointerType = LLVM.PointerType(GetLLVMTypeForTypeDesc(type), 0); + LLVMValueRef typedValue = value.LLVMValue; + LLVMValueRef typedPointer = destinationPointer.LLVMValue; - if (type != null) + if (LLVM.GetTypeKind(LLVM.TypeOf(destinationPointer.LLVMValue)) != LLVMTypeKind.LLVMPointerTypeKind) { - typedValue = value.ValueAsType(type, _builder); - typedPointer = destinationPointer.ValueAsType(type.MakePointerType(), _builder); + typedPointer = LLVM.BuildIntToPtr(_builder, destinationPointer.LLVMValue, requestedPointerType, "stindintptrcast"); } else { - typedPointer = destinationPointer.ValueAsType(LLVM.PointerType(LLVM.Int32Type(), 0), _builder); - typedValue = value.ValueAsInt32(_builder, false); + typedPointer = LLVM.BuildPointerCast(_builder, destinationPointer.LLVMValue, requestedPointerType, "stindptrcast"); + } + + if (value.Type != type) + { + if (LLVM.GetTypeKind(GetLLVMTypeForTypeDesc(value.Type)) != LLVMTypeKind.LLVMPointerTypeKind) + { + typedValue = LLVM.BuildIntCast(_builder, typedValue, GetLLVMTypeForTypeDesc(type), "stindvalcast"); + } + else + { + typedValue = LLVM.BuildPointerCast(_builder, typedValue, GetLLVMTypeForTypeDesc(type), "stindvalptrcast"); + } } LLVM.BuildStore(_builder, typedValue, typedPointer); @@ -1191,140 +1065,106 @@ namespace Internal.IL } // The one exception from the above rule - if (kind == StackValueKind.ByRef) + if ((kind == StackValueKind.ByRef) && + (opcode == ILOpcode.sub || opcode == ILOpcode.sub_ovf || opcode == ILOpcode.sub_ovf_un)) { kind = StackValueKind.NativeInt; - type = type.MakePointerType(); + type = null; } LLVMValueRef result; - LLVMValueRef left = op1.ValueForStackKind(kind, _builder, false); - LLVMValueRef right = op2.ValueForStackKind(kind, _builder, false); - if (kind == StackValueKind.Float) + LLVMValueRef left = op1.LLVMValue; + LLVMValueRef right = op2.LLVMValue; + + if (kind == StackValueKind.NativeInt || kind == StackValueKind.ObjRef || kind == StackValueKind.ByRef) { - switch (opcode) + if (LLVM.GetTypeKind(LLVM.TypeOf(left)) == LLVMTypeKind.LLVMPointerTypeKind) { - case ILOpcode.add: - result = LLVM.BuildFAdd(_builder, left, right, "fadd"); - break; - case ILOpcode.sub: - result = LLVM.BuildFSub(_builder, left, right, "fsub"); - break; - case ILOpcode.mul: - result = LLVM.BuildFMul(_builder, left, right, "fmul"); - break; - case ILOpcode.div: - result = LLVM.BuildFDiv(_builder, left, right, "fdiv"); - break; - case ILOpcode.rem: - result = LLVM.BuildFRem(_builder, left, right, "frem"); - break; - - // TODO: Overflow checks - case ILOpcode.add_ovf: - case ILOpcode.add_ovf_un: - result = LLVM.BuildFAdd(_builder, left, right, "fadd"); - break; - case ILOpcode.sub_ovf: - case ILOpcode.sub_ovf_un: - result = LLVM.BuildFSub(_builder, left, right, "fsub"); - break; - case ILOpcode.mul_ovf: - case ILOpcode.mul_ovf_un: - result = LLVM.BuildFMul(_builder, left, right, "fmul"); - break; - - default: - throw new InvalidOperationException(); // Should be unreachable + left = LLVM.BuildPtrToInt(_builder, left, LLVM.Int32Type(), "lptrasint"); } - } - else - { - switch (opcode) + if (LLVM.GetTypeKind(LLVM.TypeOf(right)) == LLVMTypeKind.LLVMPointerTypeKind) { - case ILOpcode.add: - result = LLVM.BuildAdd(_builder, left, right, "add"); - break; - case ILOpcode.sub: - result = LLVM.BuildSub(_builder, left, right, "sub"); - break; - case ILOpcode.mul: - result = LLVM.BuildMul(_builder, left, right, "mul"); - break; - case ILOpcode.div: - result = LLVM.BuildSDiv(_builder, left, right, "sdiv"); - break; - case ILOpcode.div_un: - result = LLVM.BuildUDiv(_builder, left, right, "udiv"); - break; - case ILOpcode.rem: - result = LLVM.BuildSRem(_builder, left, right, "srem"); - break; - case ILOpcode.rem_un: - result = LLVM.BuildURem(_builder, left, right, "urem"); - break; - case ILOpcode.and: - result = LLVM.BuildAnd(_builder, left, right, "and"); - break; - case ILOpcode.or: - result = LLVM.BuildOr(_builder, left, right, "or"); - break; - case ILOpcode.xor: - result = LLVM.BuildXor(_builder, left, right, "xor"); - break; - - // TODO: Overflow checks - case ILOpcode.add_ovf: - case ILOpcode.add_ovf_un: - result = LLVM.BuildAdd(_builder, left, right, "add"); - break; - case ILOpcode.sub_ovf: - case ILOpcode.sub_ovf_un: - result = LLVM.BuildSub(_builder, left, right, "sub"); - break; - case ILOpcode.mul_ovf: - case ILOpcode.mul_ovf_un: - result = LLVM.BuildMul(_builder, left, right, "mul"); - break; - - default: - throw new InvalidOperationException(); // Should be unreachable + right = LLVM.BuildPtrToInt(_builder, right, LLVM.Int32Type(), "rptrasint"); } } - - if (kind == StackValueKind.NativeInt || kind == StackValueKind.ByRef || kind == StackValueKind.ObjRef) + switch (opcode) { - //we need to put the type back if we changed it because it started out a pointer - result = CastToTypeDesc(result, type); + case ILOpcode.add: + result = LLVM.BuildAdd(_builder, left, right, "add"); + break; + case ILOpcode.sub: + result = LLVM.BuildSub(_builder, left, right, "sub"); + break; + case ILOpcode.mul: + result = LLVM.BuildMul(_builder, left, right, "mul"); + break; + case ILOpcode.div: + result = LLVM.BuildSDiv(_builder, left, right, "sdiv"); + break; + case ILOpcode.div_un: + result = LLVM.BuildUDiv(_builder, left, right, "udiv"); + break; + case ILOpcode.rem: + result = LLVM.BuildSRem(_builder, left, right, "srem"); + break; + case ILOpcode.rem_un: + result = LLVM.BuildURem(_builder, left, right, "urem"); + break; + case ILOpcode.and: + result = LLVM.BuildAnd(_builder, left, right, "and"); + break; + case ILOpcode.or: + result = LLVM.BuildOr(_builder, left, right, "or"); + break; + case ILOpcode.xor: + result = LLVM.BuildXor(_builder, left, right, "xor"); + break; + + // TODO: Overflow checks + case ILOpcode.add_ovf: + case ILOpcode.add_ovf_un: + result = LLVM.BuildAdd(_builder, left, right, "add"); + break; + case ILOpcode.sub_ovf: + case ILOpcode.sub_ovf_un: + result = LLVM.BuildSub(_builder, left, right, "sub"); + break; + case ILOpcode.mul_ovf: + case ILOpcode.mul_ovf_un: + result = LLVM.BuildMul(_builder, left, right, "mul"); + break; + + default: + throw new InvalidOperationException(); // Should be unreachable } - PushExpression(kind, "binop", result, type); + + PushExpression(kind, "", result, type); } private void ImportShiftOperation(ILOpcode opcode) { LLVMValueRef result; + StackEntry numBitsToShift = _stack.Pop(); StackEntry valueToShift = _stack.Pop(); - LLVMValueRef valueToShiftValue = valueToShift.ValueForStackKind(valueToShift.Kind, _builder, false); - switch (opcode) { case ILOpcode.shl: - result = LLVM.BuildShl(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shl"); + result = LLVM.BuildShl(_builder, valueToShift.LLVMValue, numBitsToShift.LLVMValue, "shl"); break; case ILOpcode.shr: - result = LLVM.BuildAShr(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shr"); + result = LLVM.BuildAShr(_builder, valueToShift.LLVMValue, numBitsToShift.LLVMValue, "shr"); break; case ILOpcode.shr_un: - result = LLVM.BuildLShr(_builder, valueToShiftValue, numBitsToShift.ValueAsInt32(_builder, false), "shr"); + result = LLVM.BuildLShr(_builder, valueToShift.LLVMValue, numBitsToShift.LLVMValue, "shr"); break; default: throw new InvalidOperationException(); // Should be unreachable } - PushExpression(valueToShift.Kind, "shiftop", result, valueToShift.Type); + PushExpression(valueToShift.Kind, "", result, valueToShift.Type); } private void ImportCompareOperation(ILOpcode opcode) @@ -1345,8 +1185,34 @@ namespace Internal.IL } LLVMValueRef result; - LLVMValueRef typeSaneOp1 = op1.ValueForStackKind(kind, _builder, true); - LLVMValueRef typeSaneOp2 = op2.ValueForStackKind(kind, _builder, true); + //TODO: deal with sign extension here instead of just casting + var typeSaneOp1 = op1.LLVMValue; + var typeSaneOp2 = op2.LLVMValue; + if (op1.Type != op2.Type || op1.Type == null) + { + if (op1.Type != null && op2.Type != null) + { + if (op1.Type.IsPrimitive && op2.Type.IsPrimitive) + { + if (op1.Type.GetElementSize().AsInt > op2.Type.GetElementSize().AsInt) + typeSaneOp2 = CastIfNecessary(op2.LLVMValue, GetLLVMTypeForTypeDesc(op1.Type)); + else + typeSaneOp1 = CastIfNecessary(op1.LLVMValue, GetLLVMTypeForTypeDesc(op2.Type)); + } + else + { + typeSaneOp2 = CastIfNecessary(op2.LLVMValue, GetLLVMTypeForTypeDesc(op1.Type)); + } + } + else if (op1.Type == null && op1.Kind == StackValueKind.ObjRef) + { + typeSaneOp1 = CastIfNecessary(op1.LLVMValue, LLVM.TypeOf(typeSaneOp2)); + } + else if (op2.Type == null && op2.Kind == StackValueKind.ObjRef) + { + typeSaneOp2 = CastIfNecessary(op2.LLVMValue, LLVM.TypeOf(typeSaneOp1)); + } + } switch (opcode) { @@ -1369,30 +1235,23 @@ namespace Internal.IL throw new NotSupportedException(); // unreachable } - PushExpression(StackValueKind.Int32, "cmpop", result, GetWellKnownType(WellKnownType.SByte)); + PushExpression(kind, "", result, GetWellKnownType(WellKnownType.SByte)); } private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) { StackEntry value = _stack.Pop(); - LLVMValueRef convertedValue; + StackEntry convertedValue = value.Duplicate(); //conv.u for a pointer should change to a int8* - if (wellKnownType == WellKnownType.UIntPtr) + if(wellKnownType == WellKnownType.UIntPtr) { if (value.Kind == StackValueKind.Int32) { - convertedValue = LLVM.BuildIntToPtr(_builder, value.ValueAsInt32(_builder, false), LLVM.PointerType(LLVM.Int8Type(), 0), "conv.u"); - } - else - { - convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder); + convertedValue.LLVMValue = LLVM.BuildIntToPtr(_builder, value.LLVMValue, LLVM.PointerType(LLVM.Int8Type(), 0), "conv.u"); } } - else - { - convertedValue = value.ValueAsType(GetWellKnownType(wellKnownType), _builder); - } - PushExpression(value.Kind, "conv", convertedValue, value.Type); + + _stack.Push(convertedValue); } private void ImportUnaryOperation(ILOpcode opCode) @@ -1405,21 +1264,21 @@ namespace Internal.IL case ILOpcode.neg: if (argument.Kind == StackValueKind.Float) { - result = LLVM.BuildFNeg(_builder, argument.ValueForStackKind(argument.Kind, _builder, false), "neg"); + result = LLVM.BuildFNeg(_builder, argument.LLVMValue, "neg"); } else { - result = LLVM.BuildNeg(_builder, argument.ValueForStackKind(argument.Kind, _builder, true), "neg"); + result = LLVM.BuildNeg(_builder, argument.LLVMValue, "neg"); } break; case ILOpcode.not: - result = LLVM.BuildNot(_builder, argument.ValueForStackKind(argument.Kind, _builder, true), "not"); + result = LLVM.BuildNot(_builder, argument.LLVMValue, "not"); break; default: throw new NotSupportedException(); // unreachable } - PushExpression(argument.Kind, "unaryop", result, argument.Type); + PushExpression(argument.Kind, "", result, argument.Type); } private void ImportCpOpj(int token) @@ -1451,16 +1310,21 @@ namespace Internal.IL if (ldtokenValue is TypeDesc) { ldtokenKind = WellKnownType.RuntimeTypeHandle; - PushExpression(StackValueKind.ByRef, "ldtoken", GetEETypeForTypeDesc(ldtokenValue as TypeDesc), _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr")); + //AddTypeReference((TypeDesc)ldtokenValue, false); + + // todo: this doesn't work because we don't have the eetypeptr pushed. How do we get the eetypeptr? MethodDesc helper = _compilation.TypeSystemContext.GetHelperEntryPoint("LdTokenHelpers", "GetRuntimeTypeHandle"); - AddMethodReference(helper); + //AddMethodReference(helper); HandleCall(helper); name = ldtokenValue.ToString(); + + //value = new LdTokenEntry(StackValueKind.ValueType, name, (TypeDesc)ldtokenValue, GetWellKnownType(ldtokenKind)); } else if (ldtokenValue is FieldDesc) { ldtokenKind = WellKnownType.RuntimeFieldHandle; - value = new LdTokenEntry(StackValueKind.ValueType, null, (FieldDesc)ldtokenValue, GetWellKnownType(ldtokenKind)); + // todo: this is probably the wrong llvm value for the field + value = new LdTokenEntry(StackValueKind.ValueType, null, (FieldDesc)ldtokenValue, LLVM.ConstInt(LLVM.Int32Type(), (uint)token, LLVMMisc.False), GetWellKnownType(ldtokenKind)); _stack.Push(value); } else if (ldtokenValue is MethodDesc) @@ -1540,26 +1404,21 @@ namespace Internal.IL private LLVMValueRef GetInstanceFieldAddress(StackEntry objectEntry, FieldDesc field) { var objectType = objectEntry.Type ?? field.OwningType; - LLVMValueRef untypedObjectValue; - LLVMTypeRef llvmObjectType = GetLLVMTypeForTypeDesc(objectType); - if (objectEntry is LoadExpressionEntry) + LLVMValueRef typedObjectValue; + if (objectType.IsValueType && !objectType.IsPointer && objectEntry.Kind != StackValueKind.NativeInt && objectEntry.Kind != StackValueKind.ByRef) { - untypedObjectValue = CastToRawPointer(((LoadExpressionEntry)objectEntry).RawLLVMValue); - } - else if (objectType.IsValueType && !objectType.IsPointer && objectEntry.Kind != StackValueKind.NativeInt && objectEntry.Kind != StackValueKind.ByRef) - { - untypedObjectValue = LLVM.BuildAlloca(_builder, llvmObjectType, "objptr"); - LLVM.BuildStore(_builder, objectEntry.ValueAsType(llvmObjectType, _builder), untypedObjectValue); - untypedObjectValue = LLVM.BuildPointerCast(_builder, untypedObjectValue, LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), "objptrcast"); + typedObjectValue = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(objectType), "objptr"); + LLVM.BuildStore(_builder, objectEntry.LLVMValue, typedObjectValue); } else { - untypedObjectValue = objectEntry.ValueAsType(LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), _builder); + typedObjectValue = objectEntry.LLVMValue; } - var loadLocation = LLVM.BuildGEP(_builder, untypedObjectValue, + var untypedObjectPointer = CastIfNecessary(typedObjectValue, LLVM.PointerType(LLVMTypeRef.Int8Type(), 0)); + var loadLocation = LLVM.BuildGEP(_builder, untypedObjectPointer, new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)field.Offset.AsInt, LLVMMisc.False) }, String.Empty); - return loadLocation; + return LLVM.BuildPointerCast(_builder, loadLocation, LLVM.PointerType(GetLLVMTypeForTypeDesc(field.FieldType), 0), "fieldaddresscast"); } private LLVMValueRef GetFieldAddress(FieldDesc field, bool isStatic) @@ -1570,7 +1429,8 @@ namespace Internal.IL if (!isStatic) _stack.Pop(); - return WebAssemblyObjectWriter.EmitGlobal(Module, field, _compilation.NameMangler); + LLVMValueRef untypedFieldAddress = WebAssemblyObjectWriter.EmitGlobal(Module, field, _compilation.NameMangler); + return LLVM.BuildPointerCast(_builder, untypedFieldAddress, LLVM.PointerType(GetLLVMTypeForTypeDesc(field.FieldType), 0), "tempfieldaddresscast"); } else { @@ -1582,22 +1442,26 @@ namespace Internal.IL { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - PushLoadExpression(GetStackValueKind(field.FieldType), "ldfld_" + field.Name, fieldAddress, field.FieldType); + LLVMValueRef loadValue = LLVM.BuildLoad(_builder, fieldAddress, "ldfld_" + field.Name); + PushExpression(GetStackValueKind(field.FieldType), "ldfld", loadValue, field.FieldType); } private void ImportAddressOfField(int token, bool isStatic) { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - _stack.Push(new AddressExpressionEntry(StackValueKind.ByRef, "ldflda", fieldAddress, field.FieldType.MakePointerType())); + PushExpression(StackValueKind.ByRef, "ldflda", fieldAddress, field.FieldType.MakePointerType()); } private void ImportStoreField(int token, bool isStatic) { FieldDesc field = (FieldDesc)_methodIL.GetObject(token); StackEntry valueEntry = _stack.Pop(); + LLVMValueRef value = valueEntry.LLVMValue; + + value = CastIfNecessary(value, GetLLVMTypeForTypeDesc(field.FieldType)); LLVMValueRef fieldAddress = GetFieldAddress(field, isStatic); - CastingStore(fieldAddress, valueEntry, field.FieldType); + LLVM.BuildStore(_builder, value, fieldAddress); } // Loads symbol address. Address is represented as a i32* @@ -1621,24 +1485,10 @@ namespace Internal.IL private void ImportInitObj(int token) { - TypeDesc type = ResolveTypeToken(token); - var valueEntry = _stack.Pop(); - var llvmType = GetLLVMTypeForTypeDesc(type); - if (llvmType.TypeKind == LLVMTypeKind.LLVMArrayTypeKind) - ImportCallMemset(valueEntry.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder), 0, type.GetElementSize().AsInt); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstInt(llvmType, 0, LLVMMisc.False), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMPointerTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstNull(llvmType), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else if (llvmType.TypeKind == LLVMTypeKind.LLVMFloatTypeKind) - LLVM.BuildStore(_builder, LLVM.ConstReal(llvmType, 0.0), valueEntry.ValueAsType(LLVM.PointerType(llvmType, 0), _builder)); - else - throw new NotImplementedException(); } private void ImportBox(int token) { - } private void ImportLeave(BasicBlock target) @@ -1723,48 +1573,38 @@ namespace Internal.IL if (_stack.Length > 0) { entryStack = new EvaluationStack(_stack.Length); + +#pragma warning disable 162 // Due to not implement3ed exception incrementer in for needs pragma warning disable for (int i = 0; i < _stack.Length; i++) { - entryStack.Push(NewSpillSlot(_stack[i])); + // todo: do we need anything special for spilled stacks like cpp codegen does? + entryStack.Push(_stack[i]); + //entryStack.Push(NewSpillSlot(_stack[i])); } +#pragma warning restore 162 } next.EntryStack = entryStack; } if (entryStack != null) { + // todo: do we have to do anything here? +#pragma warning disable 162// Due to not implement3ed exception incrementer in for needs pragma warning disable for (int i = 0; i < entryStack.Length; i++) { - var currentEntry = _stack[i]; - var entry = entryStack[i] as SpilledExpressionEntry; - if (entry == null) - throw new InvalidProgramException(); - - if (currentEntry is SpilledExpressionEntry) - continue; //this is already a sharable value - - StoreTemp(entry.LocalIndex, currentEntry.ValueAsType(entry.Type, _builder)); + /*AppendLine(); + Append(entryStack[i]); + Append(" = "); + Append(_stack[i]); + AppendSemicolon();*/ } +#pragma warning restore 162 } MarkBasicBlock(next); } - private StackEntry NewSpillSlot(StackEntry entry) - { - if (entry is SpilledExpressionEntry) - return entry; - else - { - var entryType = entry.Type ?? GetWellKnownType(WellKnownType.Object); //type is required here, currently the only time entry.Type is null is if someone has pushed a null literal - var entryIndex = _spilledExpressions.Count; - var newEntry = new SpilledExpressionEntry(entry.Kind, entry is ExpressionEntry ? ((ExpressionEntry)entry).Name : "spilled" + entryIndex, entryType, entryIndex, this); - _spilledExpressions.Add(newEntry); - return newEntry; - } - } - private TypeDesc ResolveTypeToken(int token) { return (TypeDesc)_methodIL.GetObject(token); diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs index 3a5f48117..8a814508e 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs @@ -101,6 +101,7 @@ namespace Internal.IL static LLVMValueRef TrapFunction = default(LLVMValueRef); static LLVMValueRef DoNothingFunction = default(LLVMValueRef); + private static IEnumerable GetParameterNamesForMethod(MethodDesc method) { // TODO: The uses of this method need revision. The right way to get to this info is from diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs index 140e2b1bc..335157917 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/WebAssemblyObjectWriter.cs @@ -188,17 +188,6 @@ namespace ILCompiler.DependencyAnalysis //throw new NotImplementedException(); // This function isn't complete } - public static LLVMValueRef GetConstZeroArray(int length) - { - var int8Type = LLVM.Int8Type(); - var result = new LLVMValueRef[length]; - for (int i = 0; i < length; i++) - { - result[i] = LLVM.ConstInt(int8Type, 0, LLVMMisc.False); - } - return LLVM.ConstArray(int8Type, result); - } - public static LLVMValueRef EmitGlobal(LLVMModuleRef module, FieldDesc field, NameMangler nameMangler) { if (field.IsThreadStatic) @@ -214,7 +203,7 @@ namespace ILCompiler.DependencyAnalysis var valueType = LLVM.ArrayType(LLVM.Int8Type(), (uint)field.FieldType.GetElementSize().AsInt); var llvmValue = LLVM.AddGlobal(module, valueType, nameMangler.GetMangledFieldName(field).ToString()); LLVM.SetLinkage(llvmValue, LLVMLinkage.LLVMInternalLinkage); - LLVM.SetInitializer(llvmValue, GetConstZeroArray(field.FieldType.GetElementSize().AsInt)); + LLVM.SetInitializer(llvmValue, LLVM.ConstPointerNull(valueType)); s_staticFieldMapping.Add(field, llvmValue); return llvmValue; } @@ -273,7 +262,7 @@ namespace ILCompiler.DependencyAnalysis { LLVMValueRef valRef = IsFunction ? LLVM.GetNamedFunction(module, SymbolName) : LLVM.GetNamedGlobal(module, SymbolName); - if (Offset != 0 && valRef.Pointer != IntPtr.Zero) + if (Offset != 0) { var pointerType = LLVM.PointerType(LLVM.Int8Type(), 0); var bitCast = LLVM.ConstBitCast(valRef, pointerType); @@ -324,16 +313,8 @@ namespace ILCompiler.DependencyAnalysis if (ObjectSymbolRefs.TryGetValue(curOffset, out symbolRef)) { LLVMValueRef pointedAtValue = symbolRef.ToLLVMValueRef(module); - //TODO: why did this come back null - if (pointedAtValue.Pointer != IntPtr.Zero) - { - var ptrValue = LLVM.ConstBitCast(pointedAtValue, intPtrType); - entries.Add(ptrValue); - } - else - { - entries.Add(LLVM.ConstPointerNull(intPtrType)); - } + var ptrValue = LLVM.ConstBitCast(pointedAtValue, intPtrType); + entries.Add(ptrValue); } else { @@ -377,6 +358,7 @@ namespace ILCompiler.DependencyAnalysis _dataToFill.Add(new ObjectNodeDataEmission(arrayglobal, _currentObjectData.ToArray(), _currentObjectSymbolRefs)); + foreach (var symbolIdInfo in _symbolDefs) { EmitSymbolDef(arrayglobal, symbolIdInfo.Key, symbolIdInfo.Value); diff --git a/src/ILCompiler.WebAssembly/src/Compiler/DependencyAnalysis/WebAssemblyCodegenNodeFactory.cs b/src/ILCompiler.WebAssembly/src/Compiler/DependencyAnalysis/WebAssemblyCodegenNodeFactory.cs index 978e29f8e..039969de2 100644 --- a/src/ILCompiler.WebAssembly/src/Compiler/DependencyAnalysis/WebAssemblyCodegenNodeFactory.cs +++ b/src/ILCompiler.WebAssembly/src/Compiler/DependencyAnalysis/WebAssemblyCodegenNodeFactory.cs @@ -32,8 +32,8 @@ namespace ILCompiler.DependencyAnalysis protected override IMethodNode CreateUnboxingStubNode(MethodDesc method) { - // TODO: this is wrong: this returns an unstubbed node - return new WebAssemblyMethodCodeNode(method); + // TODO: this is wrong: this returns an assembly stub node + return new UnboxingStubNode(method, Target); } protected override ISymbolNode CreateReadyToRunHelperNode(ReadyToRunHelperKey helperCall) diff --git a/tests/src/Simple/HelloWasm/Program.cs b/tests/src/Simple/HelloWasm/Program.cs index 2cb0eb895..453a8555e 100644 --- a/tests/src/Simple/HelloWasm/Program.cs +++ b/tests/src/Simple/HelloWasm/Program.cs @@ -11,12 +11,10 @@ internal static class Program private static unsafe void Main(string[] args) { Add(1, 2); - var tempObj = new TestClass(1337); + int tempInt = 0; (*(&tempInt)) = 9; - tempObj.TestMethod("Hello"); - if(tempInt == 9) { PrintLine("Hello from C#!"); @@ -24,8 +22,6 @@ internal static class Program TwoByteStr str = new TwoByteStr() { first = 1, second = 2 }; TwoByteStr str2 = new TwoByteStr() { first = 3, second = 4 }; - *(&str) = str2; - str2 = *(&str); if (str2.second == 4) { @@ -61,7 +57,6 @@ internal static class Program { PrintLine("shiftRight test: Ok."); } - var unsignedShift = UnsignedShift(0xFFFFFFFFu, 4) == 0x0FFFFFFFu; if (unsignedShift) { @@ -164,21 +159,3 @@ public struct TwoByteStr public byte second; } -public class TestClass -{ - public string TestString {get; set;} - - public TestClass(int number) - { - if(number != 1337) - throw new Exception(); - } - - public void TestMethod(string str) - { - TestString = str; - if(TestString != str) - throw new Exception(); - } -} -