added support for box/unbox/unbox_any for WASM using malloc (#4731)

This commit is contained in:
Jeff Greene 2017-11-06 00:23:49 -08:00 коммит произвёл Morgan Brown
Родитель ff7decc2fd
Коммит 9a819d14db
2 изменённых файлов: 62 добавлений и 3 удалений

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

@ -804,6 +804,11 @@ namespace Internal.IL
{ {
MetadataType metadataType = (MetadataType)type; MetadataType metadataType = (MetadataType)type;
int objectSize = metadataType.InstanceByteCount.AsInt; int objectSize = metadataType.InstanceByteCount.AsInt;
if (metadataType.IsValueType)
{
objectSize += type.Context.Target.PointerSize;
}
LLVMValueRef allocatedMemory = LLVM.BuildMalloc(_builder, LLVM.ArrayType(LLVM.Int8Type(), (uint)objectSize), "newobj"); LLVMValueRef allocatedMemory = LLVM.BuildMalloc(_builder, LLVM.ArrayType(LLVM.Int8Type(), (uint)objectSize), "newobj");
LLVMValueRef castMemory = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.Int8Type(), 0), "castnewobj"); LLVMValueRef castMemory = LLVM.BuildPointerCast(_builder, allocatedMemory, LLVM.PointerType(LLVM.Int8Type(), 0), "castnewobj");
ImportCallMemset(castMemory, 0, objectSize); ImportCallMemset(castMemory, 0, objectSize);
@ -1428,6 +1433,37 @@ namespace Internal.IL
private void ImportUnbox(int token, ILOpcode opCode) private void ImportUnbox(int token, ILOpcode opCode)
{ {
TypeDesc type = ResolveTypeToken(token);
if (type.IsNullable)
throw new NotImplementedException();
if (opCode == ILOpcode.unbox)
{
var unboxResult = _stack.Pop().ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder);
LLVMValueRef unboxData = LLVM.BuildGEP(_builder, unboxResult, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "unboxData");
//push the pointer to the data, but it shouldnt be implicitly dereferenced
PushExpression(GetStackValueKind(type), "unboxed", unboxData, type);
}
else //unbox_any
{
Debug.Assert(opCode == ILOpcode.unbox_any);
//TODO: when the runtime is ready switch this to calling the real RhUnboxAny
//LLVMValueRef eeType = GetEETypeForTypeDesc(type);
//var eeTypeDesc = _compilation.TypeSystemContext.SystemModule.GetKnownType("System", "EETypePtr");
//LLVMValueRef untypedObjectValue = LLVM.BuildAlloca(_builder, GetLLVMTypeForTypeDesc(type), "objptr");
//PushExpression(StackValueKind.ByRef, "objPtr", untypedObjectValue, type.MakePointerType());
//PushExpression(StackValueKind.ByRef, "eeType", eeType, eeTypeDesc);
//CallRuntimeExport(_compilation.TypeSystemContext, "RhUnboxAny");
//PushLoadExpression(GetStackValueKind(type), "unboxed", untypedObjectValue, type);
//this can be removed once we can call RhUnboxAny
if (!type.IsValueType)
throw new NotImplementedException();
var unboxResult = _stack.Pop().ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder);
LLVMValueRef unboxData = LLVM.BuildGEP(_builder, unboxResult, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "unboxData");
PushLoadExpression(GetStackValueKind(type), "unboxed", unboxData, type);
}
} }
private void ImportRefAnyVal(int token) private void ImportRefAnyVal(int token)
@ -1542,7 +1578,6 @@ namespace Internal.IL
var objectType = objectEntry.Type ?? field.OwningType; var objectType = objectEntry.Type ?? field.OwningType;
LLVMValueRef untypedObjectValue; LLVMValueRef untypedObjectValue;
LLVMTypeRef llvmObjectType = GetLLVMTypeForTypeDesc(objectType); LLVMTypeRef llvmObjectType = GetLLVMTypeForTypeDesc(objectType);
if (objectType.IsValueType && !objectType.IsPointer && objectEntry.Kind != StackValueKind.NativeInt && objectEntry.Kind != StackValueKind.ByRef) if (objectType.IsValueType && !objectType.IsPointer && objectEntry.Kind != StackValueKind.NativeInt && objectEntry.Kind != StackValueKind.ByRef)
{ {
if (objectEntry is LoadExpressionEntry) if (objectEntry is LoadExpressionEntry)
@ -1560,7 +1595,6 @@ namespace Internal.IL
{ {
untypedObjectValue = objectEntry.ValueAsType(LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), _builder); untypedObjectValue = objectEntry.ValueAsType(LLVM.PointerType(LLVMTypeRef.Int8Type(), 0), _builder);
} }
if (field.Offset.AsInt == 0) if (field.Offset.AsInt == 0)
{ {
return untypedObjectValue; return untypedObjectValue;
@ -1649,7 +1683,19 @@ namespace Internal.IL
private void ImportBox(int token) private void ImportBox(int token)
{ {
TypeDesc type = ResolveTypeToken(token);
if (type.IsValueType)
{
if (type.IsNullable)
throw new NotImplementedException();
var value = _stack.Pop();
ExpressionEntry boxTarget = AllocateObject(type);
LLVMValueRef boxData = LLVM.BuildGEP(_builder, boxTarget.RawLLVMValue, new LLVMValueRef[] { BuildConstInt32(type.Context.Target.PointerSize) }, "boxData");
LLVMValueRef typedBoxData = LLVM.BuildPointerCast(_builder, boxData, LLVM.PointerType(GetLLVMTypeForTypeDesc(type), 0), "typedBoxData");
LLVM.BuildStore(_builder, value.ValueAsType(type, _builder), typedBoxData);
_stack.Push(boxTarget);
}
} }
private void ImportLeave(BasicBlock target) private void ImportLeave(BasicBlock target)
@ -1762,6 +1808,13 @@ namespace Internal.IL
} }
private void CallRuntimeExport(TypeSystemContext context, string methodName)
{
MetadataType helperType = context.SystemModule.GetKnownType("System.Runtime", "RuntimeExports");
MethodDesc helperMethod = helperType.GetKnownMethod(methodName, null);
HandleCall(helperMethod);
}
private StackEntry NewSpillSlot(StackEntry entry) private StackEntry NewSpillSlot(StackEntry entry)
{ {
if (entry is SpilledExpressionEntry) if (entry is SpilledExpressionEntry)

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

@ -38,6 +38,12 @@ internal static class Program
PrintLine("static int field test: Ok."); PrintLine("static int field test: Ok.");
} }
var boxedInt = (object)tempInt;
if(((int)boxedInt) == 9)
{
PrintLine("box test: Ok.");
}
var not = Not(0xFFFFFFFF) == 0x00000000; var not = Not(0xFFFFFFFF) == 0x00000000;
if (not) if (not)
{ {
@ -167,7 +173,7 @@ public struct TwoByteStr
public class TestClass public class TestClass
{ {
public string TestString {get; set;} public string TestString {get; set;}
public TestClass(int number) public TestClass(int number)
{ {
if(number != 1337) if(number != 1337)