Implement castclass & isinst for WebAssembly (#5325)

* Implement castclass & isinst for wasm (#4510)

Implement castclass and isinst opcodes in ILToWebAssemblyImporter by
doing related function calls to methods in System.Runtime.TypeCast.

Fix #4510

Add castclass & isinst test in HelloWasm.

This includes three types of casting:
* castclass/isinst to classes.
* castclass/isinst to interfaces.
* castclass/isinst to array types.

For now, the second and third part of test is failing due to runtime
implementation problems which should be further digged into.
This commit is contained in:
Blealtan 2018-02-03 13:15:17 +08:00 коммит произвёл Morgan Brown
Родитель 569871f97d
Коммит 3470b34c12
2 изменённых файлов: 65 добавлений и 0 удалений

Просмотреть файл

@ -818,6 +818,25 @@ namespace Internal.IL
private void ImportCasting(ILOpcode opcode, int token)
{
TypeDesc type = ResolveTypeToken(token);
//TODO: call GetCastingHelperNameForType from JitHelper.cs (needs refactoring)
string function;
bool throwing = opcode == ILOpcode.castclass;
if (type.IsArray)
function = throwing ? "CheckCastArray" : "IsInstanceOfArray";
else if (type.IsInterface)
function = throwing ? "CheckCastInterface" : "IsInstanceOfInterface";
else
function = throwing ? "CheckCastClass" : "IsInstanceOfClass";
var arguments = new StackEntry[]
{
_stack.Pop(),
new LoadExpressionEntry(StackValueKind.ValueType, "eeType", GetEETypePointerForTypeDesc(type, true), _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr"))
};
_stack.Push(CallRuntime(_compilation.TypeSystemContext, TypeCast, function, arguments, type));
}
private void ImportLoadNull()
@ -2344,6 +2363,7 @@ namespace Internal.IL
private const string RuntimeExport = "RuntimeExports";
private const string RuntimeImport = "RuntimeImports";
private const string InternalCalls = "InternalCalls";
private const string TypeCast = "TypeCast";
private ExpressionEntry CallRuntime(TypeSystemContext context, string className, string methodName, StackEntry[] arguments, TypeDesc forcedReturnType = null)
{
MetadataType helperType = context.SystemModule.GetKnownType("System.Runtime", className);

Просмотреть файл

@ -181,6 +181,27 @@ internal static class Program
IntToStringTest();
CastingTestClass castingTest = new DerivedCastingTestClass1();
if (((DerivedCastingTestClass1)castingTest).GetValue() == 1 && !(castingTest is DerivedCastingTestClass2))
{
PrintLine("Type casting with isinst & castclass to class test: Ok.");
}
// Instead of checking the result of `GetValue`, we use null check by now until interface dispatch is implemented.
if ((ICastingTest1)castingTest != null && !(castingTest is ICastingTest2))
{
PrintLine("Type casting with isinst & castclass to interface test: Ok.");
}
object arrayCastingTest = new BoxStubTest[] { new BoxStubTest { Value = "Array" }, new BoxStubTest { Value = "Cast" }, new BoxStubTest { Value = "Test" } };
PrintLine(((BoxStubTest[])arrayCastingTest)[0].Value);
PrintLine(((BoxStubTest[])arrayCastingTest)[1].Value);
PrintLine(((BoxStubTest[])arrayCastingTest)[2].Value);
if (!(arrayCastingTest is CastingTestClass[]))
{
PrintLine("Type casting with isinst & castclass to array test: Ok.");
}
PrintLine("Done");
}
@ -367,3 +388,27 @@ public class TestDerivedClass : TestClass
}
}
public interface ICastingTest1
{
int GetValue();
}
public interface ICastingTest2
{
int GetValue();
}
public abstract class CastingTestClass
{
public abstract int GetValue();
}
public class DerivedCastingTestClass1 : CastingTestClass, ICastingTest1
{
public override int GetValue() => 1;
}
public class DerivedCastingTestClass2 : CastingTestClass, ICastingTest2
{
public override int GetValue() => 2;
}