Get static string literal loads to work

This commit is contained in:
schellap 2015-10-09 01:17:37 -07:00
Родитель 27fa501f10
Коммит baa75f98ac
11 изменённых файлов: 337 добавлений и 46 удалений

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

@ -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(); }