| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "WasmReaderPch.h"
- #ifdef ENABLE_WASM
- #include "WasmLimits.h"
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- #include "Codex/Utf8Helper.h"
- #endif
- namespace Wasm
- {
- WasmBinaryReader::WasmBinaryReader(ArenaAllocator* alloc, Js::WebAssemblyModule* module, const byte* source, size_t length) :
- m_alloc(alloc),
- m_start(source),
- m_end(source + length),
- m_pc(source),
- m_curFuncEnd(nullptr),
- m_currentSection(),
- m_readerState(READER_STATE_UNKNOWN),
- m_module(module)
- #if DBG_DUMP
- , m_ops(nullptr)
- #endif
- {
- m_currentSection.code = bSectLimit;
- #if DBG_DUMP
- m_ops = Anew(m_alloc, OpSet, m_alloc);
- #endif
- }
- void WasmBinaryReader::InitializeReader()
- {
- ValidateModuleHeader();
- m_readerState = READER_STATE_UNKNOWN;
- }
- void WasmBinaryReader::ThrowDecodingError(const char16* msg, ...) const
- {
- va_list argptr;
- va_start(argptr, msg);
- throw WasmCompilationException(msg, argptr);
- }
- SectionHeader WasmBinaryReader::ReadNextSection()
- {
- while (true)
- {
- if (EndOfModule())
- {
- memset(&m_currentSection, 0, sizeof(SectionHeader));
- m_currentSection.code = bSectLimit;
- return m_currentSection;
- }
- m_currentSection = ReadSectionHeader();
- if (SectionInfo::All[m_currentSection.code].flag == fSectIgnore)
- {
- TRACE_WASM_SECTION(_u("Ignore this section"));
- m_pc = m_currentSection.end;
- // Read next section
- continue;
- }
- return m_currentSection;
- }
- }
- bool WasmBinaryReader::ProcessCurrentSection()
- {
- Assert(m_currentSection.code != bSectLimit);
- TRACE_WASM_SECTION(_u("Process section %s"), SectionInfo::All[m_currentSection.code].name);
- m_readerState = READER_STATE_MODULE;
- switch (m_currentSection.code)
- {
- case bSectMemory:
- ReadMemorySection(false);
- break;
- case bSectType:
- ReadSignatureTypeSection();
- break;
- case bSectImport:
- ReadImportSection();
- break;
- case bSectFunction:
- ReadFunctionSignatures();
- break;
- case bSectFunctionBodies:
- ReadFunctionHeaders();
- break;
- case bSectExport:
- ReadExportSection();
- break;
- case bSectStartFunction:
- ReadStartFunction();
- break;
- case bSectData:
- ReadDataSection();
- break;
- case bSectTable:
- ReadTableSection(false);
- break;
- case bSectElement:
- ReadElementSection();
- break;
- case bSectName:
- ReadNameSection();
- break;
- case bSectGlobal:
- ReadGlobalSection();
- break;
- case bSectCustom:
- ReadCustomSection();
- break;
- default:
- Assert(UNREACHED);
- m_readerState = READER_STATE_UNKNOWN;
- return false;
- }
- m_readerState = READER_STATE_UNKNOWN;
- return m_pc == m_currentSection.end;
- }
- SectionHeader WasmBinaryReader::ReadSectionHeader()
- {
- SectionHeader header;
- header.start = m_pc;
- header.code = bSectLimit;
- uint32 len = 0;
- CompileAssert(sizeof(SectionCode) == sizeof(uint8));
- SectionCode sectionId = (SectionCode)LEB128<uint8, 7>(len);
- if (sectionId > bsectLastKnownSection)
- {
- ThrowDecodingError(_u("Invalid known section opcode %u"), sectionId);
- }
- uint32 sectionSize = LEB128(len);
- header.end = m_pc + sectionSize;
- CheckBytesLeft(sectionSize);
- header.code = sectionId;
- if (sectionId == bSectCustom)
- {
- header.name = ReadInlineName(len, header.nameLength);
- }
- else
- {
- header.name = SectionInfo::All[sectionId].name;
- header.nameLength = SectionInfo::All[sectionId].nameLength;
- }
- TRACE_WASM_SECTION(_u("Section Header: %s, length = %u (0x%x)"), header.name, sectionSize, sectionSize);
- return header;
- }
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- Js::FunctionBody* WasmBinaryReader::GetFunctionBody() const
- {
- if (m_readerState == READER_STATE_FUNCTION)
- {
- return m_funcState.body;
- }
- return nullptr;
- }
- #endif
- #if DBG_DUMP
- void WasmBinaryReader::PrintOps()
- {
- int count = m_ops->Count();
- if (count == 0)
- {
- return;
- }
- WasmOp* ops = HeapNewArray(WasmOp, count);
- auto iter = m_ops->GetIterator();
- int i = 0;
- while (iter.IsValid())
- {
- __analysis_assume(i < count);
- ops[i] = iter.CurrentKey();
- iter.MoveNext();
- ++i;
- }
- for (i = 0; i < count; ++i)
- {
- int j = i;
- while (j > 0 && ops[j-1] > ops[j])
- {
- WasmOp tmp = ops[j];
- ops[j] = ops[j - 1];
- ops[j - 1] = tmp;
- --j;
- }
- }
- uint32 moduleId = m_module->GetWasmFunctionInfo(0)->GetBody()->GetSourceContextId();
- Output::Print(_u("Module #%u's current opcode distribution\n"), moduleId);
- for (i = 0; i < count; ++i)
- {
- switch (ops[i])
- {
- #define WASM_OPCODE(opname, opcode, sig, imp, wat) \
- case opcode: \
- Output::Print(_u("%s: %s\r\n"), _u(#opname), _u(wat)); \
- break;
- #include "WasmBinaryOpCodes.h"
- }
- }
- HeapDeleteArray(count, ops);
- }
- #endif
- void WasmBinaryReader::ReadFunctionHeaders()
- {
- uint32 len;
- uint32 entries = LEB128(len);
- uint32 importCount = m_module->GetImportedFunctionCount();
- if (m_module->GetWasmFunctionCount() < importCount ||
- entries != m_module->GetWasmFunctionCount() - importCount)
- {
- ThrowDecodingError(_u("Function signatures and function bodies count mismatch"));
- }
- for (uint32 i = 0; i < entries; ++i)
- {
- uint32 funcIndex = i + importCount;
- WasmFunctionInfo* funcInfo = m_module->GetWasmFunctionInfo(funcIndex);
- const uint32 funcSize = LEB128(len);
- if (funcSize > Limits::GetMaxFunctionSize())
- {
- ThrowDecodingError(_u("Function body too big"));
- }
- funcInfo->SetReaderInfo(FunctionBodyReaderInfo(funcSize, (m_pc - m_start)));
- CheckBytesLeft(funcSize);
- TRACE_WASM_DECODER(_u("Function body header: index = %u, size = %u"), funcIndex, funcSize);
- const byte* end = m_pc + funcSize;
- m_pc = end;
- }
- }
- void WasmBinaryReader::SeekToFunctionBody(class WasmFunctionInfo* funcInfo)
- {
- FunctionBodyReaderInfo readerInfo = funcInfo->GetReaderInfo();
- if (m_end < m_start || readerInfo.startOffset >= (size_t)(m_end - m_start))
- {
- ThrowDecodingError(_u("Function byte offset out of bounds"));
- }
- if (m_readerState != READER_STATE_UNKNOWN)
- {
- ThrowDecodingError(_u("Wasm reader in an invalid state to read function code"));
- }
- m_readerState = READER_STATE_FUNCTION;
- // Seek to the function start and skip function header (count)
- m_pc = m_start + readerInfo.startOffset;
- m_funcState.size = readerInfo.size;
- m_funcState.count = 0;
- CheckBytesLeft(readerInfo.size);
- m_curFuncEnd = m_pc + m_funcState.size;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- m_funcState.body = funcInfo->GetBody();
- if (DO_WASM_TRACE_DECODER)
- {
- Output::Print(_u("Decoding "));
- m_funcState.body->DumpFullFunctionName();
- if (sizeof(intptr_t) == 8)
- {
- Output::Print(_u(": start = 0x%llx, end = 0x%llx, size = 0x%x\n"), (intptr_t)m_pc, (intptr_t)m_curFuncEnd, m_funcState.size);
- }
- else
- {
- Output::Print(_u(": start = 0x%x, end = 0x%x, size = 0x%x\n"), (intptr_t)m_pc, (intptr_t)m_curFuncEnd, m_funcState.size);
- }
- }
- #endif
- uint32 length = 0;
- uint32 numLocalsEntries = LEB128(length);
- m_funcState.count += length;
- // locals
- for (uint32 j = 0; j < numLocalsEntries; j++)
- {
- uint32 numLocals = LEB128(length);
- m_funcState.count += length;
- WasmTypes::WasmType type = ReadWasmType(length);
- if (!WasmTypes::IsLocalType(type))
- {
- ThrowDecodingError(_u("Invalid local type"));
- }
- m_funcState.count += length;
- uint32 totalLocals = 0;
- if (UInt32Math::Add(funcInfo->GetLocalCount(), numLocals, &totalLocals) || totalLocals > Limits::GetMaxFunctionLocals())
- {
- ThrowDecodingError(_u("Too many locals"));
- }
- funcInfo->AddLocal(type, numLocals);
- TRACE_WASM_DECODER(_u("Local: type = %s, count = %u"), WasmTypes::GetTypeName(type), numLocals);
- }
- }
- void WasmBinaryReader::FunctionEnd()
- {
- m_readerState = READER_STATE_UNKNOWN;
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- m_funcState.body = nullptr;
- #endif
- }
- bool WasmBinaryReader::IsCurrentFunctionCompleted() const
- {
- return m_pc == m_curFuncEnd;
- }
- const uint32 WasmBinaryReader::EstimateCurrentFunctionBytecodeSize() const
- {
- if (m_readerState != READER_STATE_FUNCTION)
- {
- ThrowDecodingError(_u("Wasm reader in an invalid state to get function information"));
- }
- // Use binary size to estimate bytecode size
- return m_funcState.size;
- }
- WasmOp WasmBinaryReader::ReadPrefixedOpCode(WasmOp prefix, bool isSupported, const char16* notSupportedMsg)
- {
- CompileAssert(sizeof(WasmOp) >= 2);
- if (!isSupported)
- {
- ThrowDecodingError(notSupportedMsg);
- }
- CheckBytesLeft(1);
- ++m_funcState.count;
- return (WasmOp)((prefix << 8) | (*m_pc++));
- }
- WasmOp WasmBinaryReader::ReadOpCode()
- {
- CheckBytesLeft(1);
- WasmOp op = (WasmOp)*m_pc++;
- ++m_funcState.count;
- switch (op)
- {
- #define WASM_PREFIX(name, value, imp, errorMsg) \
- case prefix##name: \
- return ReadPrefixedOpCode(op, imp, _u(errorMsg));
- #include "WasmBinaryOpCodes.h"
- }
- return op;
- }
- WasmOp WasmBinaryReader::ReadExpr()
- {
- WasmOp op = m_currentNode.op = ReadOpCode();
- if (EndOfFunc())
- {
- // end of AST
- if (op != wbEnd)
- {
- ThrowDecodingError(_u("missing function end opcode"));
- }
- return op;
- }
- switch (op)
- {
- case wbBlock:
- case wbLoop:
- case wbIf:
- BlockNode();
- break;
- case wbElse:
- // no node attributes
- break;
- case wbCall:
- CallNode();
- break;
- case wbCallIndirect:
- CallIndirectNode();
- break;
- case wbBr:
- case wbBrIf:
- BrNode();
- break;
- case wbBrTable:
- BrTableNode();
- break;
- case wbReturn:
- break;
- case wbI32Const:
- ConstNode<WasmTypes::I32>();
- break;
- case wbI64Const:
- ConstNode<WasmTypes::I64>();
- break;
- case wbF32Const:
- ConstNode<WasmTypes::F32>();
- break;
- case wbF64Const:
- ConstNode<WasmTypes::F64>();
- break;
- #ifdef ENABLE_WASM_SIMD
- case wbM128Const:
- ConstNode<WasmTypes::M128>();
- break;
- #endif
- case wbSetLocal:
- case wbGetLocal:
- case wbTeeLocal:
- case wbGetGlobal:
- case wbSetGlobal:
- VarNode();
- break;
- case wbDrop:
- break;
- case wbEnd:
- break;
- case wbNop:
- break;
- case wbMemorySize:
- case wbMemoryGrow:
- {
- // Reserved value currently unused
- uint8 reserved = ReadConst<uint8>();
- if (reserved != 0)
- {
- ThrowDecodingError(op == wbMemorySize
- ? _u("memory.size reserved value must be 0")
- : _u("memory.grow reserved value must be 0")
- );
- }
- break;
- }
- #ifdef ENABLE_WASM_SIMD
- case wbV8X16Shuffle:
- ShuffleNode();
- break;
- #define WASM_LANE_OPCODE(opname, ...) \
- case wb##opname: \
- LaneNode(); \
- break;
- #endif
- #define WASM_MEM_OPCODE(opname, ...) \
- case wb##opname: \
- MemNode(); \
- break;
- #include "WasmBinaryOpCodes.h"
- default:
- break;
- }
- #if DBG_DUMP
- m_ops->AddNew(op);
- #endif
- return op;
- }
- void WasmBinaryReader::ValidateModuleHeader()
- {
- uint32 bytesLeft = (uint32)(m_end - m_pc);
- if (bytesLeft > Limits::GetMaxModuleSize())
- {
- ThrowDecodingError(_u("Module too big"));
- }
- uint32 magicNumber = ReadConst<uint32>();
- uint32 version = ReadConst<uint32>();
- TRACE_WASM_DECODER(_u("Module Header: Magic 0x%x, Version %u"), magicNumber, version);
- if (magicNumber != 0x6d736100)
- {
- ThrowDecodingError(_u("Malformed WASM module header!"));
- }
- if (CONFIG_FLAG(WasmCheckVersion))
- {
- if (version != binaryVersion)
- {
- ThrowDecodingError(_u("Invalid WASM version!"));
- }
- }
- }
- void WasmBinaryReader::CallNode()
- {
- uint32 length = 0;
- uint32 funcNum = LEB128(length);
- m_funcState.count += length;
- FunctionIndexTypes::Type funcType = m_module->GetFunctionIndexType(funcNum);
- if (funcType == FunctionIndexTypes::Invalid)
- {
- ThrowDecodingError(_u("Function is out of bound"));
- }
- m_currentNode.call.funcType = funcType;
- m_currentNode.call.num = funcNum;
- }
- void WasmBinaryReader::CallIndirectNode()
- {
- uint32 length = 0;
- uint32 funcNum = LEB128(length);
- // Reserved value currently unused
- uint8 reserved = ReadConst<uint8>();
- if (reserved != 0)
- {
- ThrowDecodingError(_u("call_indirect reserved value must be 0"));
- }
- if (!m_module->HasTable() && !m_module->HasTableImport())
- {
- ThrowDecodingError(_u("Found call_indirect operator, but no table"));
- }
- m_funcState.count += length;
- if (funcNum >= m_module->GetSignatureCount())
- {
- ThrowDecodingError(_u("Function is out of bound"));
- }
- m_currentNode.call.num = funcNum;
- m_currentNode.call.funcType = FunctionIndexTypes::Function;
- }
- void WasmBinaryReader::BlockNode()
- {
- uint32 len = 0;
- int64 blocktype = SLEB128<int64, 33>(len);
- m_funcState.count += len;
- // Negative values means it's a value type or Void
- if (blocktype < 0)
- {
- // Only support 1 byte for negative values
- if (len != 1)
- {
- ThrowDecodingError(_u("Invalid blocktype %lld"), blocktype);
- }
- int8 blockSig = (int8)blocktype;
- // Check if it's an empty block
- if (blockSig == LanguageTypes::emptyBlock)
- {
- m_currentNode.block.SetSingleResult(WasmTypes::Void);
- }
- else
- {
- // Otherwise, it should be a value type
- WasmTypes::WasmType type = LanguageTypes::ToWasmType(blockSig);
- m_currentNode.block.SetSingleResult(type);
- }
- }
- else
- {
- // Positive values means it a function signature
- // Function signature is only supported with the Multi-Value feature
- if (!CONFIG_FLAG(WasmMultiValue))
- {
- ThrowDecodingError(_u("Block signature not supported"));
- }
- // Make sure the blocktype is a u32 after checking for negative values
- if (blocktype > UINT32_MAX)
- {
- ThrowDecodingError(_u("Invalid blocktype %lld"), blocktype);
- }
- uint32 blockId = (uint32)blocktype;
- if (!m_module->IsSignatureIndexValid(blockId))
- {
- ThrowDecodingError(_u("Block signature %u is invalid"), blockId);
- }
- m_currentNode.block.SetSignatureId(blockId);
- }
- }
- // control flow
- void WasmBinaryReader::BrNode()
- {
- uint32 len = 0;
- m_currentNode.br.depth = LEB128(len);
- m_funcState.count += len;
- }
- void WasmBinaryReader::BrTableNode()
- {
- uint32 len = 0;
- m_currentNode.brTable.numTargets = LEB128(len);
- if (m_currentNode.brTable.numTargets > Limits::GetMaxBrTableElems())
- {
- ThrowDecodingError(_u("br_table too big"));
- }
- m_funcState.count += len;
- m_currentNode.brTable.targetTable = AnewArray(m_alloc, uint32, m_currentNode.brTable.numTargets);
- for (uint32 i = 0; i < m_currentNode.brTable.numTargets; i++)
- {
- m_currentNode.brTable.targetTable[i] = LEB128(len);
- m_funcState.count += len;
- }
- m_currentNode.brTable.defaultTarget = LEB128(len);
- m_funcState.count += len;
- }
- void WasmBinaryReader::ShuffleNode()
- {
- CheckBytesLeft(Simd::MAX_LANES);
- for (uint32 i = 0; i < Simd::MAX_LANES; i++)
- {
- m_currentNode.shuffle.indices[i] = ReadConst<uint8>();
- }
- m_funcState.count += Simd::MAX_LANES;
- }
- void WasmBinaryReader::LaneNode()
- {
- m_currentNode.lane.index = ReadConst<uint8>();
- m_funcState.count++;
- }
- void WasmBinaryReader::MemNode()
- {
- uint32 len = 0;
- // flags
- const uint32 flags = LEB128(len);
- m_currentNode.mem.alignment = (uint8)flags;
- m_funcState.count += len;
- m_currentNode.mem.offset = LEB128(len);
- m_funcState.count += len;
- }
- // Locals/Globals
- void WasmBinaryReader::VarNode()
- {
- uint32 length;
- m_currentNode.var.num = LEB128(length);
- m_funcState.count += length;
- }
- // Const
- template <WasmTypes::WasmType localType>
- void WasmBinaryReader::ConstNode()
- {
- uint32 len = 0;
- switch (localType)
- {
- case WasmTypes::I32:
- m_currentNode.cnst.i32 = SLEB128(len);
- m_funcState.count += len;
- break;
- case WasmTypes::I64:
- m_currentNode.cnst.i64 = SLEB128<int64>(len);
- m_funcState.count += len;
- break;
- case WasmTypes::F32:
- {
- m_currentNode.cnst.i32 = ReadConst<int32>();
- CompileAssert(sizeof(int32) == sizeof(float));
- m_funcState.count += sizeof(float);
- break;
- }
- case WasmTypes::F64:
- m_currentNode.cnst.i64 = ReadConst<int64>();
- CompileAssert(sizeof(int64) == sizeof(double));
- m_funcState.count += sizeof(double);
- break;
- #ifdef ENABLE_WASM_SIMD
- case WasmTypes::M128:
- Simd::EnsureSimdIsEnabled();
- for (uint i = 0; i < Simd::VEC_WIDTH; i++)
- {
- m_currentNode.cnst.v128[i] = ReadConst<uint>();
- }
- m_funcState.count += Simd::VEC_WIDTH;
- break;
- #endif
- default:
- WasmTypes::CompileAssertCases<Wasm::WasmTypes::I32, Wasm::WasmTypes::I64, Wasm::WasmTypes::F32, Wasm::WasmTypes::F64, WASM_M128_CHECK_TYPE>();
- }
- }
- bool WasmBinaryReader::EndOfFunc()
- {
- return m_funcState.count >= m_funcState.size;
- }
- bool WasmBinaryReader::EndOfModule()
- {
- return (m_pc >= m_end);
- }
- void WasmBinaryReader::ReadMemorySection(bool isImportSection)
- {
- uint32 length = 0;
- uint32 count;
- if (isImportSection)
- {
- count = 1;
- }
- else
- {
- count = LEB128(length);
- }
- if (count > 1)
- {
- ThrowDecodingError(_u("Maximum of 1 memory allowed"));
- }
- if (count == 1)
- {
- MemorySectionLimits limits = ReadSectionLimitsBase<MemorySectionLimits>(Limits::GetMaxMemoryInitialPages(), Limits::GetMaxMemoryMaximumPages(), _u("memory size too big"));
- if (Wasm::Threads::IsEnabled() && limits.IsShared() && !limits.HasMaximum())
- {
- ThrowDecodingError(_u("Shared memory must have a maximum size"));
- }
- m_module->InitializeMemory(&limits);
- }
- }
- void WasmBinaryReader::ReadSignatureTypeSection()
- {
- uint32 len = 0;
- const uint32 numTypes = LEB128(len);
- if (numTypes > Limits::GetMaxTypes())
- {
- ThrowDecodingError(_u("Too many signatures"));
- }
- m_module->SetSignatureCount(numTypes);
- // signatures table
- for (uint32 i = 0; i < numTypes; i++)
- {
- WasmSignature* sig = m_module->GetSignature(i);
- sig->SetSignatureId(i);
- int8 form = SLEB128<int8, 7>(len);
- if (form != LanguageTypes::func)
- {
- ThrowDecodingError(_u("Unexpected type form 0x%X"), form);
- }
- uint32 paramCount32 = LEB128(len);
- if (paramCount32 > Limits::GetMaxFunctionParams() || paramCount32 > UINT16_MAX)
- {
- ThrowDecodingError(_u("Too many arguments in signature"));
- }
- Js::ArgSlot paramCount = (Js::ArgSlot)paramCount32;
- sig->AllocateParams(paramCount, m_module->GetRecycler());
- for (Js::ArgSlot j = 0; j < paramCount; j++)
- {
- WasmTypes::WasmType type = ReadWasmType(len);
- sig->SetParam(type, j);
- }
- uint32 resultCount = LEB128(len);
- if (resultCount > Limits::GetMaxFunctionReturns())
- {
- ThrowDecodingError(_u("Too many returns in signature: %u. Maximum allowed: %u"), resultCount, Limits::GetMaxFunctionReturns());
- }
- sig->AllocateResults(resultCount, m_module->GetRecycler());
- for (uint32 iResult = 0; iResult < resultCount; ++iResult)
- {
- WasmTypes::WasmType type = ReadWasmType(len);
- sig->SetResult(type, iResult);
- }
- sig->FinalizeSignature();
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (DO_WASM_TRACE_DECODER)
- {
- Output::Print(_u("Signature #%u: "), i);
- sig->Dump();
- Output::Print(_u("\n"));
- }
- #endif
- }
- }
- void WasmBinaryReader::ReadFunctionSignatures()
- {
- uint32 len = 0;
- uint32 nFunctions = LEB128(len);
- uint32 totalFunctions = 0;
- if (UInt32Math::Add(nFunctions, m_module->GetWasmFunctionCount(), &totalFunctions) || totalFunctions > Limits::GetMaxFunctions())
- {
- ThrowDecodingError(_u("Too many functions"));
- }
- for (uint32 iFunc = 0; iFunc < nFunctions; iFunc++)
- {
- uint32 sigIndex = LEB128(len);
- if (sigIndex >= m_module->GetSignatureCount())
- {
- ThrowDecodingError(_u("Function signature is out of bound"));
- }
- WasmSignature* sig = m_module->GetSignature(sigIndex);
- m_module->AddWasmFunctionInfo(sig);
- }
- }
- void WasmBinaryReader::ReadExportSection()
- {
- uint32 length;
- uint32 numExports = LEB128(length);
- if (numExports > Limits::GetMaxExports())
- {
- ThrowDecodingError(_u("Too many exports"));
- }
- m_module->AllocateFunctionExports(numExports);
- ArenaAllocator tmpAlloc(_u("ExportDupCheck"), m_module->GetScriptContext()->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory);
- typedef SList<const char16*> NameList;
- JsUtil::BaseDictionary<uint32, NameList*, ArenaAllocator> exportsNameDict(&tmpAlloc);
- for (uint32 iExport = 0; iExport < numExports; iExport++)
- {
- uint32 nameLength;
- const char16* exportName = ReadInlineName(length, nameLength);
- // Check if the name is already used
- NameList* list = nullptr;
- if (exportsNameDict.TryGetValue(nameLength, &list))
- {
- const char16** found = list->Find([exportName, nameLength](const char16* existing) {
- return wcsncmp(exportName, existing, nameLength) == 0;
- });
- if (found)
- {
- ThrowDecodingError(_u("Duplicate export name: %s"), exportName);
- }
- }
- else
- {
- list = Anew(&tmpAlloc, NameList, &tmpAlloc);
- exportsNameDict.Add(nameLength, list);
- }
- list->Push(exportName);
- ExternalKinds kind = ReadExternalKind();
- uint32 index = LEB128(length);
- switch (kind)
- {
- case ExternalKinds::Function:
- {
- FunctionIndexTypes::Type type = m_module->GetFunctionIndexType(index);
- if (!FunctionIndexTypes::CanBeExported(type))
- {
- ThrowDecodingError(_u("Invalid Export %u => func[%u]"), iExport, index);
- }
- m_module->SetExport(iExport, index, exportName, nameLength, kind);
- #if DBG_DUMP
- if (type == FunctionIndexTypes::ImportThunk)
- {
- WasmImport* import = m_module->GetWasmFunctionInfo(index)->importedFunctionReference;
- TRACE_WASM_DECODER(_u("Export #%u: Import(%s.%s)(%u) => %s"), iExport, import->modName, import->importName, index, exportName);
- }
- else
- {
- TRACE_WASM_DECODER(_u("Export #%u: Function(%u) => %s"), iExport, index, exportName);
- }
- #endif
- break;
- }
- case ExternalKinds::Memory:
- if (index != 0)
- {
- ThrowDecodingError(_u("Unknown memory index %u for export %s"), index, exportName);
- }
- m_module->SetExport(iExport, index, exportName, nameLength, kind);
- break;
- case ExternalKinds::Table:
- if (index != 0)
- {
- ThrowDecodingError(_u("Unknown table index %u for export %s"), index, exportName);
- }
- m_module->SetExport(iExport, index, exportName, nameLength, kind);
- break;
- case ExternalKinds::Global:
- if (index >= m_module->GetGlobalCount())
- {
- ThrowDecodingError(_u("Unknown global %u for export %s"), index, exportName);
- }
- if (m_module->GetGlobal(index)->IsMutable())
- {
- ThrowDecodingError(_u("Mutable globals cannot be exported"), index, exportName);
- }
- m_module->SetExport(iExport, index, exportName, nameLength, kind);
- break;
- default:
- ThrowDecodingError(_u("Exported Kind %d, NYI"), kind);
- break;
- }
- }
- }
- void WasmBinaryReader::ReadTableSection(bool isImportSection)
- {
- uint32 length;
- uint32 entries;
- if (isImportSection)
- {
- entries = 1;
- }
- else
- {
- entries = LEB128(length);
- }
- if (entries > 1)
- {
- ThrowDecodingError(_u("Maximum of one table allowed"));
- }
- if (entries == 1)
- {
- int8 elementType = SLEB128<int8, 7>(length);
- if (elementType != LanguageTypes::anyfunc)
- {
- ThrowDecodingError(_u("Only anyfunc type is supported. Unknown type %d"), elementType);
- }
- TableSectionLimits limits = ReadSectionLimitsBase<TableSectionLimits>(Limits::GetMaxTableSize(), Limits::GetMaxTableSize(), _u("table too big"));
- m_module->InitializeTable(&limits);
- TRACE_WASM_DECODER(_u("Indirect table: %u to %u entries"), limits.initial, limits.maximum);
- }
- }
- void WasmBinaryReader::ReadElementSection()
- {
- uint32 length = 0;
- uint32 numSegments = LEB128(length);
- if (numSegments > Limits::GetMaxElementSegments())
- {
- ThrowDecodingError(_u("Too many element segments"));
- }
- if (numSegments > 0)
- {
- m_module->AllocateElementSegs(numSegments);
- }
- TRACE_WASM_DECODER(_u("Indirect table element: %u entries"), numSegments);
- for (uint32 i = 0; i < numSegments; ++i)
- {
- uint32 index = LEB128(length); // Table id
- if (index != 0 || !(m_module->HasTable() || m_module->HasTableImport()))
- {
- ThrowDecodingError(_u("Unknown table index %d"), index); //MVP limitation
- }
- WasmNode initExpr = ReadInitExpr(true);
- uint32 numElem = LEB128(length);
- if (numElem > Limits::GetMaxTableSize())
- {
- ThrowDecodingError(_u("Too many table element"));
- }
- WasmElementSegment* eSeg = Anew(m_alloc, WasmElementSegment, m_alloc, index, initExpr, numElem);
- for (uint32 iElem = 0; iElem < numElem; ++iElem)
- {
- uint32 elem = LEB128(length);
- FunctionIndexTypes::Type funcType = m_module->GetFunctionIndexType(elem);
- if (!FunctionIndexTypes::CanBeExported(funcType))
- {
- ThrowDecodingError(_u("Invalid function to insert in the table %u"), elem);
- }
- eSeg->AddElement(elem);
- }
- m_module->SetElementSeg(eSeg, i);
- }
- }
- void WasmBinaryReader::ReadDataSection()
- {
- uint32 len = 0;
- const uint32 numSegments = LEB128(len);
- if (numSegments > Limits::GetMaxDataSegments())
- {
- ThrowDecodingError(_u("Too many data segments"));
- }
- if (numSegments > 0)
- {
- m_module->AllocateDataSegs(numSegments);
- }
- for (uint32 i = 0; i < numSegments; ++i)
- {
- uint32 index = LEB128(len);
- if (index != 0 || !(m_module->HasMemory() || m_module->HasMemoryImport()))
- {
- ThrowDecodingError(_u("Unknown memory index %u"), index);
- }
- TRACE_WASM_DECODER(_u("Data Segment #%u"), i);
- WasmNode initExpr = ReadInitExpr(true);
- uint32 dataByteLen = LEB128(len);
- WasmDataSegment* dseg = Anew(m_alloc, WasmDataSegment, m_alloc, initExpr, dataByteLen, m_pc);
- CheckBytesLeft(dataByteLen);
- m_pc += dataByteLen;
- m_module->SetDataSeg(dseg, i);
- }
- }
- void WasmBinaryReader::ReadNameSection()
- {
- uint32 len = 0;
- uint32 numFuncNames = LEB128(len);
- if (numFuncNames > Limits::GetMaxFunctions())
- {
- ThrowDecodingError(_u("Too many function names"));
- }
- for (uint32 i = 0; i < numFuncNames; ++i)
- {
- uint32 fnNameLen = 0;
- WasmFunctionInfo* funsig = m_module->GetWasmFunctionInfo(i);
- const char16* name = ReadInlineName(len, fnNameLen);
- funsig->SetName(name, fnNameLen);
- uint32 numLocals = LEB128(len);
- if (numLocals != funsig->GetLocalCount())
- {
- ThrowDecodingError(_u("num locals mismatch in names section"));
- }
- for (uint32 j = 0; j < numLocals; ++j)
- {
- uint32 localNameLen = 0;
- ReadInlineName(len, localNameLen);
- }
- }
- }
- void WasmBinaryReader::ReadGlobalSection()
- {
- uint32 len = 0;
- uint32 numGlobals = LEB128(len);
- uint32 totalGlobals = 0;
- if (UInt32Math::Add(numGlobals, m_module->GetGlobalCount(), &totalGlobals) || totalGlobals > Limits::GetMaxGlobals())
- {
- ThrowDecodingError(_u("Too many globals"));
- }
- for (uint32 i = 0; i < numGlobals; ++i)
- {
- WasmTypes::WasmType type = ReadWasmType(len);
-
- if (!WasmTypes::IsLocalType(type))
- {
- ThrowDecodingError(_u("Invalid global type %u"), type);
- }
- switch (type)
- {
- case WasmTypes::I32: break; // Handled
- case WasmTypes::I64: break; // Handled
- case WasmTypes::F32: break; // Handled
- case WasmTypes::F64: break; // Handled
- #ifdef ENABLE_WASM_SIMD
- case WasmTypes::M128: ThrowDecodingError(_u("m128 globals not supported"));
- #endif
- default:
- WasmTypes::CompileAssertCases<WasmTypes::I32, WasmTypes::I64, WasmTypes::F32, WasmTypes::F64, WASM_M128_CHECK_TYPE>();
- }
-
- bool isMutable = ReadMutableValue();
- WasmNode globalNode = ReadInitExpr();
- GlobalReferenceTypes::Type refType = GlobalReferenceTypes::Const;
- WasmTypes::WasmType initType;
- switch (globalNode.op) {
- case wbI32Const: initType = WasmTypes::I32; break;
- case wbF32Const: initType = WasmTypes::F32; break;
- case wbF64Const: initType = WasmTypes::F64; break;
- case wbI64Const: initType = WasmTypes::I64; break;
- case wbGetGlobal:
- initType = m_module->GetGlobal(globalNode.var.num)->GetType();
- refType = GlobalReferenceTypes::LocalReference;
- break;
- default:
- Assert(UNREACHED);
- ThrowDecodingError(_u("Unknown global init_expr"));
- }
- if (type != initType)
- {
- ThrowDecodingError(_u("Type mismatch for global initialization"));
- }
- m_module->AddGlobal(refType, type, isMutable, globalNode);
- }
- }
- void WasmBinaryReader::ReadCustomSection()
- {
- CustomSection customSection;
- customSection.name = m_currentSection.name;
- customSection.nameLength = m_currentSection.nameLength;
- customSection.payload = m_pc;
- size_t size = m_currentSection.end - m_pc;
- if (m_currentSection.end < m_pc || !Math::FitsInDWord(size))
- {
- ThrowDecodingError(_u("Invalid custom section size"));
- }
- customSection.payloadSize = (uint32)size;
- m_module->AddCustomSection(customSection);
- m_pc = m_currentSection.end;
- }
- const char16* WasmBinaryReader::ReadInlineName(uint32& length, uint32& nameLength)
- {
- uint32 rawNameLength = LEB128(length);
- if (rawNameLength > Limits::GetMaxStringSize())
- {
- ThrowDecodingError(_u("Name too long"));
- }
- CheckBytesLeft(rawNameLength);
- LPCUTF8 rawName = m_pc;
- m_pc += rawNameLength;
- length += rawNameLength;
- utf8::DecodeOptions decodeOptions = utf8::doThrowOnInvalidWCHARs;
- try
- {
- nameLength = (uint32)utf8::ByteIndexIntoCharacterIndex(rawName, rawNameLength, decodeOptions);
- char16* contents = AnewArray(m_alloc, char16, nameLength + 1);
- size_t decodedLength = utf8::DecodeUnitsIntoAndNullTerminate(contents, rawName, rawName + rawNameLength, decodeOptions);
- if (decodedLength != nameLength)
- {
- AssertMsg(UNREACHED, "We calculated the length before decoding, what happened ?");
- ThrowDecodingError(_u("Error while decoding utf8 string"));
- }
- return contents;
- }
- catch (utf8::InvalidWideCharException)
- {
- ThrowDecodingError(_u("Invalid UTF-8 encoding"));
- }
- }
- void WasmBinaryReader::ReadImportSection()
- {
- uint32 len = 0;
- uint32 numImports = LEB128(len);
- if (numImports > Limits::GetMaxImports())
- {
- ThrowDecodingError(_u("Too many imports"));
- }
- for (uint32 i = 0; i < numImports; ++i)
- {
- uint32 modNameLen = 0, fnNameLen = 0;
- const char16* modName = ReadInlineName(len, modNameLen);
- const char16* fnName = ReadInlineName(len, fnNameLen);
- ExternalKinds kind = ReadExternalKind();
- TRACE_WASM_DECODER(_u("Import #%u: \"%s\".\"%s\", kind: %d"), i, modName, fnName, kind);
- switch (kind)
- {
- case ExternalKinds::Function:
- {
- uint32 sigId = LEB128(len);
- m_module->AddFunctionImport(sigId, modName, modNameLen, fnName, fnNameLen);
- if (m_module->GetWasmFunctionCount() > Limits::GetMaxFunctions())
- {
- ThrowDecodingError(_u("Too many functions"));
- }
- break;
- }
- case ExternalKinds::Global:
- {
- WasmTypes::WasmType type = ReadWasmType(len);
- bool isMutable = ReadMutableValue();
- if (isMutable)
- {
- ThrowDecodingError(_u("Mutable globals cannot be imported"));
- }
- m_module->AddGlobal(GlobalReferenceTypes::ImportedReference, type, isMutable, {});
- m_module->AddGlobalImport(modName, modNameLen, fnName, fnNameLen);
- if (m_module->GetGlobalCount() > Limits::GetMaxGlobals())
- {
- ThrowDecodingError(_u("Too many globals"));
- }
- break;
- }
- case ExternalKinds::Table:
- ReadTableSection(true);
- m_module->AddTableImport(modName, modNameLen, fnName, fnNameLen);
- break;
- case ExternalKinds::Memory:
- ReadMemorySection(true);
- m_module->AddMemoryImport(modName, modNameLen, fnName, fnNameLen);
- break;
- default:
- ThrowDecodingError(_u("Imported Kind %d, NYI"), kind);
- break;
- }
- }
- }
- void WasmBinaryReader::ReadStartFunction()
- {
- uint32 len = 0;
- uint32 id = LEB128(len);
- Wasm::FunctionIndexTypes::Type funcType = m_module->GetFunctionIndexType(id);
- if (!FunctionIndexTypes::CanBeExported(funcType))
- {
- ThrowDecodingError(_u("Invalid function index for start function %u"), id);
- }
- WasmSignature* sig = m_module->GetWasmFunctionInfo(id)->GetSignature();
- if (sig->GetParamCount() > 0 || sig->GetResultCount())
- {
- ThrowDecodingError(_u("Start function must be void and nullary"));
- }
- m_module->SetStartFunction(id);
- }
- template<typename LEBType, uint32 bits>
- LEBType WasmBinaryReader::LEB128(uint32 &length)
- {
- CompileAssert((sizeof(LEBType) * 8) >= bits);
- constexpr bool sign = LEBType(-1) < LEBType(0);
- LEBType result = 0;
- uint32 shift = 0;
- byte b = 0;
- length = 0;
- constexpr uint32 maxReads = (uint32) (((bits % 7) == 0) ? bits/7 : bits/7 + 1);
- CompileAssert(maxReads > 0);
- for (uint32 i = 0; i < maxReads; ++i)
- {
- CheckBytesLeft(1);
- b = *m_pc++;
- ++length;
- result = result | ((LEBType)(b & 0x7f) << shift);
- if (sign)
- {
- shift += 7;
- if ((b & 0x80) == 0)
- break;
- }
- else
- {
- if ((b & 0x80) == 0)
- break;
- shift += 7;
- }
- }
- if (b & 0x80 || m_pc > m_end)
- {
- ThrowDecodingError(_u("Invalid LEB128 format"));
- }
- if (sign && (shift < (sizeof(LEBType) * 8)) && (0x40 & b))
- {
- #pragma prefast(suppress:26453)
- result |= ((~(LEBType)0) << shift);
- }
- return result;
- }
- WasmNode WasmBinaryReader::ReadInitExpr(bool isOffset)
- {
- if (m_readerState != READER_STATE_MODULE)
- {
- ThrowDecodingError(_u("Wasm reader in an invalid state to read init_expr"));
- }
- m_funcState.count = 0;
- m_funcState.size = (uint32)(m_currentSection.end - m_pc);
- #if TARGET_64
- Assert(m_pc + m_funcState.size == m_currentSection.end);
- #endif
- ReadExpr();
- WasmNode node = m_currentNode;
- switch (node.op)
- {
- case wbI32Const:
- case wbF32Const:
- case wbI64Const:
- case wbF64Const:
- break;
- case wbGetGlobal:
- {
- uint32 globalIndex = node.var.num;
- WasmGlobal* global = m_module->GetGlobal(globalIndex);
- if (global->GetReferenceType() != GlobalReferenceTypes::ImportedReference)
- {
- ThrowDecodingError(_u("initializer expression can only use imported globals"));
- }
- if (global->IsMutable())
- {
- ThrowDecodingError(_u("initializer expression cannot reference a mutable global"));
- }
- break;
- }
- default:
- ThrowDecodingError(_u("Invalid initexpr opcode"));
- }
- if (ReadExpr() != wbEnd)
- {
- ThrowDecodingError(_u("Missing end opcode after init expr"));
- }
- if (isOffset)
- {
- m_module->ValidateInitExportForOffset(node);
- }
- return node;
- }
- template<typename SectionLimitType>
- SectionLimitType WasmBinaryReader::ReadSectionLimitsBase(uint32 maxInitial, uint32 maxMaximum, const char16* errorMsg)
- {
- SectionLimitType limits;
- uint32 length = 0;
- limits.flags = (SectionLimits::Flags)LEB128(length);
- limits.initial = LEB128(length);
- limits.maximum = maxMaximum;
- if (limits.HasMaximum())
- {
- limits.maximum = LEB128(length);
- if (limits.maximum > maxMaximum)
- {
- ThrowDecodingError(_u("Maximum %s"), errorMsg);
- }
- }
- if (limits.initial > maxInitial)
- {
- ThrowDecodingError(_u("Minimum %s"), errorMsg);
- }
- return limits;
- }
- // Do not use float version of ReadConst. Instead use integer version and reinterpret bits.
- template<> double WasmBinaryReader::ReadConst<double>() { Assert(false); return 0; }
- template<> float WasmBinaryReader::ReadConst<float>() { Assert(false); return 0; }
- template <typename T>
- T WasmBinaryReader::ReadConst()
- {
- CheckBytesLeft(sizeof(T));
- T value = *((T*)m_pc);
- m_pc += sizeof(T);
- return value;
- }
- bool WasmBinaryReader::ReadMutableValue()
- {
- uint8 mutableValue = ReadConst<UINT8>();
- switch (mutableValue)
- {
- case 0: return false;
- case 1: return true;
- default:
- ThrowDecodingError(_u("invalid mutability"));
- }
- }
- WasmTypes::WasmType WasmBinaryReader::ReadWasmType(uint32& length)
- {
- return LanguageTypes::ToWasmType(SLEB128<int8, 7>(length));
- }
- void WasmBinaryReader::CheckBytesLeft(uint32 bytesNeeded)
- {
- uint32 bytesLeft = (uint32)(m_end - m_pc);
- if (bytesNeeded > bytesLeft)
- {
- ThrowDecodingError(_u("Out of file: Needed: %d, Left: %d"), bytesNeeded, bytesLeft);
- }
- }
- } // namespace Wasm
- #endif // ENABLE_WASM
|