fix dup instruction result to no longer reference the original memory in WASM (#5784)

fix dup instruction result to no longer reference the original memory
 added additional dup test cases
This commit is contained in:
Jeff Greene 2018-05-10 15:39:48 -07:00 коммит произвёл Morgan Brown
Родитель 932f1d0788
Коммит 832b86f068
6 изменённых файлов: 177 добавлений и 18 удалений

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

@ -239,7 +239,7 @@ namespace Internal.IL
/// Create a new copy of current entry.
/// </summary>
/// <returns>A new instance of the same type as the current entry.</returns>
public abstract StackEntry Duplicate();
public abstract StackEntry Duplicate(LLVMBuilderRef builder);
}
/// <summary>
@ -298,7 +298,7 @@ namespace Internal.IL
}
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new Int32ConstantEntry(Value, Type);
}
@ -333,7 +333,7 @@ namespace Internal.IL
{
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new Int64ConstantEntry(Value, Type);
}
@ -397,7 +397,7 @@ namespace Internal.IL
return LLVM.ConstReal(type, Value);
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new FloatConstantEntry(Value, Type);
}
@ -425,7 +425,7 @@ namespace Internal.IL
RawLLVMValue = llvmValue;
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new ExpressionEntry(Kind, Name, RawLLVMValue, Type);
}
@ -449,9 +449,9 @@ namespace Internal.IL
{
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type);
return new ExpressionEntry(Kind, "duplicate_" + Name, ILImporter.LoadValue(builder, RawLLVMValue, Type, ILImporter.GetLLVMTypeForTypeDesc(Type), false, "load_duplicate_" + Name), Type);
}
protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
@ -472,9 +472,9 @@ namespace Internal.IL
{
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new LoadExpressionEntry(Kind, Name, RawLLVMValue, Type);
return new AddressExpressionEntry(Kind, Name, RawLLVMValue, Type);
}
protected override LLVMValueRef ValueAsTypeInternal(LLVMTypeRef type, LLVMBuilderRef builder, bool signExtend)
@ -501,7 +501,7 @@ namespace Internal.IL
IsVirtual = isVirtual;
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new FunctionPointerEntry(Name, Method, RawLLVMValue, Type, IsVirtual);
}
@ -519,7 +519,7 @@ namespace Internal.IL
LdToken = token;
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new LdTokenEntry<T>(Kind, Name, LdToken, RawLLVMValue, Type);
}
@ -544,7 +544,7 @@ namespace Internal.IL
{
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return this;
}
@ -576,7 +576,7 @@ namespace Internal.IL
return ILImporter.CastIfNecessary(builder, value, type);
}
public override StackEntry Duplicate()
public override StackEntry Duplicate(LLVMBuilderRef builder)
{
return new SpilledExpressionEntry(Kind, Name, Type, LocalIndex, _importer);
}

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

@ -295,7 +295,7 @@ namespace Internal.IL
int n = entryStack.Length;
for (int i = 0; i < n; i++)
{
_stack.Push(entryStack[i].Duplicate());
_stack.Push(entryStack[i].Duplicate(_builder));
}
}
@ -365,19 +365,19 @@ namespace Internal.IL
LLVM.BuildStore(_builder, CastToTypeDesc(value, type), CastToPointerToTypeDesc(address, type));
}
internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend)
internal static LLVMValueRef LoadValue(LLVMBuilderRef builder, LLVMValueRef address, TypeDesc sourceType, LLVMTypeRef targetType, bool signExtend, string loadName = null)
{
var underlyingSourceType = sourceType.UnderlyingType;
if (targetType.TypeKind == LLVMTypeKind.LLVMIntegerTypeKind && underlyingSourceType.IsPrimitive && !underlyingSourceType.IsPointer)
{
var sourceLLVMType = ILImporter.GetLLVMTypeForTypeDesc(underlyingSourceType);
var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(sourceLLVMType, 0));
return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, "ldvalue"), targetType, signExtend);
return CastIntValue(builder, LLVM.BuildLoad(builder, typedAddress, loadName ?? "ldvalue"), targetType, signExtend);
}
else
{
var typedAddress = CastIfNecessary(builder, address, LLVM.PointerType(targetType, 0));
return LLVM.BuildLoad(builder, typedAddress, "ldvalue");
return LLVM.BuildLoad(builder, typedAddress, loadName ?? "ldvalue");
}
}
@ -836,7 +836,9 @@ namespace Internal.IL
private void ImportDup()
{
_stack.Push(_stack.Peek().Duplicate());
var entry = _stack.Pop();
_stack.Push(entry.Duplicate(_builder));
_stack.Push(entry.Duplicate(_builder));
}
private void ImportPop()

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

@ -4,6 +4,9 @@
<ProjectReference Include="CpObj.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
<IlcArg Include="-r:$(IntermediateOutputPath)\CpObj.dll" Condition="'$(OS)' == 'Windows_NT'" />
<ProjectReference Include="ILHelpers.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
<IlcArg Include="-r:$(IntermediateOutputPath)\ILHelpers.dll" Condition="'$(OS)' == 'Windows_NT'" />
</ItemGroup>
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'">

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

@ -0,0 +1,111 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly extern System.Private.CoreLib
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
.ver 4:0:0:0
}
.assembly ILHelpers { }
.class public ILHelpers.ILHelpersTest
{
.method public static void EatArgs(string, object)
{
ret
}
.method public static void EatArg(object)
{
ret
}
//this is copied from the test case for https://github.com/dotnet/coreclr/issues/14784
//its been adapted to remove the requirement for Console.WriteLine because thats not supported in WASM
//it can be removed once we have support for Console.WriteLine and can run the CoreCLR tests
.method public static int32 InlineAssignByte()
{
.locals init (
int8 local,
object b
)
ldstr "InlineAssignByte"
ldc.i4 300
dup
stloc.0
box int32
stloc.1
ldloc.1
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
ldstr "InlineAssignByte"
ldloc.0
box int32
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
ldloc.1
//after the unboxing and truncation on the way in ensure that we can subtract 200 and end up with the expected 100 return value
unbox.any int32
ldc.i4 200
sub
ret
}
.method public static int32 DupTest(int32&)
{
.locals init (
int32 local,
int32 local2
)
ldarg.0
//push a bunch of entries onto the stack using dup, we will consume them through the rest of this method
dup
dup
dup
dup
dup
//first off lets ensure the passed parameter was pointing to an int of less than 10 (it should be 9)
ldind.i4
ldc.i4 10
clt
brtrue target
//this is just trying to mess with the stack accross basic block boundries
//it should actually leave the evaluation stack unchanged in the end
pop
dup
//make sure we can deref one of our duplicate int refs and box it without any trouble
target: ldind.i4
box int32
call void ILHelpers.ILHelpersTest::EatArg(object)
//deref one of our duplicates and add 1 to it, this should not write back to the parameter it should only be stored in the local
ldind.i4
ldc.i4 1
add
stloc.0
//load one of our duplicates and add 200 to it, we're eventually going to return this value and test for it in the caller
ldind.i4
ldc.i4 200
add
//this should write back into the parameter
stind.i4
ldloc.0
dup
add
dup
stloc.1
ldloc.0
ceq
//if the added value equals the source value we've got something writing to its original StackEntry instead of a dup
brtrue failure
ldind.i4
ret
failure:
pop
ldc.i4 0
ret
}
}

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

@ -0,0 +1,20 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Library</OutputType>
<DebugType>portable</DebugType>
<OutputPath>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutputPath>
<IntermediateOutputPath>$(MSBuildProjectDirectory)\obj\$(Configuration)\$(Platform)\</IntermediateOutputPath>
</PropertyGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<Compile Include="ILHelpers.il" />
<PackageReference Include="Microsoft.NETCore.App">
<Version>$(MicrosoftNETCoreAppPackageVersion)</Version>
</PackageReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

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

@ -17,12 +17,31 @@ internal static class Program
{
Add(1, 2);
int tempInt = 0;
int tempInt2 = 0;
(*(&tempInt)) = 9;
if(tempInt == 9)
{
PrintLine("Hello from C#!");
}
int* targetAddr = (tempInt > 0) ? (&tempInt2) : (&tempInt);
(*targetAddr) = 1;
if(tempInt2 == 1 && tempInt == 9)
{
PrintLine("basic block stack entry Test: Ok.");
}
if(ILHelpers.ILHelpersTest.InlineAssignByte() == 100)
{
PrintLine("Inline assign byte Test: Ok.");
}
if(ILHelpers.ILHelpersTest.DupTest(ref tempInt) == 209 && tempInt == 209)
{
PrintLine("dup test: Ok.");
}
TestClass tempObj = new TestDerivedClass(1337);
tempObj.TestMethod("Hello");
tempObj.TestVirtualMethod("Hello");
@ -159,6 +178,10 @@ internal static class Program
arrayTest[1].Value = "Array load/store test: Ok.";
PrintLine(arrayTest[1].Value);
int ii = 0;
arrayTest[ii++].Value = "dup ref test: Ok.";
PrintLine(arrayTest[0].Value);
var largeArrayTest = new long[] { Int64.MaxValue, 0, Int64.MinValue, 0 };
if(largeArrayTest[0] == Int64.MaxValue &&
largeArrayTest[1] == 0 &&