Skip to content

Commit 719a4bd

Browse files
ARM64: Copy XDataAllocator implementation from ARM32 to get code working
1 parent e69b2fc commit 719a4bd

File tree

4 files changed

+126
-40
lines changed

4 files changed

+126
-40
lines changed

lib/Backend/Encoder.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,11 @@ Encoder::Encode()
329329
#ifdef _M_X64
330330
pdataCount = 1;
331331
xdataSize = (ushort)m_func->m_prologEncoder.SizeOfUnwindInfo();
332-
#elif _M_ARM
332+
#elif defined(_M_ARM32_OR_ARM64)
333+
#pragma warning(push)
334+
#pragma warning(disable:4244) // warning C4244: 'argument': conversion from 'ptrdiff_t' to 'DWORD', possible loss of data
333335
pdataCount = (ushort)m_func->m_unwindInfo.GetPDataCount(codeSize);
336+
#pragma warning(pop)
334337
xdataSize = (UnwindInfoManager::MaxXdataBytes + 3) * pdataCount;
335338
#else
336339
xdataSize = 0;

lib/Backend/arm64/LowerMD.cpp

Lines changed: 59 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,15 +1028,16 @@ IR::Instr *
10281028
LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
10291029
{
10301030

1031-
//IR::Instr *insertInstr = entryInstr->m_next;
1031+
IR::Instr *insertInstr = entryInstr->m_next;
10321032

10331033
// ARM64_WORKITEM
1034-
__debugbreak();
1034+
//__debugbreak();
10351035

1036-
#if 0
1036+
//#if 0
10371037

10381038
BYTE regEncode;
10391039
BOOL hasTry = this->m_func->HasTry();
1040+
AssertMsg(!hasTry, "ToDo (SaAgarwa): prolog not implemented for try");
10401041

10411042
// Begin recording info for later pdata/xdata emission.
10421043
UnwindInfoManager *unwindInfo = &this->m_func->m_unwindInfo;
@@ -1158,7 +1159,7 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
11581159
}
11591160
}
11601161

1161-
BVUnit32 usedDoubleRegs;
1162+
BVUnit usedDoubleRegs;
11621163
short doubleRegCount = 0;
11631164

11641165
if (!hasTry)
@@ -1176,8 +1177,11 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
11761177

11771178
if (doubleRegCount)
11781179
{
1180+
#pragma warning(push)
1181+
#pragma warning(disable:4244) // warning C4244: 'argument': conversion from 'UnitWord64' to 'DWORD', possible loss of data
11791182
BYTE lastDoubleReg = UnwindInfoManager::GetLastSavedReg(usedDoubleRegs.GetWord());
11801183
BYTE firstDoubleReg = UnwindInfoManager::GetFirstSavedReg(usedDoubleRegs.GetWord());
1184+
#pragma warning(pop)
11811185

11821186
// We do want to push all the double registers in a single VPUSH instructions
11831187
// This might cause us to VPUSH some registers which are not used
@@ -1202,7 +1206,10 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
12021206

12031207
if (doubleRegCount)
12041208
{
1209+
#pragma warning(push)
1210+
#pragma warning(disable:4244) // warning C4244: 'argument': conversion from 'UnitWord64' to 'DWORD', possible loss of data
12051211
unwindInfo->SetDoubleSavedRegList(usedDoubleRegs.GetWord());
1212+
#pragma warning(pop)
12061213
fpOffsetSize += (doubleRegCount * MachRegDouble);
12071214

12081215
//When there is try-catch we allocate registers even if there are no calls. For scenarios see Win8 487030.
@@ -1260,9 +1267,9 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
12601267
}
12611268
}
12621269

1263-
bool useDynamicStackProbe =
1270+
bool useDynamicStackProbe = false;/*
12641271
(m_func->GetJITFunctionBody()->DoInterruptProbe() || !m_func->GetThreadContextInfo()->IsThreadBound()) &&
1265-
!EncoderMD::CanEncodeModConst12(stackProbeStackHeight + Js::Constants::MinStackJIT);
1272+
!EncoderMD::CanEncodeModConst12(stackProbeStackHeight + Js::Constants::MinStackJIT);*/
12661273

12671274
if (useDynamicStackProbe && !hasCalls)
12681275
{
@@ -1344,16 +1351,26 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
13441351
GenerateStackProbe(insertInstr, false); //stack is already aligned in this case
13451352
}
13461353

1347-
IR::RegOpnd * r12Opnd = nullptr;
1354+
IR::RegOpnd * r17Opnd = nullptr;
1355+
1356+
/*
1357+
Homed arguments (r0-r7)
1358+
Callee-Saved float Registers (d16-d29)
1359+
Callee-Saved Int Registers (r19-r28)
1360+
Local Variables
1361+
lr - link Register (r30)
1362+
fp - Frame Pointer (r29)
1363+
alloca area
1364+
*/
13481365

13491366
// Zero-initialize dedicated arguments slot
13501367
if (hasCalls)
13511368
{
1352-
//R12 acts a dummy zero register which we push to arguments slot
1353-
//mov r12, 0
1354-
Assert(r12Opnd == nullptr);
1355-
r12Opnd = IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachReg, this->m_func);
1356-
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, r12Opnd, IR::IntConstOpnd::New(0, TyMachReg, this->m_func), this->m_func);
1369+
//R17 acts a dummy zero register which we push to arguments slot
1370+
//mov r17, 0
1371+
Assert(r17Opnd == nullptr);
1372+
r17Opnd = IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachReg, this->m_func);
1373+
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, r17Opnd, IR::IntConstOpnd::New(0, TyMachReg, this->m_func), this->m_func);
13571374
insertInstr->InsertBefore(instrMov);
13581375
IR::LabelInstr *prologStartLabel = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
13591376
insertInstr->InsertBefore(prologStartLabel);
@@ -1362,37 +1379,51 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
13621379

13631380
if (!paramRegs.IsEmpty())
13641381
{
1382+
for (int i = LAST_INT_ARG_REG; i >= FIRST_INT_ARG_REG; --i)
1383+
{
1384+
RegNum reg = (RegNum)(i);
1385+
if (paramRegs.Test(RegEncode[reg]))
1386+
{
1387+
IR::Instr * instrStore = IR::Instr::New(Js::OpCode::STR, this->m_func);
1388+
instrStore->SetDst(IR::IndirOpnd::New(IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func));
1389+
instrStore->SetSrc1(IR::RegOpnd::New(reg, TyMachReg, this->m_func));
1390+
insertInstr->InsertBefore(instrStore);
1391+
}
1392+
}
1393+
1394+
/*
13651395
// Generate PUSH {r0-r3}
1366-
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::PUSH, this->m_func);
1396+
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::STP, this->m_func);
13671397
instrPush->SetDst(IR::IndirOpnd::New(IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func));
13681398
instrPush->SetSrc1(IR::RegBVOpnd::New(paramRegs, TyMachReg, this->m_func));
13691399
insertInstr->InsertBefore(instrPush);
1400+
*/
13701401
}
13711402

13721403
// Setup Frame pointer
13731404
if (hasCalls)
13741405
{
13751406
BVUnit frameRegs;
1376-
frameRegs.Set(RegEncode[RegR11]);
1407+
frameRegs.Set(RegEncode[RegFP]);
13771408
frameRegs.Set(RegEncode[RegLR]);
13781409

13791410
// Generate PUSH {r11,lr}
1380-
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::PUSH, this->m_func);
1411+
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::STP, this->m_func);
13811412
instrPush->SetDst(IR::IndirOpnd::New(IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func));
13821413
instrPush->SetSrc1(IR::RegBVOpnd::New(frameRegs, TyMachReg, this->m_func));
13831414
insertInstr->InsertBefore(instrPush);
13841415

1385-
// Generate MOV r11,sp
1416+
// Generate MOV fp,sp
13861417
IR::RegOpnd* spOpnd = IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func);
1387-
IR::RegOpnd* r11Opnd = IR::RegOpnd::New(nullptr, RegR11, TyMachReg, this->m_func);
1418+
IR::RegOpnd* r11Opnd = IR::RegOpnd::New(nullptr, RegFP, TyMachReg, this->m_func);
13881419
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, r11Opnd, spOpnd, this->m_func);
13891420
insertInstr->InsertBefore(instrMov);
13901421
}
13911422

13921423
if (!usedRegs.IsEmpty())
13931424
{
13941425
// Generate PUSH {r4-r10,r12}
1395-
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::PUSH, this->m_func);
1426+
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::STP, this->m_func);
13961427
instrPush->SetDst(IR::IndirOpnd::New(IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func));
13971428
instrPush->SetSrc1(IR::RegBVOpnd::New(usedRegs, TyMachReg, this->m_func));
13981429
insertInstr->InsertBefore(instrPush);
@@ -1401,7 +1432,7 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
14011432
if (!usedDoubleRegs.IsEmpty())
14021433
{
14031434
// Generate VPUSH {d8-d15}
1404-
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::VPUSH, this->m_func);
1435+
IR::Instr * instrPush = IR::Instr::New(Js::OpCode::STP64, this->m_func);
14051436
instrPush->SetDst(IR::IndirOpnd::New(IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func));
14061437
instrPush->SetSrc1(IR::RegBVOpnd::New(usedDoubleRegs, TyMachReg, this->m_func));
14071438
insertInstr->InsertBefore(instrPush);
@@ -1451,7 +1482,7 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
14511482
ehReg.Set(RegEncode[EH_STACK_SAVE_REG]);
14521483
IR::Instr * instrPush =
14531484
IR::Instr::New(
1454-
Js::OpCode::PUSH,
1485+
Js::OpCode::STP,
14551486
IR::IndirOpnd::New(
14561487
IR::RegOpnd::New(nullptr, RegSP, TyMachReg, this->m_func), (int32)0, TyMachReg, this->m_func),
14571488
IR::RegBVOpnd::New(ehReg, TyMachReg, this->m_func),
@@ -1472,11 +1503,11 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
14721503
if (m_func->GetMaxInlineeArgOutSize() != 0)
14731504
{
14741505
// This is done post prolog. so we don't have to emit unwind data.
1475-
if (r12Opnd == nullptr || isScratchRegisterThrashed)
1506+
if (r17Opnd == nullptr || isScratchRegisterThrashed)
14761507
{
1477-
r12Opnd = r12Opnd ? r12Opnd : IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachReg, this->m_func);
1508+
r17Opnd = r17Opnd ? r17Opnd : IR::RegOpnd::New(nullptr, SCRATCH_REG, TyMachReg, this->m_func);
14781509
// mov r12, 0
1479-
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, r12Opnd, IR::IntConstOpnd::New(0, TyMachReg, this->m_func), this->m_func);
1510+
IR::Instr * instrMov = IR::Instr::New(Js::OpCode::MOV, r17Opnd, IR::IntConstOpnd::New(0, TyMachReg, this->m_func), this->m_func);
14801511
insertInstr->InsertBefore(instrMov);
14811512
}
14821513

@@ -1487,7 +1518,7 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
14871518
IR::Opnd *dst = IR::SymOpnd::New(sym, 0, TyMachReg, this->m_func);
14881519
insertInstr->InsertBefore(IR::Instr::New(Js::OpCode::STR,
14891520
dst,
1490-
r12Opnd,
1521+
r17Opnd,
14911522
this->m_func));
14921523
}
14931524

@@ -1497,7 +1528,7 @@ LowererMD::LowerEntryInstr(IR::EntryInstr * entryInstr)
14971528
{
14981529
GenerateStackProbe(insertInstr, true); //stack is already aligned in this case
14991530
}
1500-
#endif
1531+
//#endif
15011532

15021533
return entryInstr;
15031534
}
@@ -1506,7 +1537,7 @@ IR::Instr *
15061537
LowererMD::LowerExitInstr(IR::ExitInstr * exitInstr)
15071538
{
15081539
// ARM64_WORKITEM
1509-
__debugbreak();
1540+
//__debugbreak();
15101541

15111542
#if 0
15121543

@@ -1549,7 +1580,7 @@ LowererMD::LowerExitInstr(IR::ExitInstr * exitInstr)
15491580

15501581
// Record used callee-saved registers. This is in the form of a fixed bitfield.
15511582

1552-
BVUnit32 usedRegs;
1583+
BVUnit usedRegs;
15531584
for (RegNum reg = FIRST_CALLEE_SAVED_GP_REG; reg <= LAST_CALLEE_SAVED_GP_REG; reg = (RegNum)(reg+1))
15541585
{
15551586
Assert(LinearScan::IsCalleeSaved(reg));
@@ -1616,7 +1647,7 @@ LowererMD::LowerExitInstr(IR::ExitInstr * exitInstr)
16161647
}
16171648

16181649
// 2. Restore saved double registers. Generate vpop {d8-d15}
1619-
BVUnit32 savedDoubleRegs(this->m_func->m_unwindInfo.GetDoubleSavedRegList());
1650+
BVUnit savedDoubleRegs(this->m_func->m_unwindInfo.GetDoubleSavedRegList());
16201651
if (!savedDoubleRegs.IsEmpty())
16211652
{
16221653
IR::Instr * instrVPop = IR::Instr::New(Js::OpCode::VPOP, this->m_func);

lib/Common/Memory/arm64/XDataAllocator.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,101 @@ CompileAssert(false)
1111
#include "XDataAllocator.h"
1212
#include "Core/DelayLoadLibrary.h"
1313

14+
// ToDo (SaAgarwa): Everything here is copied from arm32. Validate that this is correct
15+
1416
XDataAllocator::XDataAllocator(BYTE* address, uint size)
1517
{
16-
__debugbreak();
18+
Assert(size == 0);
1719
}
1820

1921

2022
void XDataAllocator::Delete()
2123
{
22-
__debugbreak();
24+
HeapDelete(this);
2325
}
2426

2527
bool XDataAllocator::Initialize(void* segmentStart, void* segmentEnd)
2628
{
27-
__debugbreak();
2829
return true;
2930
}
3031

3132
bool XDataAllocator::Alloc(ULONG_PTR functionStart, DWORD functionSize, ushort pdataCount, ushort xdataSize, SecondaryAllocation* allocation)
3233
{
33-
__debugbreak();
34-
return false;
34+
XDataAllocation* xdata = static_cast<XDataAllocation*>(allocation);
35+
Assert(pdataCount > 0);
36+
Assert(xdataSize >= 0);
37+
Assert(xdata);
38+
39+
DWORD size = GetAllocSize(pdataCount, xdataSize);
40+
BYTE* alloc = HeapNewNoThrowArray(BYTE, size);
41+
if (alloc != nullptr)
42+
{
43+
xdata->address = alloc;
44+
xdata->xdataSize = xdataSize;
45+
xdata->pdataCount = pdataCount;
46+
47+
return true; //success
48+
}
49+
return false; //fail;
3550
}
3651

3752

3853
void XDataAllocator::Release(const SecondaryAllocation& allocation)
3954
{
40-
__debugbreak();
55+
const XDataAllocation& xdata = static_cast<const XDataAllocation&>(allocation);
56+
if (xdata.address != nullptr)
57+
{
58+
HeapDeleteArray(GetAllocSize(xdata.pdataCount, xdata.xdataSize), xdata.address);
59+
}
4160
}
4261

4362
/* static */
4463
void XDataAllocator::Register(XDataAllocation * xdataInfo, intptr_t functionStart, DWORD functionSize)
4564
{
46-
__debugbreak();
65+
#ifdef _WIN32
66+
RUNTIME_FUNCTION* pdataArray = xdataInfo->GetPdataArray();
67+
for (ushort i = 0; i < xdataInfo->pdataCount; i++)
68+
{
69+
RUNTIME_FUNCTION* pdata = pdataArray + i;
70+
Assert(pdata->UnwindData != 0);
71+
Assert(pdata->BeginAddress != 0);
72+
pdata->BeginAddress = pdata->BeginAddress - (DWORD)functionStart;
73+
if (pdata->Flag != 1) // if it is not packed unwind data
74+
{
75+
pdata->UnwindData = pdata->UnwindData - (DWORD)functionStart;
76+
}
77+
}
78+
Assert(xdataInfo->functionTable == nullptr);
79+
80+
// Since we do not expect many thunk functions to be created, we are using 1 table/function
81+
// for now. This can be optimized further if needed.
82+
DWORD status = NtdllLibrary::Instance->AddGrowableFunctionTable(&xdataInfo->functionTable,
83+
pdataArray,
84+
/*MaxEntryCount*/ xdataInfo->pdataCount,
85+
/*Valid entry count*/ xdataInfo->pdataCount,
86+
/*RangeBase*/ functionStart,
87+
/*RangeEnd*/ functionStart + functionSize);
88+
89+
Js::Throw::CheckAndThrowOutOfMemory(NT_SUCCESS(status));
90+
91+
#else // !_WIN32
92+
Assert(ReadHead(xdataInfo->address)); // should be non-empty .eh_frame
93+
__REGISTER_FRAME(xdataInfo->address);
94+
#endif
4795
}
4896

4997
/* static */
5098
void XDataAllocator::Unregister(XDataAllocation * xdataInfo)
5199
{
52-
__debugbreak();
100+
#ifdef _WIN32
101+
NtdllLibrary::Instance->DeleteGrowableFunctionTable(xdataInfo->functionTable);
102+
#else // !_WIN32
103+
Assert(ReadHead(xdataInfo->address)); // should be non-empty .eh_frame
104+
__DEREGISTER_FRAME(xdataInfo->address);
105+
#endif
53106
}
54107

55108
bool XDataAllocator::CanAllocate()
56109
{
57-
__debugbreak();
58110
return true;
59111
}

lib/Common/Memory/arm64/XDataAllocator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ class XDataAllocator sealed : public SecondaryAllocator
5656
bool CanAllocate();
5757
static DWORD GetAllocSize(ushort pdataCount, ushort xdataSize)
5858
{
59-
__debugbreak();
60-
return 0;
59+
// ToDo (SaAgarwa): Copied from arm32, validate that this is correct for arm64
60+
return sizeof(RUNTIME_FUNCTION) * pdataCount + xdataSize;
6161
}
6262

6363
static void Register(XDataAllocation * xdataInfo, intptr_t functionStart, DWORD functionSize);

0 commit comments

Comments
 (0)