Skip to content

Commit

Permalink
[MERGE #1959 @MikeHolman] Add WebAssembly.Table support
Browse files Browse the repository at this point in the history
Merge pull request #1959 from MikeHolman:wasmtable

Closes #1874
Closes #1876
Closes #1879
Closes #1879
  • Loading branch information
MikeHolman committed Nov 10, 2016
2 parents dbfe697 + c9014ef commit 6d3068e
Show file tree
Hide file tree
Showing 49 changed files with 1,083 additions and 375 deletions.
16 changes: 16 additions & 0 deletions lib/Backend/AsmJsJITInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ AsmJsJITInfo::GetArgType(Js::ArgSlot argNum) const
return GetArgTypeArray()[argNum];
}

#ifdef ENABLE_WASM
Wasm::WasmSignature *
AsmJsJITInfo::GetWasmSignature(uint index) const
{
Assert(index < m_data.wasmSignatureCount);
return Wasm::WasmSignature::FromIDL(&m_data.wasmSignatures[index]);
}

intptr_t
AsmJsJITInfo::GetWasmSignatureAddr(uint index) const
{
Assert(index < m_data.wasmSignatureCount);
return m_data.wasmSignaturesBaseAddr + index * sizeof(Wasm::WasmSignature);
}
#endif

bool
AsmJsJITInfo::IsHeapBufferConst() const
{
Expand Down
5 changes: 5 additions & 0 deletions lib/Backend/AsmJsJITInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class AsmJsJITInfo
Js::AsmJsVarType::Which * GetArgTypeArray() const;
Js::AsmJsVarType::Which GetArgType(Js::ArgSlot argNum) const;

#ifdef ENABLE_WASM
Wasm::WasmSignature * GetWasmSignature(uint index) const;
intptr_t GetWasmSignatureAddr(uint index) const;
#endif

bool IsHeapBufferConst() const;
bool UsesHeapBuffer() const;
bool AccessNeedsBoundCheck(uint offset) const;
Expand Down
27 changes: 26 additions & 1 deletion lib/Backend/IRBuilderAsmJs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ IRBuilderAsmJs::BuildElementSlot(Js::OpCodeAsmJs newOpcode, uint32 offset, int32
{
Assert(OpCodeAttrAsmJs::HasMultiSizeLayout(newOpcode));

Assert(instance == 1 || newOpcode == Js::OpCodeAsmJs::LdArr_Func);
Assert(instance == 1 || newOpcode == Js::OpCodeAsmJs::LdArr_Func || newOpcode == Js::OpCodeAsmJs::LdArr_WasmFunc);

Js::RegSlot valueRegSlot;
IR::Opnd * slotOpnd;
Expand Down Expand Up @@ -1238,13 +1238,22 @@ IRBuilderAsmJs::BuildElementSlot(Js::OpCodeAsmJs newOpcode, uint32 offset, int32
{
IR::RegOpnd * baseOpnd = BuildSrcOpnd(GetRegSlotFromVarReg(instance), TyVar);
IR::RegOpnd * indexOpnd = BuildSrcOpnd(GetRegSlotFromIntReg(slotIndex), TyUint32);

IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(baseOpnd, indexOpnd, TyVar, m_func);

regOpnd = BuildDstOpnd(GetRegSlotFromVarReg(value), TyVar);
instr = IR::Instr::New(Js::OpCode::LdAsmJsFunc, regOpnd, indirOpnd, m_func);
break;
}
case Js::OpCodeAsmJs::LdArr_WasmFunc:
{
IR::RegOpnd * baseOpnd = BuildSrcOpnd(GetRegSlotFromVarReg(instance), TyVar);
IR::RegOpnd * indexOpnd = BuildSrcOpnd(GetRegSlotFromIntReg(slotIndex), TyUint32);

regOpnd = BuildDstOpnd(GetRegSlotFromVarReg(value), TyVar);
instr = IR::Instr::New(Js::OpCode::LdWasmFunc, regOpnd, baseOpnd, indexOpnd, m_func);
break;
}
case Js::OpCodeAsmJs::StSlot_Int:
case Js::OpCodeAsmJs::LdSlot_Int:
type = WAsmJs::INT32;
Expand Down Expand Up @@ -2179,6 +2188,22 @@ IRBuilderAsmJs::BuildInt1Const1(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::Re
AddInstr(instr, offset);
}

void
IRBuilderAsmJs::BuildReg1IntConst1(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::RegSlot reg1, int constInt)
{
Assert(newOpcode == Js::OpCodeAsmJs::CheckSignature);

IR::RegOpnd * funcReg = BuildSrcOpnd(reg1, TyMachPtr);

IR::IntConstOpnd * sigIndex = IR::IntConstOpnd::New(constInt, TyInt32, m_func);

IR::Instr * instr = IR::Instr::New(Js::OpCode::CheckWasmSignature, m_func);
instr->SetSrc1(funcReg);
instr->SetSrc2(sigIndex);

AddInstr(instr, offset);
}

void
IRBuilderAsmJs::BuildFloat1Const1(Js::OpCodeAsmJs newOpcode, uint32 offset, Js::RegSlot dstRegSlot, float constVal)
{
Expand Down
9 changes: 9 additions & 0 deletions lib/Backend/JITTimeFunctionBody.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ JITTimeFunctionBody::InitializeJITFunctionData(
jitBody->asmJsData->isHeapBufferConst = asmFuncInfo->IsHeapBufferConst();
jitBody->asmJsData->usesHeapBuffer = asmFuncInfo->UsesHeapBuffer();
jitBody->asmJsData->totalSizeInBytes = asmFuncInfo->GetTotalSizeinBytes();

#ifdef ENABLE_WASM
if (functionBody->IsWasmFunction())
{
jitBody->asmJsData->wasmSignatureCount = asmFuncInfo->GetWebAssemblyModule()->GetSignatureCount();
jitBody->asmJsData->wasmSignaturesBaseAddr = (intptr_t)asmFuncInfo->GetWebAssemblyModule()->GetSignatures();
jitBody->asmJsData->wasmSignatures = (WasmSignatureIDL*)asmFuncInfo->GetWebAssemblyModule()->GetSignatures();
}
#endif
}
#endif
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/JnHelperMethodList.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ HELPERCALL(Op_TypeofElem_Int32, Js::JavascriptOperators::TypeofElem_Int32, 0)
HELPERCALL(Op_TypeofPropertyScoped, Js::JavascriptOperators::OP_TypeofPropertyScoped, 0)
HELPERCALL(Op_Rem_Double, Js::NumberUtilities::Modulus, 0)

#ifdef ENABLE_WASM
HELPERCALL(Op_CheckWasmSignature, Js::WebAssembly::CheckSignature, AttrCanThrow)
#endif

HELPERCALL_FULL_OR_INPLACE_MATH(Op_Increment, Js::JavascriptMath::Increment, Js::SSE2::JavascriptMath::Increment, AttrCanThrow)
HELPERCALL_FULL_OR_INPLACE_MATH(Op_Decrement, Js::JavascriptMath::Decrement, Js::SSE2::JavascriptMath::Decrement, AttrCanThrow)
HELPERCALL_FULL_OR_INPLACE_MATH(Op_Negate, Js::JavascriptMath::Negate, Js::SSE2::JavascriptMath::Negate, AttrCanThrow)
Expand Down
104 changes: 103 additions & 1 deletion lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1809,6 +1809,14 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
this->LowerUnaryHelper(instr, IR::HelperOp_UnwrapWithObj);
break;

#ifdef ENABLE_WASM
case Js::OpCode::CheckWasmSignature:
this->LowerCheckWasmSignature(instr);
break;
case Js::OpCode::LdWasmFunc:
instrPrev = this->LowerLdWasmFunc(instr);
break;
#endif
case Js::OpCode::LdAsmJsFunc:
if (instr->GetSrc1()->IsIndirOpnd())
{
Expand All @@ -1831,7 +1839,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
indir->SetScale(scale);
}
}
// Fallthrough
//fallthrough
case Js::OpCode::Ld_I4:
case Js::OpCode::Ld_A:
case Js::OpCode::InitConst:
Expand Down Expand Up @@ -8179,6 +8187,100 @@ Lowerer::LoadArgumentsFromFrame(IR::Instr *const instr)
}
}

#ifdef ENABLE_WASM
IR::Instr *
Lowerer::LowerCheckWasmSignature(IR::Instr * instr)
{
Assert(m_func->GetJITFunctionBody()->IsWasmFunction());
Assert(instr->GetSrc1());
Assert(instr->GetSrc2()->IsIntConstOpnd());

int sigId = instr->UnlinkSrc2()->AsIntConstOpnd()->AsInt32();

IR::Instr *instrPrev = instr->m_prev;

IR::IndirOpnd * actualSig = IR::IndirOpnd::New(instr->UnlinkSrc1()->AsRegOpnd(), Js::AsmJsScriptFunction::GetOffsetOfSignature(), TyMachReg, m_func);

Wasm::WasmSignature * expectedSig = m_func->GetJITFunctionBody()->GetAsmJsInfo()->GetWasmSignature(sigId);
if (expectedSig->GetShortSig() == Js::Constants::InvalidSignature)
{
intptr_t sigAddr = m_func->GetJITFunctionBody()->GetAsmJsInfo()->GetWasmSignatureAddr(sigId);
IR::AddrOpnd * expectedOpnd = IR::AddrOpnd::New(sigAddr, IR::AddrOpndKindConstantAddress, m_func);
m_lowererMD.LoadHelperArgument(instr, expectedOpnd);
m_lowererMD.LoadHelperArgument(instr, actualSig);

LoadScriptContext(instr);

m_lowererMD.ChangeToHelperCall(instr, IR::HelperOp_CheckWasmSignature);
}
else
{
IR::LabelInstr * trapLabel = InsertLabel(true, instr);
IR::LabelInstr * labelFallThrough = InsertLabel(false, instr->m_next);
IR::RegOpnd * actualRegOpnd = IR::RegOpnd::New(TyMachReg, m_func);
InsertMove(actualRegOpnd, actualSig, trapLabel);

IR::IndirOpnd * shortSigIndir = IR::IndirOpnd::New(actualRegOpnd, Wasm::WasmSignature::GetOffsetOfShortSig(), TyMachReg, m_func);
InsertCompareBranch(shortSigIndir, IR::IntConstOpnd::New(expectedSig->GetShortSig(), TyMachReg, m_func), Js::OpCode::BrNeq_A, trapLabel, trapLabel);

InsertBranch(Js::OpCode::Br, labelFallThrough, trapLabel);

GenerateThrow(IR::IntConstOpnd::NewFromType(SCODE_CODE(WASMERR_SignatureMismatch), TyInt32, m_func), instr);

instr->Remove();

}


return instrPrev;
}

IR::Instr *
Lowerer::LowerLdWasmFunc(IR::Instr* instr)
{
IR::Instr * prev = instr->m_prev;

IR::RegOpnd * tableReg = instr->UnlinkSrc1()->AsRegOpnd();

IR::Opnd * indexOpnd = instr->UnlinkSrc2();
IR::Opnd * dst = instr->UnlinkDst();

IR::IndirOpnd * lengthOpnd = IR::IndirOpnd::New(tableReg, Js::WebAssemblyTable::GetOffsetOfCurrentLength(), TyUint32, m_func);
IR::IndirOpnd * valuesIndirOpnd = IR::IndirOpnd::New(tableReg, Js::WebAssemblyTable::GetOffsetOfValues(), TyMachPtr, m_func);
IR::RegOpnd * valuesRegOpnd = IR::RegOpnd::New(TyMachPtr, m_func);

byte scale = m_lowererMD.GetDefaultIndirScale();
IR::IndirOpnd * funcIndirOpnd;
if (indexOpnd->IsIntConstOpnd())
{
funcIndirOpnd = IR::IndirOpnd::New(valuesRegOpnd, indexOpnd->AsIntConstOpnd()->AsInt32() << scale, TyMachPtr, m_func);
}
else
{
Assert(indexOpnd->IsRegOpnd());
funcIndirOpnd = IR::IndirOpnd::New(valuesRegOpnd, indexOpnd->AsRegOpnd(), TyMachPtr, m_func);
funcIndirOpnd->SetScale(scale);
}

IR::LabelInstr * trapLabel = InsertLabel(true, instr);
IR::LabelInstr * doneLabel = InsertLabel(false, instr->m_next);
InsertCompareBranch(indexOpnd, lengthOpnd, Js::OpCode::BrGe_A, trapLabel, trapLabel);
InsertMove(valuesRegOpnd, valuesIndirOpnd, trapLabel);

InsertMove(dst, funcIndirOpnd, trapLabel);

InsertCompareBranch(dst, IR::IntConstOpnd::New(0, TyMachPtr, m_func), Js::OpCode::BrEq_A, trapLabel, trapLabel);
InsertBranch(Js::OpCode::Br, doneLabel, trapLabel);

GenerateThrow(IR::IntConstOpnd::NewFromType(SCODE_CODE(WASMERR_TableIndexOutOfRange), TyInt32, m_func), instr);

instr->Remove();

return prev;
}

#endif

IR::Instr *
Lowerer::LowerUnaryHelper(IR::Instr *instr, IR::JnHelperMethod helperMethod, IR::Opnd* opndBailoutArg)
{
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/Lower.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ class Lowerer
IR::JnHelperMethod helperMethodWithTemp, IR::JnHelperMethod helperMethodLeftDead);
IR::Instr * LowerAddLeftDeadForString(IR::Instr *instr);
IR::Instr * LowerBinaryHelper(IR::Instr *instr, IR::JnHelperMethod helperMethod);
#ifdef ENABLE_WASM
IR::Instr * LowerCheckWasmSignature(IR::Instr * instr);
IR::Instr * LowerLdWasmFunc(IR::Instr* instr);
#endif
IR::Instr * LowerInitCachedScope(IR::Instr * instr);
IR::Instr * LowerBrBReturn(IR::Instr * instr, IR::JnHelperMethod helperMethod, bool isHelper);
IR::Instr * LowerBrBMem(IR::Instr *instr, IR::JnHelperMethod helperMethod);
Expand Down
44 changes: 28 additions & 16 deletions lib/JITIDL/JITTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,28 @@ typedef struct StatementMapIDL
IDL_PAD2(0)
} StatementMapIDL;

typedef struct WasmSignatureIDL
{
int resultType;
unsigned int id;
unsigned int paramSize;
unsigned int paramsCount;
CHAKRA_PTR shortSig;
IDL_DEF([size_is(paramsCount)]) int * params;
} WasmSignatureIDL;

typedef struct TypedSlotInfo
{
boolean isValidType;
IDL_PAD1(0)
IDL_PAD2(1)
unsigned int constCount;
unsigned int varCount;
unsigned int tmpCount;
unsigned int byteOffset;
unsigned int constSrcByteOffset;
} TypedSlotInfo;

typedef struct AsmJsDataIDL
{
boolean isHeapBufferConst;
Expand All @@ -376,16 +398,12 @@ typedef struct AsmJsDataIDL
unsigned short argCount;
IDL_PAD2(0)
int retType;
struct TypedSlotInfo
{
unsigned int constCount;
unsigned int varCount;
unsigned int tmpCount;
unsigned int byteOffset;
unsigned int constSrcByteOffset;
boolean isValidType;
} typedSlotInfos[5];
int totalSizeInBytes;
unsigned int wasmSignatureCount;
X64_PAD4(1)
TypedSlotInfo typedSlotInfos[5];
CHAKRA_PTR wasmSignaturesBaseAddr;
IDL_DEF([size_is(wasmSignatureCount)]) WasmSignatureIDL * wasmSignatures;
IDL_DEF([size_is(argCount)]) byte * argTypeArray;
} AsmJsDataIDL;

Expand Down Expand Up @@ -467,18 +485,12 @@ typedef struct FunctionBodyDataIDL
boolean hasFinally;
boolean usesArgumentsObject;
boolean doScopeObjectCreation;
#if defined(_M_IX86) || defined(_M_ARM)
IDL_PAD1(0)
#else
IDL_PAD1(0)
IDL_PAD2(1)
#endif

unsigned short envDepth;
unsigned short inParamCount;
unsigned short argUsedForBranch;
unsigned short profiledCallSiteCount;

IDL_PAD2(0)
unsigned int funcNumber;
unsigned int sourceContextId;
unsigned int nestedCount;
Expand Down
6 changes: 6 additions & 0 deletions lib/Parser/rterrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,9 @@ RT_ERROR_MSG(WASMERR_InvalidGlobalRef, 5673, "", "Global initialization does not
RT_ERROR_MSG(WASMERR_NeedMemoryObject, 5674, "%s is not a WebAssembly.Memory", "WebAssembly.Memory object expected", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_InvalidTypeConversion, 5675, "Invalid WebAssembly type conversion %s to %s", "Invalid WebAssembly type conversion", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_DivideByZero, 5676, "", "Division by zero", kjstError, 0)
RT_ERROR_MSG(WASMERR_ExpectedAnyFunc, 5677, "%s is not AnyFunc", "AnyFunc expected", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_NeedTableObject, 5678, "%s is not a WebAssembly.Table", "WebAssembly.Table object expected", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_NeedWebAssemblyFunc, 5679, "%s is not a WebAssembly exported function", "WebAssembly exported function expected", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_SignatureMismatch, 5680, "%s called with invalid signature", "Function called with invalid signature", kjstWebAssemblyRuntimeError, 0)
RT_ERROR_MSG(WASMERR_ElementSegOutOfRange, 5681, "", "Element segment is out of range", kjstTypeError, 0)
RT_ERROR_MSG(WASMERR_TableIndexOutOfRange, 5682, "", "Table index is out of range", kjstWebAssemblyRuntimeError, 0)
1 change: 1 addition & 0 deletions lib/Runtime/Base/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace Js
static const uint UninitializedValue = (uint)-1;
static const ArgSlot InvalidArgSlot = (ArgSlot)-1;
static const uint32 InvalidSymID = (uint32)-1;
static const size_t InvalidSignature = (size_t)-1;

static const uint64 ExponentMask;
static const uint64 MantissaMask;
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/ByteCode/AsmJsByteCodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ namespace Js
break;
}
case OpCodeAsmJs::LdArr_Func:
case OpCodeAsmJs::LdArr_WasmFunc:
Output::Print(_u(" R%d = R%d[I%d]"), data->Value, data->Instance, data->SlotIndex);
break;
case OpCodeAsmJs::StSlot_Int:
Expand Down
17 changes: 17 additions & 0 deletions lib/Runtime/ByteCode/AsmJsByteCodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,18 @@ namespace Js
return false;
}

template <typename SizePolicy>
bool AsmJsByteCodeWriter::TryWriteReg1IntConst1(OpCodeAsmJs op, RegSlot R0, int C1)
{
OpLayoutT_Reg1IntConst1<SizePolicy> layout;
if (SizePolicy::Assign(layout.R0, R0) && SizePolicy::Assign(layout.C1, C1))
{
m_byteCodeData.EncodeT<SizePolicy::LayoutEnum>(op, &layout, sizeof(layout), this);
return true;
}
return false;
}

template <typename SizePolicy>
bool AsmJsByteCodeWriter::TryWriteLong1Const1(OpCodeAsmJs op, RegSlot R0, int64 C1)
{
Expand Down Expand Up @@ -387,6 +399,11 @@ namespace Js
MULTISIZE_LAYOUT_WRITE(Int1Const1, op, R0, C1);
}

void AsmJsByteCodeWriter::AsmReg1IntConst1(OpCodeAsmJs op, RegSlot R0, int C1)
{
MULTISIZE_LAYOUT_WRITE(Reg1IntConst1, op, R0, C1);
}

void AsmJsByteCodeWriter::AsmLong1Const1(OpCodeAsmJs op, RegSlot R0, int64 C1)
{
MULTISIZE_LAYOUT_WRITE(Long1Const1, op, R0, C1);
Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/ByteCode/AsmJsByteCodeWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Js
void EmptyAsm ( OpCodeAsmJs op );
void Conv ( OpCodeAsmJs op, RegSlot R0, RegSlot R1 );
void AsmInt1Const1 ( OpCodeAsmJs op, RegSlot R0, int C1 );
void AsmReg1IntConst1( OpCodeAsmJs op, RegSlot R0, int C1 );
void AsmLong1Const1 ( OpCodeAsmJs op, RegSlot R0, int64 C1 );
void AsmFloat1Const1 ( OpCodeAsmJs op, RegSlot R0, float C1 );
void AsmDouble1Const1( OpCodeAsmJs op, RegSlot R0, double C1 );
Expand Down Expand Up @@ -72,6 +73,7 @@ namespace Js
RegSlot R9, RegSlot R10, RegSlot R11, RegSlot R12, RegSlot R13, RegSlot R14, RegSlot R15, RegSlot R16, RegSlot R17, RegSlot R18);

template <typename SizePolicy> bool TryWriteInt1Const1 ( OpCodeAsmJs op, RegSlot R0, int C1 );
template <typename SizePolicy> bool TryWriteReg1IntConst1 ( OpCodeAsmJs op, RegSlot R0, int C1 );
template <typename SizePolicy> bool TryWriteLong1Const1 ( OpCodeAsmJs op, RegSlot R0, int64 C1 );
template <typename SizePolicy> bool TryWriteFloat1Const1 ( OpCodeAsmJs op, RegSlot R0, float C1 );
template <typename SizePolicy> bool TryWriteDouble1Const1 ( OpCodeAsmJs op, RegSlot R0, double C1 );
Expand Down
Loading

0 comments on commit 6d3068e

Please sign in to comment.