Get static string literal loads to work
This commit is contained in:
Родитель
27fa501f10
Коммит
baa75f98ac
|
@ -0,0 +1,69 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ILToNative
|
||||
{
|
||||
class AsmStringWriter
|
||||
{
|
||||
private Encoding _stringEncoding;
|
||||
|
||||
private Action<byte> WriteByte { get; set; }
|
||||
|
||||
public AsmStringWriter(Action<byte> byteWriter)
|
||||
{
|
||||
this.WriteByte = byteWriter;
|
||||
this._stringEncoding = UTF8Encoding.UTF8;
|
||||
}
|
||||
|
||||
public void WriteUInt32(uint value)
|
||||
{
|
||||
WriteByte((byte)value);
|
||||
WriteByte((byte)(value >> 8));
|
||||
WriteByte((byte)(value >> 16));
|
||||
WriteByte((byte)(value >> 24));
|
||||
}
|
||||
|
||||
public void WriteUnsigned(uint d)
|
||||
{
|
||||
if (d < 128)
|
||||
{
|
||||
WriteByte((byte)(d * 2 + 0));
|
||||
}
|
||||
else if (d < 128 * 128)
|
||||
{
|
||||
WriteByte((byte)(d * 4 + 1));
|
||||
WriteByte((byte)(d >> 6));
|
||||
}
|
||||
else if (d < 128 * 128 * 128)
|
||||
{
|
||||
WriteByte((byte)(d * 8 + 3));
|
||||
WriteByte((byte)(d >> 5));
|
||||
WriteByte((byte)(d >> 13));
|
||||
}
|
||||
else if (d < 128 * 128 * 128 * 128)
|
||||
{
|
||||
WriteByte((byte)(d * 16 + 7));
|
||||
WriteByte((byte)(d >> 4));
|
||||
WriteByte((byte)(d >> 12));
|
||||
WriteByte((byte)(d >> 20));
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteByte((byte)15);
|
||||
WriteUInt32(d);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteString(string s)
|
||||
{
|
||||
byte[] bytes = _stringEncoding.GetBytes(s);
|
||||
|
||||
WriteUnsigned((uint)bytes.Length);
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
WriteByte(bytes[i]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ namespace ILToNative
|
|||
Out.WriteLine();
|
||||
Out.WriteLine(".data");
|
||||
|
||||
OutputStrings();
|
||||
|
||||
Out.WriteLine();
|
||||
Out.WriteLine("// Non-GC statics");
|
||||
OutputNonGCStatics();
|
||||
|
@ -101,6 +103,12 @@ namespace ILToNative
|
|||
targetName = ((JitHelper)target).MangledName;
|
||||
}
|
||||
else
|
||||
if (target is string)
|
||||
{
|
||||
int id = AddToStringTable((string)target);
|
||||
targetName = "__str" + id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO:
|
||||
throw new NotImplementedException();
|
||||
|
@ -113,6 +121,17 @@ namespace ILToNative
|
|||
Out.WriteLine(targetName);
|
||||
i += 7;
|
||||
break;
|
||||
|
||||
// REVIEW: I believe the JIT is emitting 0x3 instead of 0xA
|
||||
// for x64, because emitter from x86 is ported for RyuJIT.
|
||||
// I will consult with Bruce and if he agrees, I will delete
|
||||
// this "case" duplicated by IMAGE_REL_BASED_DIR64.
|
||||
case 0x03: // IMAGE_REL_BASED_HIGHLOW
|
||||
Out.Write(".quad ");
|
||||
Out.WriteLine(targetName);
|
||||
i += 7;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
if (code[i] != 0xE8) // call
|
||||
throw new NotImplementedException();
|
||||
|
@ -271,42 +290,77 @@ namespace ILToNative
|
|||
|
||||
void OutputEETypes()
|
||||
{
|
||||
foreach (var t in _registeredTypes.Values)
|
||||
foreach (RegisteredType t in _registeredTypes.Values)
|
||||
{
|
||||
if (!t.IncludedInCompilation)
|
||||
continue;
|
||||
OutputEEType(t.Type, t.Constructed);
|
||||
}
|
||||
}
|
||||
|
||||
Out.WriteLine(".align 16");
|
||||
Out.Write("__EEType_");
|
||||
Out.Write(NameMangler.GetMangledTypeName(t.Type));
|
||||
void OutputEEType(TypeDesc type, bool isConstructed)
|
||||
{
|
||||
Out.WriteLine(".align 16");
|
||||
Out.Write("__EEType_");
|
||||
Out.Write(NameMangler.GetMangledTypeName(type));
|
||||
Out.WriteLine(":");
|
||||
|
||||
if (type.IsArray && ((ArrayType)type).Rank == 1)
|
||||
{
|
||||
Out.Write(".word ");
|
||||
Out.WriteLine(type.GetElementSize()); // m_ComponentSize
|
||||
Out.WriteLine(".word 4"); // m_flags: IsArray(0x4)
|
||||
Out.WriteLine(".int 24");
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.WriteLine(".int 0, 24");
|
||||
}
|
||||
|
||||
if (type.BaseType != null)
|
||||
{
|
||||
Out.Write(".quad __EEType_");
|
||||
Out.WriteLine(NameMangler.GetMangledTypeName(type.BaseType));
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.WriteLine(".quad 0");
|
||||
}
|
||||
|
||||
if (isConstructed)
|
||||
OutputVirtualSlots(type, type);
|
||||
|
||||
Out.WriteLine();
|
||||
}
|
||||
|
||||
|
||||
void OutputStrings()
|
||||
{
|
||||
var strType = TypeSystemContext.GetWellKnownType(WellKnownType.String);
|
||||
|
||||
Out.Write(".global __EEType_");
|
||||
Out.WriteLine(NameMangler.GetMangledTypeName(strType));
|
||||
|
||||
Out.WriteLine(".global __str_fixup");
|
||||
Out.WriteLine(".global __str_fixup_end");
|
||||
Out.WriteLine("__str_fixup:");
|
||||
foreach (var se in _stringTable)
|
||||
{
|
||||
Out.Write("__str");
|
||||
Out.Write(se.Value);
|
||||
Out.Write(": .quad __str_table_entry");
|
||||
Out.WriteLine(se.Value);
|
||||
}
|
||||
Out.WriteLine("__str_fixup_end:");
|
||||
|
||||
Action<byte> byteWriter = (byte b) => { Out.WriteLine(".byte " + b); };
|
||||
AsmStringWriter nf = (_stringTable.Count > 0) ? new AsmStringWriter(byteWriter) : null;
|
||||
foreach (var se in _stringTable)
|
||||
{
|
||||
Out.Write("__str_table_entry");
|
||||
Out.Write(se.Value);
|
||||
Out.WriteLine(":");
|
||||
|
||||
if (t.Type.IsArray && ((ArrayType)t.Type).Rank == 1)
|
||||
{
|
||||
Out.Write(".word ");
|
||||
Out.WriteLine(t.Type.GetElementSize()); // m_ComponentSize
|
||||
Out.WriteLine(".word 4"); // m_flags: IsArray(0x4)
|
||||
Out.WriteLine(".int 24");
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.WriteLine(".int 0, 24");
|
||||
}
|
||||
|
||||
if (t.Type.BaseType != null)
|
||||
{
|
||||
Out.Write(".quad __EEType_");
|
||||
Out.WriteLine(NameMangler.GetMangledTypeName(t.Type.BaseType));
|
||||
}
|
||||
else
|
||||
{
|
||||
Out.WriteLine(".quad 0");
|
||||
}
|
||||
|
||||
if (t.Constructed)
|
||||
OutputVirtualSlots(t.Type, t.Type);
|
||||
|
||||
Out.WriteLine();
|
||||
nf.WriteString(se.Key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace ILToNative
|
|||
readonly CompilerTypeSystemContext _typeSystemContext;
|
||||
readonly CompilationOptions _options;
|
||||
|
||||
Dictionary<string, int> _stringTable = new Dictionary<string, int>();
|
||||
Dictionary<TypeDesc, RegisteredType> _registeredTypes = new Dictionary<TypeDesc, RegisteredType>();
|
||||
Dictionary<MethodDesc, RegisteredMethod> _registeredMethods = new Dictionary<MethodDesc, RegisteredMethod>();
|
||||
Dictionary<FieldDesc, RegisteredField> _registeredFields = new Dictionary<FieldDesc, RegisteredField>();
|
||||
|
@ -275,6 +276,8 @@ namespace ILToNative
|
|||
_mainMethod = mainMethod;
|
||||
AddMethod(mainMethod);
|
||||
|
||||
AddWellKnownTypes();
|
||||
|
||||
while (_methodsThatNeedsCompilation != null)
|
||||
{
|
||||
CompileMethods();
|
||||
|
@ -292,6 +295,13 @@ namespace ILToNative
|
|||
}
|
||||
}
|
||||
|
||||
private void AddWellKnownTypes()
|
||||
{
|
||||
var stringType = TypeSystemContext.GetWellKnownType(WellKnownType.String);
|
||||
AddType(stringType);
|
||||
MarkAsConstructed(stringType);
|
||||
}
|
||||
|
||||
public void AddMethod(MethodDesc method)
|
||||
{
|
||||
RegisteredMethod reg = GetRegisteredMethod(method);
|
||||
|
@ -369,6 +379,13 @@ namespace ILToNative
|
|||
}
|
||||
}
|
||||
|
||||
internal int AddToStringTable(string str)
|
||||
{
|
||||
int id;
|
||||
if (!_stringTable.TryGetValue(str, out id))
|
||||
_stringTable.Add(str, id = _stringTable.Count);
|
||||
return id;
|
||||
}
|
||||
|
||||
struct ReadyToRunHelperKey : IEquatable<ReadyToRunHelperKey>
|
||||
{
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Compiler\AsmStringWriter.cs" />
|
||||
<Compile Include="Compiler\AsmWriter.cs" />
|
||||
<Compile Include="Compiler\Compilation.cs" />
|
||||
<Compile Include="Compiler\CompilerTypeSystemContext.cs" />
|
||||
|
@ -96,4 +97,4 @@
|
|||
<None Include="project.json" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -53,6 +53,76 @@ void __range_check(void * a, size_t elem);
|
|||
|
||||
Object * __get_commandline_args(int argc, char * argv[]);
|
||||
|
||||
namespace AsmDataFormat
|
||||
{
|
||||
typedef uint8_t byte;
|
||||
typedef uint32_t UInt32;
|
||||
|
||||
static UInt32 ReadUInt32(byte **ppStream)
|
||||
{
|
||||
UInt32 result = *(UInt32*)(*ppStream); // Assumes little endian and unaligned access
|
||||
*ppStream += 4;
|
||||
return result;
|
||||
}
|
||||
static int DecodeUnsigned(byte** ppStream, byte* pStreamEnd, UInt32 *pValue)
|
||||
{
|
||||
if (*ppStream >= pStreamEnd)
|
||||
return -1;
|
||||
|
||||
UInt32 value = 0;
|
||||
UInt32 val = **ppStream;
|
||||
if ((val & 1) == 0)
|
||||
{
|
||||
value = (val >> 1);
|
||||
*ppStream += 1;
|
||||
}
|
||||
else if ((val & 2) == 0)
|
||||
{
|
||||
if (*ppStream + 1 >= pStreamEnd)
|
||||
return -1;
|
||||
|
||||
value = (val >> 2) |
|
||||
(((UInt32)*(*ppStream + 1)) << 6);
|
||||
*ppStream += 2;
|
||||
}
|
||||
else if ((val & 4) == 0)
|
||||
{
|
||||
if (*ppStream + 2 >= pStreamEnd)
|
||||
return -1;
|
||||
|
||||
value = (val >> 3) |
|
||||
(((UInt32)*(*ppStream + 1)) << 5) |
|
||||
(((UInt32)*(*ppStream + 2)) << 13);
|
||||
*ppStream += 3;
|
||||
}
|
||||
else if ((val & 8) == 0)
|
||||
{
|
||||
if (*ppStream + 3 >= pStreamEnd)
|
||||
return -1;
|
||||
|
||||
value = (val >> 4) |
|
||||
(((UInt32)*(*ppStream + 1)) << 4) |
|
||||
(((UInt32)*(*ppStream + 2)) << 12) |
|
||||
(((UInt32)*(*ppStream + 3)) << 20);
|
||||
*ppStream += 4;
|
||||
}
|
||||
else if ((val & 16) == 0)
|
||||
{
|
||||
if (*ppStream + 4 >= pStreamEnd)
|
||||
return -1;
|
||||
*ppStream += 1;
|
||||
value = ReadUInt32(ppStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
*pValue = value;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// POD version of EEType to use for static initialization
|
||||
struct RawEEType
|
||||
{
|
||||
|
|
|
@ -20,6 +20,8 @@ extern "C" int32_t RhpEnableConservativeStackReporting();
|
|||
extern "C" void RhpRegisterSimpleModule(SimpleModuleHeader* pModule);
|
||||
#endif // USE_MRT
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
int __initialize_runtime()
|
||||
{
|
||||
#if USE_MRT
|
||||
|
@ -169,10 +171,10 @@ extern "C" Object * __allocate_object(MethodTable * pMT)
|
|||
#endif
|
||||
}
|
||||
|
||||
extern "C" void __EEType_mscorlib_System_String();
|
||||
|
||||
Object * __allocate_string(int32_t len)
|
||||
{
|
||||
#ifdef CPPCODEGEN
|
||||
|
||||
#if !USE_MRT
|
||||
alloc_context * acontext = GetThread()->GetAllocContext();
|
||||
Object * pObject;
|
||||
|
@ -195,19 +197,16 @@ Object * __allocate_string(int32_t len)
|
|||
if (pObject == NULL)
|
||||
return NULL; // TODO: Throw OOM
|
||||
}
|
||||
|
||||
#ifdef CPPCODEGEN
|
||||
pObject->SetMethodTable(System::String::__getMethodTable());
|
||||
|
||||
*(int32_t *)(((intptr_t *)pObject)+1) = len;
|
||||
|
||||
return pObject;
|
||||
#else
|
||||
pObject->SetMethodTable((MethodTable*)__EEType_mscorlib_System_String);
|
||||
#endif
|
||||
*(int32_t *)(((intptr_t *)pObject) + 1) = len;
|
||||
return pObject;
|
||||
#else
|
||||
return RhNewArray(System::String::__getMethodTable(), len);
|
||||
#endif
|
||||
|
||||
#else
|
||||
throw 42;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" Object * __allocate_array(size_t elements, MethodTable * pMT)
|
||||
|
@ -298,6 +297,16 @@ Object * __load_string_literal(const char * string)
|
|||
return pString;
|
||||
}
|
||||
|
||||
Object* __load_static_string_literal(const uint8_t* utf8, int32_t utf8Len, int32_t strLen, OBJECTHANDLE* pHandle)
|
||||
{
|
||||
Object * pString = __allocate_string(strLen);
|
||||
uint16_t * buffer = (uint16_t *)((char*)pString + sizeof(intptr_t) + sizeof(int32_t));
|
||||
if (strLen > 0)
|
||||
UTF8ToWideChar((char*)utf8, utf8Len, buffer, strLen);
|
||||
*pHandle = CreateGlobalHandle(ObjectToOBJECTREF(pString));
|
||||
return pString;
|
||||
}
|
||||
|
||||
// TODO: Rewrite in C#
|
||||
|
||||
extern "C" Object * __castclass_class(void * p, MethodTable * pTargetMT)
|
||||
|
@ -592,10 +601,41 @@ SimpleModuleHeader __module = { NULL, NULL /* &__gcStatics, &__gcStaticsDescs */
|
|||
|
||||
extern "C" int repro_Program__Main();
|
||||
|
||||
extern "C" void __str_fixup();
|
||||
extern "C" void __str_fixup_end();
|
||||
int __reloc_string_fixup()
|
||||
{
|
||||
for (unsigned** ptr = (unsigned**)__str_fixup;
|
||||
ptr < (unsigned**)__str_fixup_end; ptr++)
|
||||
{
|
||||
int utf8Len;
|
||||
uint8_t* bytes = (uint8_t*) *ptr;
|
||||
if (AsmDataFormat::DecodeUnsigned(&bytes, bytes + 5, (unsigned*)&utf8Len) != 0)
|
||||
return -1;
|
||||
|
||||
assert(bytes <= ((uint8_t*)*ptr) + 5);
|
||||
assert(utf8Len >= 0);
|
||||
|
||||
int strLen = 0;
|
||||
if (utf8Len != 0)
|
||||
{
|
||||
strLen = UTF8ToWideCharLen((char*)bytes, utf8Len);
|
||||
if (strLen <= 0) return -1;
|
||||
}
|
||||
|
||||
OBJECTHANDLE handle;
|
||||
*((Object**)ptr) = __load_static_string_literal(bytes, utf8Len, strLen, &handle);
|
||||
// TODO: This "handle" will leak, deallocate with __unload
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
if (__initialize_runtime() != 0) return -1;
|
||||
__register_module(&__module);
|
||||
ReversePInvokeFrame frame; __reverse_pinvoke(&frame);
|
||||
|
||||
if (__reloc_string_fixup() != 0) return -1;
|
||||
|
||||
repro_Program__Main();
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
int UTF8ToWideCharLen(char* bytes, int len);
|
||||
|
||||
int UTF8ToWideChar(char* bytes, int len, uint16_t* buffer, int bufLen);
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include "common.h"
|
||||
#include "platform.h"
|
||||
#include "windows.h"
|
||||
|
||||
int UTF8ToWideCharLen(char* bytes, int len)
|
||||
{
|
||||
assert(len > 0);
|
||||
return MultiByteToWideChar(CP_UTF8, 0, bytes, len, NULL, 0);
|
||||
}
|
||||
|
||||
int UTF8ToWideChar(char* bytes, int len, uint16_t* buffer, int bufLen)
|
||||
{
|
||||
assert(len > 0 && bufLen > 0);
|
||||
return MultiByteToWideChar(CP_UTF8, 0, bytes, len, (LPWSTR) buffer, bufLen);
|
||||
}
|
||||
|
|
@ -83,6 +83,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="platform.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\Native\gc\gccommon.cpp" />
|
||||
|
@ -102,6 +103,7 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="platform.windows.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="repro.s">
|
||||
|
|
|
@ -59,4 +59,4 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1180,8 +1180,15 @@ namespace Internal.JitInterface
|
|||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
bool canGetVarArgsHandle(IntPtr _this, CORINFO_SIG_INFO* pSig)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
InfoAccessType constructStringLiteral(IntPtr _this, CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue)
|
||||
{ throw new NotImplementedException(); }
|
||||
{
|
||||
MethodIL methodIL = (MethodIL) HandleToObject((IntPtr)module);
|
||||
object literal = methodIL.GetObject((int)metaTok);
|
||||
ppValue = (void*) ObjectToHandle(literal);
|
||||
return InfoAccessType.IAT_PVALUE;
|
||||
}
|
||||
|
||||
InfoAccessType emptyStringLiteral(IntPtr _this, ref void* ppValue)
|
||||
{ throw new NotImplementedException(); }
|
||||
uint getFieldThreadLocalStoreID(IntPtr _this, CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection)
|
||||
|
@ -1364,7 +1371,10 @@ namespace Internal.JitInterface
|
|||
}
|
||||
|
||||
ushort getRelocTypeHint(IntPtr _this, void* target)
|
||||
{ throw new NotImplementedException(); }
|
||||
{
|
||||
// TODO: Hint to use REL32
|
||||
return 0xFFFF;
|
||||
}
|
||||
void getModuleNativeEntryPointRange(IntPtr _this, ref void* pStart, ref void* pEnd)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче