Skip to content

Commit aee7f39

Browse files
author
Meghana Gupta
committed
Add jit support for x64 load and store index out of bounds
Out of bound memory access in Wasm traps. Code to insert relevant checks and error is added in the interpreter and jit. Wasm provides an offset + index addressing mode for memory accesses. We represent this using an int64 to address problems with wrapping due to overflow. Also new opcode LdArrViewElemWasm is added specially for wasm since we cannot use LdArrViewElem of AsmJs which is side-effect free.
1 parent 2f3b2ff commit aee7f39

25 files changed

+426
-36
lines changed

lib/Backend/IRBuilderAsmJs.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,8 @@ IRBuilderAsmJs::BuildAsmTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, uint3
14261426
{
14271427
IRType type = TyInt32;
14281428
bool isLd = newOpcode == Js::OpCodeAsmJs::LdArr || newOpcode == Js::OpCodeAsmJs::LdArrWasm || newOpcode == Js::OpCodeAsmJs::LdArrConst;
1429-
Js::OpCode op = isLd ? Js::OpCode::LdArrViewElem : Js::OpCode::StArrViewElem;
1429+
Js::OpCode op = isLd ? (this->m_func->GetJITFunctionBody()->IsWasmFunction() ?
1430+
Js::OpCode::LdArrViewElemWasm : Js::OpCode::LdArrViewElem) : Js::OpCode::StArrViewElem;
14301431
ValueType arrayType;
14311432
WAsmJs::Types valueRegType = WAsmJs::INT32;
14321433

@@ -1494,7 +1495,7 @@ IRBuilderAsmJs::BuildAsmTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, uint3
14941495
IR::IndirOpnd * indirOpnd = nullptr;
14951496

14961497
// Get the index
1497-
if (newOpcode == Js::OpCodeAsmJs::LdArr || newOpcode == Js::OpCodeAsmJs::StArr || newOpcode == Js::OpCodeAsmJs::LdArrWasm || newOpcode == Js::OpCodeAsmJs::StArrWasm)
1498+
if (newOpcode == Js::OpCodeAsmJs::LdArr || newOpcode == Js::OpCodeAsmJs::StArr)
14981499
{
14991500
uint32 mask = Js::ArrayBufferView::ViewMask[viewType];
15001501
Js::RegSlot indexRegSlot = GetRegSlotFromIntReg(slotIndex);
@@ -1512,6 +1513,13 @@ IRBuilderAsmJs::BuildAsmTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, uint3
15121513
indirOpnd = IR::IndirOpnd::New(BuildSrcOpnd(AsmJsRegSlots::BufferReg, TyVar), maskedOpnd, type, m_func);
15131514
indirOpnd->GetBaseOpnd()->SetValueType(arrayType);
15141515
}
1516+
else if (newOpcode == Js::OpCodeAsmJs::LdArrWasm || newOpcode == Js::OpCodeAsmJs::StArrWasm)
1517+
{
1518+
Js::RegSlot indexRegSlot = GetRegSlotFromInt64Reg(slotIndex);
1519+
IR::RegOpnd * maskedOpnd = BuildSrcOpnd(indexRegSlot, TyUint64);
1520+
indirOpnd = IR::IndirOpnd::New(BuildSrcOpnd(AsmJsRegSlots::BufferReg, TyVar), maskedOpnd, type, m_func);
1521+
indirOpnd->GetBaseOpnd()->SetValueType(arrayType);
1522+
}
15151523
else
15161524
{
15171525
Assert(newOpcode == Js::OpCodeAsmJs::LdArrConst || newOpcode == Js::OpCodeAsmJs::StArrConst);
@@ -1552,6 +1560,11 @@ IRBuilderAsmJs::BuildAsmTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, uint3
15521560

15531561
#if _M_IX86 || !_WIN32
15541562
instr->SetSrc2(BuildSrcOpnd(AsmJsRegSlots::LengthReg, TyUint32));
1563+
#else
1564+
if (this->m_func->GetJITFunctionBody()->IsWasmFunction())
1565+
{
1566+
instr->SetSrc2(BuildSrcOpnd(AsmJsRegSlots::LengthReg, TyUint32));
1567+
}
15551568
#endif
15561569
AddInstr(instr, offset);
15571570
}
@@ -3108,11 +3121,11 @@ IRBuilderAsmJs::BuildLong1Int1(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::Reg
31083121
IR::RegOpnd * srcOpnd = nullptr;
31093122
switch (newOpcode)
31103123
{
3111-
case Js::OpCodeAsmJs::Conv_ITD:
3124+
case Js::OpCodeAsmJs::Conv_ITL:
31123125
srcOpnd = BuildSrcOpnd(srcRegSlot, TyInt32);
31133126
break;
31143127

3115-
case Js::OpCodeAsmJs::Conv_UTD:
3128+
case Js::OpCodeAsmJs::Conv_UTL:
31163129
srcOpnd = BuildSrcOpnd(srcRegSlot, TyUint32);
31173130
break;
31183131

lib/Backend/Lower.cpp

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,10 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
15591559
instrPrev = LowerStArrViewElem(instr);
15601560
break;
15611561

1562+
case Js::OpCode::LdArrViewElemWasm:
1563+
instrPrev = LowerLdArrViewElemWasm(instr);
1564+
break;
1565+
15621566
case Js::OpCode::Memset:
15631567
case Js::OpCode::Memcopy:
15641568
{
@@ -1914,6 +1918,21 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
19141918
m_lowererMD.EmitFloat32ToFloat64(instr->GetDst(), instr->GetSrc1(), instr);
19151919
}
19161920
}
1921+
else if (instr->GetDst()->IsInt64())
1922+
{
1923+
if (instr->GetSrc1()->IsInt32())
1924+
{
1925+
m_lowererMD.EmitIntToLong(instr->GetDst(), instr->GetSrc1(), instr);
1926+
}
1927+
else if (instr->GetSrc1()->IsUInt32())
1928+
{
1929+
m_lowererMD.EmitUIntToLong(instr->GetDst(), instr->GetSrc1(), instr);
1930+
}
1931+
else
1932+
{
1933+
Assert(0);
1934+
}
1935+
}
19171936
else
19181937
{
19191938
Assert(instr->GetDst()->IsInt32());
@@ -8870,6 +8889,44 @@ Lowerer::LowerLdArrViewElem(IR::Instr * instr)
88708889
#endif
88718890
}
88728891

8892+
IR::Instr *
8893+
Lowerer::LowerLdArrViewElemWasm(IR::Instr * instr)
8894+
{
8895+
#ifdef ASMJS_PLAT
8896+
Assert(m_func->GetJITFunctionBody()->IsWasmFunction());
8897+
Assert(instr);
8898+
Assert(instr->m_opcode == Js::OpCode::LdArrViewElemWasm);
8899+
8900+
IR::Instr * instrPrev = instr->m_prev;
8901+
8902+
IR::Opnd * dst = instr->GetDst();
8903+
IR::Opnd * src1 = instr->GetSrc1();
8904+
8905+
IR::Instr * done;
8906+
8907+
Assert(!dst->IsFloat32() || src1->IsFloat32());
8908+
Assert(!dst->IsFloat64() || src1->IsFloat64());
8909+
done = m_lowererMD.LowerWasmMemOp(instr, src1);
8910+
8911+
if (dst->IsInt64())
8912+
{
8913+
IR::Instr* movInt64 = IR::Instr::New(Js::OpCode::Ld_I4, dst, src1, m_func);
8914+
done->InsertBefore(movInt64);
8915+
m_lowererMD.LowerInt64Assign(movInt64);
8916+
}
8917+
else
8918+
{
8919+
InsertMove(dst, src1, done);
8920+
}
8921+
8922+
instr->Remove();
8923+
return instrPrev;
8924+
#else
8925+
Assert(UNREACHED);
8926+
return instr;
8927+
#endif
8928+
}
8929+
88738930
IR::Instr *
88748931
Lowerer::LowerMemset(IR::Instr * instr, IR::RegOpnd * helperRet)
88758932
{
@@ -9045,7 +9102,12 @@ Lowerer::LowerStArrViewElem(IR::Instr * instr)
90459102
Assert(!dst->IsInt64() || src1->IsInt64());
90469103

90479104
IR::Instr * done;
9048-
if (indexOpnd || m_func->GetJITFunctionBody()->GetAsmJsInfo()->AccessNeedsBoundCheck((uint32)dst->AsIndirOpnd()->GetOffset()))
9105+
9106+
if (m_func->GetJITFunctionBody()->IsWasmFunction())
9107+
{
9108+
done = m_lowererMD.LowerWasmMemOp(instr, dst);
9109+
}
9110+
else if (indexOpnd || m_func->GetJITFunctionBody()->GetAsmJsInfo()->AccessNeedsBoundCheck((uint32)dst->AsIndirOpnd()->GetOffset()))
90499111
{
90509112
// CMP indexOpnd, src2(arrSize)
90519113
// JA $helper
@@ -9055,7 +9117,6 @@ Lowerer::LowerStArrViewElem(IR::Instr * instr)
90559117
// $store:
90569118
// MOV dst([arrayBuffer + indexOpnd]), src1
90579119
// $done:
9058-
90599120
done = m_lowererMD.LowerAsmJsStElemHelper(instr);
90609121
}
90619122
else

lib/Backend/Lower.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class Lowerer
174174

175175
IR::Instr * LowerLdArrViewElem(IR::Instr * instr);
176176
IR::Instr * LowerStArrViewElem(IR::Instr * instr);
177+
IR::Instr * LowerLdArrViewElemWasm(IR::Instr * instr);
177178
IR::Instr * LowerArrayDetachedCheck(IR::Instr * instr);
178179
IR::Instr * LowerDeleteElemI(IR::Instr *instr, bool strictMode);
179180
IR::Instr * LowerStElemC(IR::Instr *instr);

lib/Backend/LowerMDShared.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,12 @@ LowererMD::LowerAsmJsCallE(IR::Instr * callInstr)
267267
return this->lowererMDArch.LowerAsmJsCallE(callInstr);
268268
}
269269

270+
IR::Instr *
271+
LowererMD::LowerWasmMemOp(IR::Instr * instr, IR::Opnd *addrOpnd)
272+
{
273+
return this->lowererMDArch.LowerWasmMemOp(instr, addrOpnd);
274+
}
275+
270276
IR::Instr *
271277
LowererMD::LowerAsmJsLdElemHelper(IR::Instr * callInstr)
272278
{
@@ -7899,6 +7905,18 @@ LowererMD::EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
78997905
this->lowererMDArch.EmitUIntToFloat(dst, src, instrInsert);
79007906
}
79017907

7908+
void
7909+
LowererMD::EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
7910+
{
7911+
this->lowererMDArch.EmitIntToLong(dst, src, instrInsert);
7912+
}
7913+
7914+
void
7915+
LowererMD::EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
7916+
{
7917+
this->lowererMDArch.EmitUIntToLong(dst, src, instrInsert);
7918+
}
7919+
79027920
void
79037921
LowererMD::EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
79047922
{

lib/Backend/LowerMDShared.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class LowererMD
104104
IR::Instr * LoadFunctionObjectOpnd(IR::Instr *instr, IR::Opnd *&functionObjOpnd);
105105
IR::Instr * LowerLdSuper(IR::Instr *instr, IR::JnHelperMethod helperOpCode);
106106
IR::Instr * LowerNewScObject(IR::Instr *newObjInstr);
107+
IR::Instr * LowerWasmMemOp(IR::Instr *instr, IR::Opnd *addrOpnd);
107108
void ForceDstToReg(IR::Instr *instr);
108109

109110
public:
@@ -208,6 +209,8 @@ class LowererMD
208209
bool EmitLoadInt32(IR::Instr *instr, bool conversionFromObjectAllowed);
209210
void EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
210211
void EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
212+
void EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
213+
void EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
211214
void EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
212215
void EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
213216
static IR::Instr *InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr);

lib/Backend/amd64/LowererMDArch.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,30 @@ LowererMDArch::LowerAsmJsCallI(IR::Instr * callInstr)
11171117
return ret;
11181118
}
11191119

1120+
IR::Instr *
1121+
LowererMDArch::LowerWasmMemOp(IR::Instr * instr, IR::Opnd *addrOpnd)
1122+
{
1123+
Assert(instr->GetSrc2());
1124+
1125+
IR::LabelInstr * helperLabel = Lowerer::InsertLabel(true, instr);
1126+
IR::LabelInstr * loadLabel = Lowerer::InsertLabel(false, instr);
1127+
IR::LabelInstr * doneLabel = Lowerer::InsertLabel(false, instr);
1128+
1129+
// Find array buffer length
1130+
IR::RegOpnd * indexOpnd = addrOpnd->AsIndirOpnd()->GetIndexOpnd();
1131+
IR::Opnd *arrayLenOpnd = instr->GetSrc2();
1132+
1133+
// Compare index + memop access length and array buffer length, and generate RuntimeError if greater
1134+
IR::Opnd *cmpOpnd = IR::RegOpnd::New(TyUint64, m_func);
1135+
Lowerer::InsertAdd(true, cmpOpnd, indexOpnd, IR::IntConstOpnd::New(addrOpnd->GetSize(), TyUint64, m_func), helperLabel);
1136+
lowererMD->m_lowerer->InsertCompareBranch(cmpOpnd, arrayLenOpnd, Js::OpCode::BrGt_A, true, helperLabel, helperLabel);
1137+
1138+
// MGTODO : call RuntimeError once implemented
1139+
lowererMD->m_lowerer->GenerateRuntimeError(loadLabel, JSERR_InvalidTypedArrayIndex, IR::HelperOp_RuntimeRangeError);
1140+
Lowerer::InsertBranch(Js::OpCode::Br, loadLabel, helperLabel);
1141+
return doneLabel;
1142+
}
1143+
11201144
IR::Instr*
11211145
LowererMDArch::LowerAsmJsLdElemHelper(IR::Instr * instr, bool isSimdLoad /*= false*/, bool checkEndOffset /*= false*/)
11221146
{
@@ -2541,6 +2565,36 @@ LowererMDArch::EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInse
25412565
}
25422566
}
25432567

2568+
void
2569+
LowererMDArch::EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
2570+
{
2571+
Assert(dst->IsRegOpnd() && dst->IsInt64());
2572+
Assert(src->IsInt32());
2573+
2574+
if (src->IsIntConstOpnd())
2575+
{
2576+
Lowerer::InsertMove(dst, src, instrInsert);
2577+
return;
2578+
}
2579+
Assert(src->IsRegOpnd());
2580+
instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::MOVSXD, dst, src, this->m_func));
2581+
}
2582+
2583+
void
2584+
LowererMDArch::EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
2585+
{
2586+
Assert(dst->IsRegOpnd() && dst->IsInt64());
2587+
Assert(src->IsUInt32());
2588+
2589+
if (src->IsIntConstOpnd())
2590+
{
2591+
Lowerer::InsertMove(dst, src, instrInsert);
2592+
return;
2593+
}
2594+
Assert(src->IsRegOpnd());
2595+
instrInsert->InsertBefore(IR::Instr::New(Js::OpCode::MOV, dst, src, this->m_func));
2596+
}
2597+
25442598
void
25452599
LowererMDArch::EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
25462600
{

lib/Backend/amd64/LowererMDArch.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class LowererMDArch
6969
IR::Instr * LowerStartCall(IR::Instr * instr);
7070
IR::Instr * LowerAsmJsCallI(IR::Instr * callInstr);
7171
IR::Instr * LowerAsmJsCallE(IR::Instr * callInstr);
72-
72+
IR::Instr * LowerWasmMemOp(IR::Instr * instr, IR::Opnd *addrOpnd);
7373
IR::Instr * LowerAsmJsLdElemHelper(IR::Instr * instr, bool isSimdLoad = false, bool checkEndOffset = false);
7474
IR::Instr * LowerAsmJsStElemHelper(IR::Instr * instr, bool isSimdStore = false, bool checkEndOffset = false);
7575

@@ -94,6 +94,8 @@ class LowererMDArch
9494
void EmitLoadVar(IR::Instr *instrLoad, bool isFromUint32 = false, bool isHelper = false);
9595
void EmitIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
9696
void EmitUIntToFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
97+
void EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
98+
void EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
9799
bool EmitLoadInt32(IR::Instr *instrLoad, bool conversionFromObjectAllowed);
98100

99101
IR::Instr * LoadCheckedFloat(IR::RegOpnd *opndOrig, IR::RegOpnd *opndFloat, IR::LabelInstr *labelInline, IR::LabelInstr *labelHelper, IR::Instr *instrInsert, const bool checkForNullInLoopBody = false);

lib/Backend/arm/LowerMD.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8842,6 +8842,18 @@ void LowererMD::ConvertFloatToInt32(IR::Opnd* intOpnd, IR::Opnd* floatOpnd, IR::
88428842
this->CheckOverflowOnFloatToInt32(instrInsert, intOpnd, labelHelper, labelDone);
88438843
}
88448844

8845+
void
8846+
LowererMD::EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
8847+
{
8848+
Assert(UNREACHED);
8849+
}
8850+
8851+
void
8852+
LowererMD::EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
8853+
{
8854+
Assert(UNREACHED);
8855+
}
8856+
88458857
void
88468858
LowererMD::CheckOverflowOnFloatToInt32(IR::Instr* instrInsert, IR::Opnd* intOpnd, IR::LabelInstr * labelHelper, IR::LabelInstr * labelDone)
88478859
{

lib/Backend/arm/LowerMD.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ class LowererMD
205205
void EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
206206
void EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert) { Assert(UNREACHED); }
207207
static IR::Instr * InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr);
208+
void EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
209+
void EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
208210
void EmitLoadFloatFromNumber(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr);
209211
IR::LabelInstr* EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool needHelperLabel);
210212
static IR::Instr * LoadFloatZero(IR::Opnd * opndDst, IR::Instr * instrInsert);

0 commit comments

Comments
 (0)