Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 59 additions & 20 deletions src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3999,6 +3999,17 @@ private void ImportRefAnyVal(int token)

private void ImportCkFinite()
{
StackEntry value = _stack.Pop();
if (value.Type == GetWellKnownType(WellKnownType.Single))
{
ThrowCkFinite(value.ValueForStackKind(value.Kind, _builder, false), 32, ref CkFinite32Function);
}
else
{
ThrowCkFinite(value.ValueForStackKind(value.Kind, _builder, false), 64, ref CkFinite64Function);
}

_stack.Push(value);
}

private void ImportMkRefAny(int token)
Expand Down Expand Up @@ -4201,39 +4212,67 @@ private void ThrowIfNull(LLVMValueRef entry)
builder.BuildCondBr(builder.BuildICmp(LLVMIntPredicate.LLVMIntEQ, NullRefFunction.GetParam(1), LLVMValueRef.CreateConstPointerNull(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0)), "nullCheck"),
throwBlock, retBlock);
builder.PositionAtEnd(throwBlock);
MetadataType nullRefType = _compilation.NodeFactory.TypeSystemContext.SystemModule.GetType("System", "NullReferenceException");

ThrowException(builder, "ThrowHelpers", "ThrowNullReferenceException", NullRefFunction);

builder.PositionAtEnd(retBlock);
builder.BuildRetVoid();
}

LLVMBasicBlockRef nextInstrBlock = default;
CallOrInvoke(false, _builder, GetCurrentTryRegion(), NullRefFunction, new List<LLVMValueRef> { GetShadowStack(), entry }, ref nextInstrBlock);
}

private void ThrowCkFinite(LLVMValueRef value, int size, ref LLVMValueRef llvmCheckFunction)
{
if (llvmCheckFunction.Handle == IntPtr.Zero)
{
llvmCheckFunction = Module.AddFunction("corert.throwckfinite" + size, LLVMTypeRef.CreateFunction(LLVMTypeRef.Void, new LLVMTypeRef[] { LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), size == 32 ? LLVMTypeRef.Float : LLVMTypeRef.Double }, false));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar here - this can be a helper method in MathHelpers.

LLVMValueRef exponentMask;
LLVMTypeRef intTypeRef;
var builder = Context.CreateBuilder();
var block = llvmCheckFunction.AppendBasicBlock("Block");
builder.PositionAtEnd(block);

var arguments = new StackEntry[] { new LoadExpressionEntry(StackValueKind.ValueType, "eeType", GetEETypePointerForTypeDesc(nullRefType, true), GetEETypePtrTypeDesc()) };
if (size == 32)
{
intTypeRef = LLVMTypeRef.Int32;
exponentMask = LLVMValueRef.CreateConstInt(intTypeRef, 0x7F800000, false);
}
else
{
intTypeRef = LLVMTypeRef.Int64;
exponentMask = LLVMValueRef.CreateConstInt(intTypeRef, 0x7FF0000000000000, false);
}

MetadataType helperType = _compilation.TypeSystemContext.SystemModule.GetKnownType("System.Runtime", RuntimeExport);
MethodDesc helperMethod = helperType.GetKnownMethod("RhNewObject", null);
var resultAddress = builder.BuildIntCast(builder.BuildAlloca(LLVMTypeRef.Int32, "resultAddress"), LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), "castResultAddress");
HandleDirectCall(helperMethod, helperMethod.Signature, arguments, null, default(LLVMValueRef), 0, NullRefFunction.GetParam(0), builder, true, resultAddress, helperMethod);
var valRef = builder.BuildBitCast(llvmCheckFunction.GetParam(1), intTypeRef);
LLVMValueRef exponentBits = builder.BuildAnd(valRef, exponentMask, "and");
LLVMValueRef isFinite = builder.BuildICmp(LLVMIntPredicate.LLVMIntEQ, exponentBits, exponentMask, "isfinite");

var exceptionEntry = new LoadExpressionEntry(GetStackValueKind(nullRefType), "RhNewObject_return", resultAddress, nullRefType);
LLVMBasicBlockRef throwBlock = llvmCheckFunction.AppendBasicBlock("Throw");
LLVMBasicBlockRef afterIf = llvmCheckFunction.AppendBasicBlock("AfterIf");
builder.BuildCondBr(isFinite, throwBlock, afterIf);

var ctorDef = nullRefType.GetDefaultConstructor();
builder.PositionAtEnd(throwBlock);

HandleDirectCall(ctorDef, ctorDef.Signature, new StackEntry[] { exceptionEntry }, null, default(LLVMValueRef), 0, NullRefFunction.GetParam(0), builder, false, default(LLVMValueRef), ctorDef);
ThrowException(builder, "ThrowHelpers", "ThrowOverflowException", llvmCheckFunction);

EnsureRhpThrowEx();
LLVMValueRef[] args = new LLVMValueRef[] { exceptionEntry.ValueAsType(LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0), builder) };
builder.BuildCall(RhpThrowEx, args, "");
builder.BuildUnreachable();
builder.PositionAtEnd(retBlock);
afterIf.MoveAfter(llvmCheckFunction.LastBasicBlock);
builder.PositionAtEnd(afterIf);
builder.BuildRetVoid();
}

LLVMBasicBlockRef nextInstrBlock = default;
CallOrInvoke(false, _builder, GetCurrentTryRegion(), NullRefFunction, new List<LLVMValueRef> { GetShadowStack(), entry }, ref nextInstrBlock);
CallOrInvoke(false, _builder, GetCurrentTryRegion(), llvmCheckFunction, new List<LLVMValueRef> { GetShadowStack(), value }, ref nextInstrBlock);
}

void EnsureRhpThrowEx()
private void ThrowException(LLVMBuilderRef builder, string helperClass, string helperMethodName, LLVMValueRef throwingFunction)
{
if (RhpThrowEx.Handle.Equals(IntPtr.Zero))
{
RhpThrowEx = Module.AddFunction("RhpThrowEx", LLVMTypeRef.CreateFunction(LLVMTypeRef.Void, new LLVMTypeRef[] { LLVMTypeRef.CreatePointer(LLVMTypeRef.Int8, 0) }, false));
}
MetadataType helperType = _compilation.TypeSystemContext.SystemModule.GetKnownType("Internal.Runtime.CompilerHelpers", helperClass);
MethodDesc helperMethod = helperType.GetKnownMethod(helperMethodName, null);
LLVMValueRef fn = LLVMFunctionForMethod(helperMethod, helperMethod, null, false, null, null, out bool hasHiddenParam, out LLVMValueRef dictPtrPtrStore, out LLVMValueRef fatFunctionPtr);
builder.BuildCall(fn, new LLVMValueRef[] {throwingFunction.GetParam(0) }, string.Empty);
builder.BuildUnreachable();
}

private LLVMValueRef GetInstanceFieldAddress(StackEntry objectEntry, FieldDesc field)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ public static void CompileMethod(WebAssemblyCodegenCompilation compilation, WebA
static LLVMValueRef LlvmCatchFunclet = default(LLVMValueRef);
static LLVMValueRef LlvmFinallyFunclet = default(LLVMValueRef);
static LLVMValueRef NullRefFunction = default(LLVMValueRef);
static LLVMValueRef CkFinite32Function = default(LLVMValueRef);
static LLVMValueRef CkFinite64Function = default(LLVMValueRef);
public static LLVMValueRef GxxPersonality = default(LLVMValueRef);
public static LLVMTypeRef GxxPersonalityType = default(LLVMTypeRef);

Expand Down
54 changes: 54 additions & 0 deletions tests/src/Simple/HelloWasm/CkFinite.il
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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 CkFinite { }

.class public abstract sealed CkFinite.CkFiniteTest {

.method public static bool CkFinite32(float32) {
.maxstack 5
try_start:
ldarg 0
ckfinite
pop //remove the value from the stack
leave try_end
try_end:
ldc.i4 0x00000001
ret
handler_start:
pop //remove the exception ref from the stack
leave done
handler_end:
done:
ldc.i4 0x00000000
ret
.try try_start to try_end catch [mscorlib]System.OverflowException handler handler_start to handler_end
}

.method public static bool CkFinite64(float64) {
.maxstack 5
try_start:
ldarg 0
ckfinite
pop //remove the value from the stack
leave try_end
try_end:
ldc.i4 0x00000001
ret
handler_start:
pop //remove the exception ref from the stack
leave done
handler_end:
done:
ldc.i4 0x00000000
ret
.try try_start to try_end catch [mscorlib]System.OverflowException handler handler_start to handler_end
}
}
20 changes: 20 additions & 0 deletions tests/src/Simple/HelloWasm/CkFinite.ilproj
Original file line number Diff line number Diff line change
@@ -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="CkFinite.il" />
<PackageReference Include="Microsoft.NETCore.App">
<Version>$(MicrosoftNETCoreAppPackageVersion)</Version>
</PackageReference>
</ItemGroup>

<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
3 changes: 2 additions & 1 deletion tests/src/Simple/HelloWasm/HelloWasm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

<ProjectReference Include="CpObj.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
<IlcArg Include="-r:$(IntermediateOutputPath)\CpObj.dll" Condition="'$(OS)' == 'Windows_NT'" />

<ProjectReference Include="CkFinite.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
<IlcArg Include="-r:$(IntermediateOutputPath)\CkFinite.dll" Condition="'$(OS)' == 'Windows_NT'" />
<ProjectReference Include="ILHelpers.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
<IlcArg Include="-r:$(IntermediateOutputPath)\ILHelpers.dll" Condition="'$(OS)' == 'Windows_NT'" />
</ItemGroup>
Expand Down
45 changes: 44 additions & 1 deletion tests/src/Simple/HelloWasm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#if TARGET_WINDOWS
using CpObj;
using CkFinite;
#endif
internal static class Program
{
Expand Down Expand Up @@ -276,7 +277,7 @@ private static unsafe int Main(string[] args)

TestTryFinally();


#if TARGET_WINDOWS
StartTest("RVA static field test");
int rvaFieldValue = ILHelpers.ILHelpersTest.StaticInitedInt;
Expand Down Expand Up @@ -344,6 +345,10 @@ private static unsafe int Main(string[] args)

TestThrowIfNull();

#if TARGET_WINDOWS
TestCkFinite();
#endif

// This test should remain last to get other results before stopping the debugger
PrintLine("Debugger.Break() test: Ok if debugger is open and breaks.");
System.Diagnostics.Debugger.Break();
Expand Down Expand Up @@ -1671,6 +1676,43 @@ static void TestThrowIfNull()
EndTest(success);
}

#if TARGET_WINDOWS
private static void TestCkFinite()
{
// includes tests from https://github.com/dotnet/coreclr/blob/9b0a9fd623/tests/src/JIT/IL_Conformance/Old/Base/ckfinite.il4
StartTest("CkFiniteTests");
if (!CkFiniteTest.CkFinite32(0) || !CkFiniteTest.CkFinite32(1) ||
!CkFiniteTest.CkFinite32(100) || !CkFiniteTest.CkFinite32(-100) ||
!CkFinite32(0x7F7FFFC0) || CkFinite32(0xFF800000) || // use converter function to get the float equivalent of this bits
CkFinite32(0x7FC00000) && !CkFinite32(0xFF7FFFFF) ||
CkFinite32(0x7F800000))
{
FailTest("one or more 32 bit tests failed");
return;
}

if (!CkFiniteTest.CkFinite64(0) || !CkFiniteTest.CkFinite64(1) ||
!CkFiniteTest.CkFinite64(100) || !CkFiniteTest.CkFinite64(-100) ||
CkFinite64(0x7FF0000000000000) || CkFinite64(0xFFF0000000000000) ||
CkFinite64(0x7FF8000000000000) || !CkFinite64(0xFFEFFFFFFFFFFFFF))
{
FailTest("one or more 64 bit tests failed.");
return;
}
PassTest();
}

private static unsafe bool CkFinite32(uint value)
{
return CkFiniteTest.CkFinite32 (* (float*)(&value));
}

private static unsafe bool CkFinite64(ulong value)
{
return CkFiniteTest.CkFinite64(*(double*)(&value));
}
#endif

static ushort ReadUInt16()
{
// something with MSB set
Expand All @@ -1692,6 +1734,7 @@ public class ClassForNre
public int F;
}


public class ClassWithFloat
{
public static float F;
Expand Down