added support for box/unbox/unbox_any for WASM using malloc (#4731)
This commit is contained in:
Родитель
ff7decc2fd
Коммит
9a819d14db
|
@ -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)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче