diff options
author | Blealtan <blealtan@outlook.com> | 2018-02-28 06:30:54 +0300 |
---|---|---|
committer | Morgan Brown <morganbr@users.noreply.github.com> | 2018-02-28 06:30:54 +0300 |
commit | beff0a43b2635ff5acdcb413c037d3ecc97864cb (patch) | |
tree | 2a503e5d02457386546fb127b1acee4cb5152b48 | |
parent | 76899b2aaef6e30297e06ba7043995c1b2336c42 (diff) |
Implement intrinsic call to RuntimeHelpers.InitializeArray for WASM (#5377)
* Implement intrinsic call to InitializeArray.
RuntimeHelpers.InitializeArray is implemented as a call to LLVM
intrinsic llvm.memcpy.p0i8.p0i8.i32, which copies from generated global
constant to provided target array.
Currently the base size of the array object is hardcoded to 8, since no
EEType is provided in the intrinsic call.
Fix #5345.
Add testing code for InitializeArray in HelloWasm.
Roslyn generates RuntimeHelpers.InitializeArray for arrays of integral
types with initializer of length greater or equal than 3. Here we use
this feature to generate a call to RuntimeHelpers.InitializeArray for
test.
Catagorize array argument types in InitializeArray
Differently handle vectors, multidimensional arrays and object typed
arrays in InitializeArray intrinsic.
-rw-r--r-- | src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs | 57 | ||||
-rw-r--r-- | tests/src/Simple/HelloWasm/Program.cs | 8 |
2 files changed, 65 insertions, 0 deletions
diff --git a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs index 037140bb6..8b0936d1e 100644 --- a/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs +++ b/src/ILCompiler.WebAssembly/src/CodeGen/ILToWebAssemblyImporter.cs @@ -1062,6 +1062,63 @@ namespace Internal.IL switch (method.Name) { + case "InitializeArray": + if (metadataType.Namespace == "System.Runtime.CompilerServices" && metadataType.Name == "RuntimeHelpers") + { + StackEntry fieldSlot = _stack.Pop(); + StackEntry arraySlot = _stack.Pop(); + + // TODO: Does fldHandle always come from ldtoken? If not, what to do with other cases? + if (!(fieldSlot is LdTokenEntry<FieldDesc> checkedFieldSlot) || + !(_compilation.GetFieldRvaData(checkedFieldSlot.LdToken) is BlobNode fieldNode)) + throw new InvalidProgramException("Provided field handle is invalid."); + + LLVMValueRef src = LoadAddressOfSymbolNode(fieldNode); + _dependencies.Add(fieldNode); + int srcLength = fieldNode.GetData(_compilation.NodeFactory, false).Data.Length; + + if (arraySlot.Type.IsSzArray) + { + // Handle single dimensional arrays (vectors). + LLVMValueRef arrayObjPtr = arraySlot.ValueAsType(LLVM.PointerType(LLVM.Int8Type(), 0), _builder); + + var argsType = new LLVMTypeRef[] + { + LLVM.PointerType(LLVM.Int8Type(), 0), + LLVM.PointerType(LLVM.Int8Type(), 0), + LLVM.Int32Type(), + LLVM.Int32Type(), + LLVM.Int1Type() + }; + LLVMValueRef memcpyFunction = GetOrCreateLLVMFunction("llvm.memcpy.p0i8.p0i8.i32", LLVM.FunctionType(LLVM.VoidType(), argsType, false)); + + var args = new LLVMValueRef[] + { + LLVM.BuildGEP(_builder, arrayObjPtr, new LLVMValueRef[] { ArrayBaseSize() }, string.Empty), + LLVM.BuildBitCast(_builder, src, LLVM.PointerType(LLVM.Int8Type(), 0), string.Empty), + BuildConstInt32(srcLength), // TODO: Handle destination array length to avoid runtime overflow. + BuildConstInt32(0), // Assume no alignment + BuildConstInt1(0) + }; + LLVM.BuildCall(_builder, memcpyFunction, args, string.Empty); + } + else if (arraySlot.Type.IsMdArray) + { + // Handle multidimensional arrays. + // TODO: Add support for multidimensional array. + throw new NotImplementedException(); + } + else + { + // Handle object-typed first argument. This include System.Array typed array, and any ill-typed argument. + // TODO: Emit runtime type check code on array argument and further memcpy. + // TODO: Maybe a new runtime interface for this is better than hand-written code emission? + throw new NotImplementedException(); + } + + return true; + } + break; case "get_Value": if (metadataType.IsByReferenceOfT) { diff --git a/tests/src/Simple/HelloWasm/Program.cs b/tests/src/Simple/HelloWasm/Program.cs index 812101795..75864c2e0 100644 --- a/tests/src/Simple/HelloWasm/Program.cs +++ b/tests/src/Simple/HelloWasm/Program.cs @@ -210,6 +210,14 @@ internal static class Program System.Diagnostics.Debugger.Break(); + var testRuntimeHelpersInitArray = new long[] {1, 2, 3}; + if(testRuntimeHelpersInitArray[0] == 1 && + testRuntimeHelpersInitArray[1] == 2 && + testRuntimeHelpersInitArray[2] == 3) + { + PrintLine("Runtime.Helpers array initialization test: Ok."); + } + PrintLine("Done"); } |