diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
index 3a6267d96..98f862c54 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/EvaluationStack.cs
@@ -125,7 +125,11 @@ namespace Internal.IL
/// Element at the top of the stack
public T Peek()
{
- Debug.Assert(_top > 0, "Stack is not empty");
+ if (_top <= 0)
+ {
+ ThrowHelper.ThrowInvalidProgramException();
+ }
+
return _stack[_top - 1];
}
@@ -135,11 +139,11 @@ namespace Internal.IL
/// Element formerly at the top of the stack
public T Pop()
{
-#if DEBUG // This should eventually be an assert, but while many opcodes are unimplemented, we can just throw to avoid
- // killing the process
- if(_top <= 0)
- throw new Exception("Stack is not empty");
-#endif //DEBUG
+ if (_top <= 0)
+ {
+ ThrowHelper.ThrowInvalidProgramException();
+ }
+
return _stack[--_top];
}
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
index ab2f01841..7d09d7413 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
@@ -28,6 +28,8 @@ namespace Internal.IL
public LLVMModuleRef Module { get; }
private readonly MethodDesc _method;
private readonly MethodIL _methodIL;
+ private readonly MethodSignature _signature;
+ private readonly TypeDesc _thisType;
private readonly WebAssemblyCodegenCompilation _compilation;
private LLVMValueRef _llvmFunction;
private LLVMBasicBlockRef _curBasicBlock;
@@ -78,6 +80,8 @@ namespace Internal.IL
_methodIL = methodIL;
_ilBytes = methodIL.GetILBytes();
_locals = methodIL.GetLocals();
+ _signature = method.Signature;
+ _thisType = method.OwningType;
var ilExceptionRegions = methodIL.GetExceptionRegions();
_exceptionRegions = new ExceptionRegion[ilExceptionRegions.Length];
@@ -300,17 +304,35 @@ namespace Internal.IL
private void ImportLoadVar(int index, bool argument)
{
int varBase;
+ int varCountBase;
int varOffset;
LLVMTypeRef valueType;
TypeDesc type;
if (argument)
{
+ varCountBase = 0;
varBase = 0;
- // todo: this is off by one for instance methods
+ if (!_signature.IsStatic)
+ {
+ varCountBase = 1;
+ }
+
GetArgSizeAndOffsetAtIndex(index, out int argSize, out varOffset);
- valueType = GetLLVMTypeForTypeDesc(_method.Signature[index]);
- type = _method.Signature[index];
+
+ if (!_signature.IsStatic && index == 0)
+ {
+ type = _thisType;
+ if (type.IsValueType)
+ {
+ type = type.MakeByRefType();
+ }
+ }
+ else
+ {
+ type = _signature[index - varCountBase];
+ }
+ valueType = GetLLVMTypeForTypeDesc(type);
}
else
{
@@ -489,22 +511,51 @@ namespace Internal.IL
private int GetTotalParameterOffset()
{
int offset = 0;
- for (int i = 0; i < _method.Signature.Length; i++)
+ for (int i = 0; i < _signature.Length; i++)
{
- offset += _method.Signature[i].GetElementSize().AsInt;
+ offset += _signature[i].GetElementSize().AsInt;
}
+ if (!_signature.IsStatic)
+ {
+ // If this is a struct, then it's a pointer on the stack
+ if (_thisType.IsValueType)
+ {
+ offset += _thisType.Context.Target.PointerSize;
+ }
+ else
+ {
+ offset += _thisType.GetElementSize().AsInt;
+ }
+ }
+
return offset;
}
private void GetArgSizeAndOffsetAtIndex(int index, out int size, out int offset)
{
- var argType = _method.Signature[index];
+ int thisSize = 0;
+ if (!_signature.IsStatic)
+ {
+ thisSize = _thisType.IsValueType ? _thisType.Context.Target.PointerSize : _thisType.GetElementSize().AsInt;
+ if (index == 0)
+ {
+ size = thisSize;
+ offset = 0;
+ return;
+ }
+ else
+ {
+ index--;
+ }
+ }
+
+ var argType = _signature[index];
size = argType.GetElementSize().AsInt;
- offset = 0;
+ offset = thisSize;
for (int i = 0; i < index; i++)
{
- offset += _method.Signature[i].GetElementSize().AsInt;
+ offset += _signature[i].GetElementSize().AsInt;
}
}
@@ -563,10 +614,10 @@ namespace Internal.IL
private void ImportReturn()
{
- if(_method.Signature.ReturnType != GetWellKnownType(WellKnownType.Void))
+ if (_signature.ReturnType != GetWellKnownType(WellKnownType.Void))
{
StackEntry retVal = _stack.Pop();
- LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_method.Signature.ReturnType);
+ LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(_signature.ReturnType);
ImportStoreHelper(retVal.LLVMValue, valueType, LLVM.GetNextParam(LLVM.GetFirstParam(_llvmFunction)), 0);
}
@@ -597,6 +648,11 @@ namespace Internal.IL
{
throw new NotImplementedException();
}
+ if (opcode == ILOpcode.callvirt && callee.IsAbstract)
+ {
+ throw new NotImplementedException();
+ }
+
HandleCall(callee);
}
@@ -650,9 +706,15 @@ namespace Internal.IL
// argument offset
uint argOffset = 0;
+ int instanceAdjustment = 0;
+ if (!callee.Signature.IsStatic)
+ {
+ instanceAdjustment = 1;
+ }
// The last argument is the top of the stack. We need to reverse them and store starting at the first argument
- LLVMValueRef[] argumentValues = new LLVMValueRef[callee.Signature.Length];
+ LLVMValueRef[] argumentValues = new LLVMValueRef[callee.Signature.Length + instanceAdjustment];
+
for(int i = 0; i < argumentValues.Length; i++)
{
argumentValues[argumentValues.Length - i - 1] = _stack.Pop().LLVMValue;
@@ -662,11 +724,21 @@ namespace Internal.IL
{
LLVMValueRef toStore = argumentValues[index];
- LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(callee.Signature[index]);
+ TypeDesc argType;
+ if (index == 0 && !callee.Signature.IsStatic)
+ {
+ argType = callee.OwningType;
+ }
+ else
+ {
+ argType = callee.Signature[index - instanceAdjustment];
+ }
+
+ LLVMTypeRef valueType = GetLLVMTypeForTypeDesc(argType);
ImportStoreHelper(toStore, valueType, castShadowStack, argOffset);
- argOffset += (uint) callee.Signature[index].GetElementSize().AsInt;
+ argOffset += (uint)argType.GetElementSize().AsInt;
}
LLVM.BuildCall(_builder, fn, new LLVMValueRef[] {
@@ -1250,6 +1322,21 @@ namespace Internal.IL
private void ImportLoadField(int token, bool isStatic)
{
+ if (isStatic)
+ {
+ throw new NotImplementedException("static ldfld");
+ }
+
+ FieldDesc field = (FieldDesc)_methodIL.GetObject(token);
+
+ StackEntry objectEntry = _stack.Pop();
+
+ var untypedObjectPointer = LLVM.BuildPointerCast(_builder, objectEntry.LLVMValue, LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), String.Empty);
+ var loadLocation = LLVM.BuildGEP(_builder, untypedObjectPointer,
+ new LLVMValueRef[] { LLVM.ConstInt(LLVM.Int32Type(), (ulong)field.Offset.AsInt, LLVMMisc.False) }, String.Empty);
+ var typedLoadLocation = LLVM.BuildPointerCast(_builder, loadLocation, LLVM.PointerType(GetLLVMTypeForTypeDesc(field.FieldType), 0), String.Empty);
+ LLVMValueRef loadValue = LLVM.BuildLoad(_builder, typedLoadLocation, "ldfld_" + field.Name);
+ PushExpression(GetStackValueKind(field.FieldType), "ldfld", loadValue, field.FieldType);
}
private void ImportAddressOfField(int token, bool isStatic)
@@ -1312,6 +1399,25 @@ namespace Internal.IL
private void ImportLeave(BasicBlock target)
{
+ for (int i = 0; i < _exceptionRegions.Length; i++)
+ {
+ var r = _exceptionRegions[i];
+
+ if (r.ILRegion.Kind == ILExceptionRegionKind.Finally &&
+ IsOffsetContained(_currentOffset - 1, r.ILRegion.TryOffset, r.ILRegion.TryLength) &&
+ !IsOffsetContained(target.StartOffset, r.ILRegion.TryOffset, r.ILRegion.TryLength))
+ {
+ MarkBasicBlock(_basicBlocks[r.ILRegion.HandlerOffset]);
+ }
+ }
+
+ MarkBasicBlock(target);
+ LLVM.BuildBr(_builder, GetLLVMBasicBlockForBlock(target));
+ }
+
+ private static bool IsOffsetContained(int offset, int start, int length)
+ {
+ return start <= offset && offset < start + length;
}
private void ImportNewArray(int token)
@@ -1438,5 +1544,10 @@ namespace Internal.IL
}
LLVM.BuildCall(_builder, TrapFunction, Array.Empty(), string.Empty);
}
+
+ public override string ToString()
+ {
+ return _method.ToString();
+ }
}
}
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
index 5f75f89c4..2cd878705 100644
--- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
+++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter_Statics.cs
@@ -31,7 +31,8 @@ namespace Internal.IL
if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute"))
{
- throw new NotImplementedException();
+ methodCodeNodeNeedingCode.CompilationCompleted = true;
+ //throw new NotImplementedException();
//CompileExternMethod(methodCodeNodeNeedingCode, ((EcmaMethod)method).GetRuntimeImportName());
//return;
}
@@ -49,7 +50,18 @@ namespace Internal.IL
ILImporter ilImporter = null;
try
{
- ilImporter = new ILImporter(compilation, method, methodIL, methodCodeNodeNeedingCode.GetMangledName(compilation.NameMangler));
+ string mangledName;
+ // TODO: We should use the startup node to generate StartupCodeMain and avoid special casing here
+ if (methodCodeNodeNeedingCode.Method.Signature.IsStatic && methodCodeNodeNeedingCode.Method.Name == "Main")
+ {
+ mangledName = "Main";
+ }
+ else
+ {
+ mangledName = compilation.NameMangler.GetMangledMethodName(methodCodeNodeNeedingCode.Method).ToString();
+ }
+
+ ilImporter = new ILImporter(compilation, method, methodIL, mangledName);
CompilerTypeSystemContext typeSystemContext = compilation.TypeSystemContext;
diff --git a/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilationBuilder.cs b/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilationBuilder.cs
index 5b6919942..48bfaa15b 100644
--- a/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilationBuilder.cs
+++ b/src/ILCompiler.WebAssembly/src/Compiler/WebAssemblyCodegenCompilationBuilder.cs
@@ -19,7 +19,7 @@ namespace ILCompiler
WebAssemblyCodegenConfigProvider _config = new WebAssemblyCodegenConfigProvider(Array.Empty());
public WebAssemblyCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group)
- : base(context, group, new CoreRTNameMangler(new WebAssemblyNodeMangler(), true))
+ : base(context, group, new CoreRTNameMangler(new WebAssemblyNodeMangler(), false))
{
}
diff --git a/tests/src/Simple/HelloWasm/Program.cs b/tests/src/Simple/HelloWasm/Program.cs
index 57eb439ef..63608fe6b 100644
--- a/tests/src/Simple/HelloWasm/Program.cs
+++ b/tests/src/Simple/HelloWasm/Program.cs
@@ -22,46 +22,47 @@ internal static class Program
if(tempInt == 9)
{
string s = "Hello from C#!";
- PrintString(s, 14);
+ PrintString(s);
}
var not = Not(0xFFFFFFFF) == 0x00000000;
if(not)
{
- PrintString("\n", 1);
- PrintString("not test: Ok.", 13);
+ PrintString("\n");
+ PrintString("not test: Ok.");
}
var negInt = Neg(42) == -42;
if(negInt)
{
- PrintString("\n", 1);
- PrintString("negInt test: Ok.", 16);
+ PrintString("\n");
+ PrintString("negInt test: Ok.");
}
var shiftLeft = ShiftLeft(1, 2) == 4;
if(shiftLeft)
{
- PrintString("\n", 1);
- PrintString("shiftLeft test: Ok.", 19);
+ PrintString("\n");
+ PrintString("shiftLeft test: Ok.");
}
var shiftRight = ShiftRight(4, 2) == 1;
if(shiftRight)
{
- PrintString("\n", 1);
- PrintString("shiftRight test: Ok.", 20);
+ PrintString("\n");
+ PrintString("shiftRight test: Ok.");
}
var unsignedShift = UnsignedShift(0xFFFFFFFFu, 4) == 0x0FFFFFFFu;
if(unsignedShift)
{
- PrintString("\n", 1);
- PrintString("unsignedShift test: Ok.", 23);
+ PrintString("\n");
+ PrintString("unsignedShift test: Ok.");
}
}
- private static unsafe void PrintString(string s, int length)
+ private static unsafe void PrintString(string s)
{
+ int length = s.Length;
fixed (char* curChar = s)
{
for (int i = 0; i < length; i++)