| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- {
- namespace WasmTypes
- {
- bool IsLocalType(WasmTypes::WasmType type)
- {
- // Check if type in range ]Void,Limit[
- return (uint32)(type - 1) < (WasmTypes::Limit - 1);
- }
- uint32 GetTypeByteSize(WasmType type)
- {
- switch (type)
- {
- case Void: return sizeof(Js::Var);
- case I32: return sizeof(int32);
- case I64: return sizeof(int64);
- case F32: return sizeof(float);
- case F64: return sizeof(double);
- default:
- Js::Throw::InternalError();
- }
- }
- const char16 * GetTypeName(WasmType type)
- {
- const char16* typestring = _u("unknown");
- switch (type) {
- case WasmTypes::WasmType::Void:
- typestring = _u("void");
- break;
- case WasmTypes::WasmType::I32:
- typestring = _u("i32");
- break;
- case WasmTypes::WasmType::I64:
- typestring = _u("i64");
- break;
- case WasmTypes::WasmType::F32:
- typestring = _u("f32");
- break;
- case WasmTypes::WasmType::F64:
- typestring = _u("f64");
- break;
- default:
- Assert(false);
- break;
- }
- return typestring;
- }
- } // namespace WasmTypes
- WasmTypes::WasmType LanguageTypes::ToWasmType(int8 binType)
- {
- switch (binType)
- {
- case LanguageTypes::i32: return WasmTypes::I32;
- case LanguageTypes::i64: return WasmTypes::I64;
- case LanguageTypes::f32: return WasmTypes::F32;
- case LanguageTypes::f64: return WasmTypes::F64;
- default:
- throw WasmCompilationException(_u("Invalid binary type %d"), binType);
- }
- }
- bool FunctionIndexTypes::CanBeExported(FunctionIndexTypes::Type funcType)
- {
- return funcType == FunctionIndexTypes::Function || funcType == FunctionIndexTypes::ImportThunk;
- }
- WasmBinaryReader::WasmBinaryReader(ArenaAllocator* alloc, Js::WebAssemblyModule* module, const byte* source, size_t length) :
- m_module(module),
- m_curFuncEnd(nullptr),
- m_alloc(alloc),
- m_readerState(READER_STATE_UNKNOWN)
- {
- m_start = m_pc = source;
- m_end = source + length;
- 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, ...)
- {
- 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)ReadVarUInt7();
- 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 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())
- {
- 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;
- }
- }
- for (i = 0; i < count; ++i)
- {
- switch (ops[i])
- {
- #define WASM_OPCODE(opname, opcode, sig, nyi) \
- case opcode: \
- Output::Print(_u("%s\r\n"), _u(#opname)); \
- 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->m_readerInfo.size = funcSize;
- funcInfo->m_readerInfo.startOffset = (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->m_readerInfo;
- if (readerInfo.startOffset >= (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;
- 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;
- }
- bool WasmBinaryReader::IsCurrentFunctionCompleted() const
- {
- return m_pc == m_curFuncEnd;
- }
- WasmOp WasmBinaryReader::ReadExpr()
- {
- WasmOp op = m_currentNode.op = (WasmOp)*m_pc++;
- ++m_funcState.count;
- 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;
- case wbSetLocal:
- case wbGetLocal:
- case wbTeeLocal:
- case wbGetGlobal:
- case wbSetGlobal:
- VarNode();
- break;
- case wbDrop:
- break;
- case wbEnd:
- break;
- case wbNop:
- break;
- case wbCurrentMemory:
- case wbGrowMemory:
- // Reserved value currently unused
- ReadConst<uint8>();
- break;
- #define WASM_MEM_OPCODE(opname, opcode, sig, nyi) \
- 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))
- {
- // Accept version 0xd to avoid problem in our test infrastructure
- // We should eventually remove support for 0xd.
- // The Assert is here as a reminder in case we change the binary version and we haven't removed 0xd support yet
- CompileAssert(binaryVersion == 0x1);
- if (version != binaryVersion && version != 0xd)
- {
- 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
- ReadConst<uint8>();
- 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()
- {
- int8 blockType = ReadConst<int8>();
- m_funcState.count++;
- m_currentNode.block.sig = blockType == LanguageTypes::emptyBlock ? WasmTypes::Void : LanguageTypes::ToWasmType(blockType);
- }
- // 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::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.f32 = ReadConst<float>();
- m_funcState.count += sizeof(float);
- break;
- case WasmTypes::F64:
- m_currentNode.cnst.f64 = ReadConst<double>();
- m_funcState.count += sizeof(double);
- break;
- }
- }
- 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)
- {
- SectionLimits limits = ReadSectionLimits(Limits::GetMaxMemoryInitialPages(), Limits::GetMaxMemoryMaximumPages(), _u("memory size too big"));
- m_module->InitializeMemory(limits.initial, limits.maximum);
- }
- }
- 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++)
- {
- TRACE_WASM_DECODER(_u("Signature #%u"), i);
- WasmSignature* sig = m_module->GetSignature(i);
- sig->SetSignatureId(i);
- int8 form = ReadConst<int8>();
- 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 > 1)
- {
- ThrowDecodingError(_u("Too many returns in signature: %u. Maximum allowed: 1"), resultCount);
- }
- if (resultCount == 1)
- {
- WasmTypes::WasmType type = ReadWasmType(len);
- sig->SetResultType(type);
- }
- sig->FinalizeSignature();
- }
- }
- 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::ExternalKind kind = (ExternalKinds::ExternalKind)ReadConst<int8>();
- 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 = ReadConst<int8>();
- if (elementType != LanguageTypes::anyfunc)
- {
- ThrowDecodingError(_u("Only anyfunc type is supported. Unknown type %d"), elementType);
- }
- SectionLimits limits = ReadSectionLimits(Limits::GetMaxTableSize(), Limits::GetMaxTableSize(), _u("table too big"));
- m_module->InitializeTable(limits.initial, limits.maximum);
- 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);
- 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::doDefault;
- 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;
- }
- 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::ExternalKind kind = (ExternalKinds::ExternalKind)ReadConst<int8>();
- 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->GetResultType() != WasmTypes::Void)
- {
- ThrowDecodingError(_u("Start function must be void and nullary"));
- }
- m_module->SetStartFunction(id);
- }
- template<typename MaxAllowedType>
- MaxAllowedType WasmBinaryReader::LEB128(uint32 &length, bool sgn)
- {
- MaxAllowedType result = 0;
- uint32 shamt = 0;
- byte b = 0;
- length = 1;
- uint32 maxReads = sizeof(MaxAllowedType) == 4 ? 5 : 10;
- CompileAssert(sizeof(MaxAllowedType) == 4 || sizeof(MaxAllowedType) == 8);
- for (uint32 i = 0; i < maxReads; i++, length++)
- {
- CheckBytesLeft(1);
- b = *m_pc++;
- result = result | ((MaxAllowedType)(b & 0x7f) << shamt);
- if (sgn)
- {
- shamt += 7;
- if ((b & 0x80) == 0)
- break;
- }
- else
- {
- if ((b & 0x80) == 0)
- break;
- shamt += 7;
- }
- }
- if (b & 0x80 || m_pc > m_end)
- {
- ThrowDecodingError(_u("Invalid LEB128 format"));
- }
- if (sgn && (shamt < sizeof(MaxAllowedType) * 8) && (0x40 & b))
- {
- if (sizeof(MaxAllowedType) == 4)
- {
- result |= -(1 << shamt);
- }
- else if (sizeof(MaxAllowedType) == 8)
- {
- result |= -((int64)1 << shamt);
- }
- }
- if (!sgn)
- {
- if (sizeof(MaxAllowedType) == 4)
- {
- TRACE_WASM_LEB128(_u("Binary decoder: LEB128 length = %u, value = %u (0x%x)"), length, result, result);
- }
- else if (sizeof(MaxAllowedType) == 8)
- {
- TRACE_WASM_LEB128(_u("Binary decoder: LEB128 length = %u, value = %llu (0x%llx)"), length, result, result);
- }
- }
- return result;
- }
- // Signed LEB128
- template<>
- int32 WasmBinaryReader::SLEB128(uint32 &length)
- {
- int32 result = LEB128<uint32>(length, true);
- TRACE_WASM_LEB128(_u("Binary decoder: SLEB128 length = %u, value = %d (0x%x)"), length, result, result);
- return result;
- }
- template<>
- int64 WasmBinaryReader::SLEB128(uint32 &length)
- {
- int64 result = LEB128<uint64>(length, true);
- TRACE_WASM_LEB128(_u("Binary decoder: SLEB128 length = %u, value = %lld (0x%llx)"), length, result, result);
- 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 = m_currentSection.end - m_pc;
- 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;
- }
- SectionLimits WasmBinaryReader::ReadSectionLimits(uint32 maxInitial, uint32 maxMaximum, const char16* errorMsg)
- {
- SectionLimits limits;
- uint32 length = 0;
- uint32 flags = LEB128(length);
- limits.initial = LEB128(length);
- limits.maximum = maxMaximum;
- if (flags & 0x1)
- {
- limits.maximum = LEB128(length);
- if (limits.maximum > maxMaximum)
- {
- ThrowDecodingError(_u("Maximum %s"), errorMsg);
- }
- }
- if (limits.initial > maxInitial)
- {
- ThrowDecodingError(_u("Minimum %s"), errorMsg);
- }
- return limits;
- }
- template <typename T>
- T WasmBinaryReader::ReadConst()
- {
- CheckBytesLeft(sizeof(T));
- T value = *((T*)m_pc);
- m_pc += sizeof(T);
- return value;
- }
- uint8 WasmBinaryReader::ReadVarUInt7()
- {
- return ReadConst<uint8>() & 0x7F;
- }
- 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)
- {
- length = 1;
- return LanguageTypes::ToWasmType(ReadConst<int8>());
- }
- 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
|