| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261 |
- //-------------------------------------------------------------------------------------------------------
- // 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
- #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 (uint)(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();
- }
- }
- } // 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);
- }
- bool
- WasmBinaryReader::ReadNextSection(SectionCode nextSection)
- {
- while (true)
- {
- if (EndOfModule() || SectionInfo::All[nextSection].flag == fSectIgnore)
- {
- return false;
- }
- m_currentSection = ReadSectionHeader();
- if (SectionInfo::All[m_currentSection.code].flag == fSectIgnore)
- {
- TRACE_WASM_DECODER(_u("Ignore this section"));
- m_pc = m_currentSection.end;
- // Read next section
- continue;
- }
- // Process the custom sections now
- if (m_currentSection.code == bSectCustom)
- {
- if (!ProcessCurrentSection())
- {
- ThrowDecodingError(_u("Error while reading custom section %s"), m_currentSection.name);
- }
- // Read next section
- continue;
- }
- if (m_currentSection.code < nextSection)
- {
- ThrowDecodingError(_u("Invalid Section %s"), m_currentSection.code);
- }
- if (m_currentSection.code != nextSection)
- {
- TRACE_WASM_DECODER(_u("The current section is not the one we are looking for"));
- // We know about this section, but it's not the one we're looking for
- m_pc = m_currentSection.start;
- return false;
- }
- return true;
- }
- }
- 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 bSectSignatures:
- ReadSignatures();
- break;
- case bSectImportTable:
- ReadImportEntries();
- break;
- case bSectFunctionSignatures:
- ReadFunctionsSignatures();
- break;
- case bSectFunctionBodies:
- ReadFunctionHeaders();
- break;
- case bSectExportTable:
- ReadExportTable();
- break;
- case bSectStartFunction:
- ReadStartFunction();
- break;
- case bSectDataSegments:
- ReadDataSegments();
- break;
- case bSectIndirectFunctionTable:
- ReadTableSection(false);
- break;
- case bSectElement:
- ReadElementSection();
- break;
- case bSectNames:
- ReadNamesSection();
- break;
- case bSectGlobal:
- ReadGlobalsSection();
- 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;
- UINT 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);
- funcInfo->m_readerInfo.index = funcIndex;
- 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(FunctionBodyReaderInfo 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 len = 0;
- uint32 entryCount = LEB128(len);
- m_funcState.count += len;
- WasmFunctionInfo* funcInfo = m_module->GetWasmFunctionInfo(readerInfo.index);
- // locals
- for (uint32 j = 0; j < entryCount; j++)
- {
- uint32 count = LEB128(len);
- m_funcState.count += len;
- WasmTypes::WasmType type = ReadWasmType(len);
- if (!WasmTypes::IsLocalType(type))
- {
- ThrowDecodingError(_u("Invalid local type"));
- }
- m_funcState.count += len;
- funcInfo->AddLocal(type, count);
- switch (type)
- {
- case WasmTypes::I32: TRACE_WASM_DECODER(_u("Local: type = I32, count = %u"), count); break;
- case WasmTypes::I64: TRACE_WASM_DECODER(_u("Local: type = I64, count = %u"), count); break;
- case WasmTypes::F32: TRACE_WASM_DECODER(_u("Local: type = F32, count = %u"), count); break;
- case WasmTypes::F64: TRACE_WASM_DECODER(_u("Local: type = F64, count = %u"), count); break;
- break;
- default:
- break;
- }
- }
- }
- 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 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()
- {
- UINT 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()
- {
- UINT 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()
- {
- UINT len = 0;
- m_currentNode.br.depth = LEB128(len);
- m_funcState.count += len;
- }
- void
- WasmBinaryReader::BrTableNode()
- {
- UINT len = 0;
- m_currentNode.brTable.numTargets = LEB128(len);
- 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()
- {
- uint 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()
- {
- UINT length;
- m_currentNode.var.num = LEB128(length);
- m_funcState.count += length;
- }
- // Const
- template <WasmTypes::WasmType localType>
- void WasmBinaryReader::ConstNode()
- {
- UINT 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);
- }
- // readers
- void
- WasmBinaryReader::ReadMemorySection(bool isImportSection)
- {
- UINT 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)
- {
- uint32 flags = LEB128(length);
- uint32 minPage = LEB128(length);
- if (minPage > 65536)
- {
- throw Wasm::WasmCompilationException(_u("Memory size must be at most 65536 pages (4GiB)"));
- }
- uint32 maxPage = UINT32_MAX;
- if (flags & 0x1)
- {
- maxPage = LEB128(length);
- if (maxPage > 65536)
- {
- throw Wasm::WasmCompilationException(_u("Memory size must be at most 65536 pages (4GiB)"));
- }
- }
- m_module->InitializeMemory(minPage, maxPage);
- }
- }
- void
- WasmBinaryReader::ReadSignatures()
- {
- UINT len = 0;
- const uint32 count = LEB128(len);
- m_module->SetSignatureCount(count);
- // signatures table
- for (UINT32 i = 0; i < count; 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 paramCount = LEB128(len);
- WasmTypes::WasmType type;
- sig->AllocateParams(paramCount, m_module->GetRecycler());
- for (UINT32 j = 0; j < paramCount; j++)
- {
- type = ReadWasmType(len);
- sig->SetParam(type, j);
- }
- UINT32 resultCount = LEB128(len);
- if (resultCount != 0 && resultCount != 1)
- {
- ThrowDecodingError(_u("Unexpected result count %u"), resultCount);
- }
- if (resultCount == 1)
- {
- type = ReadWasmType(len);
- sig->SetResultType(type);
- }
- sig->FinalizeSignature();
- }
- }
- void
- WasmBinaryReader::ReadFunctionsSignatures()
- {
- UINT len = 0;
- uint32 nFunctions = LEB128(len);
- 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::ReadExportTable()
- {
- uint32 length;
- uint32 entries = LEB128(length);
- m_module->AllocateFunctionExports(entries);
- 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 < entries; iExport++)
- {
- uint32 nameLength;
- const char16* exportName = ReadInlineName(length, nameLength);
- // Check if the name is already used
- NameList* list;
- 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);
- }
- uint32 flags = LEB128(length);
- uint32 initialLength = LEB128(length);
- uint32 maximumLength = UINT32_MAX;
- if (flags & 0x1)
- {
- maximumLength = LEB128(length);
- }
- m_module->InitializeTable(initialLength, maximumLength);
- TRACE_WASM_DECODER(_u("Indirect table: %u to %u entries"), initialLength, maximumLength);
- }
- }
- void
- WasmBinaryReader::ReadElementSection()
- {
- uint32 length = 0;
- uint32 count = LEB128(length);
- if (count != 0)
- {
- m_module->AllocateElementSegs(count);
- }
- TRACE_WASM_DECODER(_u("Indirect table element: %u entries"), count);
- for (uint32 i = 0; i < count; ++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);
- 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);
- }
- m_module->SetElementSeg(eSeg, i);
- }
- }
- void
- WasmBinaryReader::ReadDataSegments()
- {
- UINT len = 0;
- const uint32 entries = LEB128(len);
- if (entries > 0)
- {
- m_module->AllocateDataSegs(entries);
- }
- for (uint32 i = 0; i < entries; ++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 offset = initExpr.cnst.i32;
- 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::ReadNamesSection()
- {
- UINT len = 0;
- UINT numEntries = LEB128(len);
- for (UINT i = 0; i < numEntries; ++i)
- {
- UINT fnNameLen = 0;
- WasmFunctionInfo* funsig = m_module->GetWasmFunctionInfo(i);
- const char16* name = ReadInlineName(len, fnNameLen);
- funsig->SetName(name, fnNameLen);
- UINT numLocals = LEB128(len);
- if (numLocals != funsig->GetLocalCount())
- {
- ThrowDecodingError(_u("num locals mismatch in names section"));
- }
- for (UINT j = 0; j < numLocals; ++j)
- {
- UINT localNameLen = 0;
- ReadInlineName(len, localNameLen);
- }
- }
- }
- void
- WasmBinaryReader::ReadGlobalsSection()
- {
- UINT len = 0;
- UINT numEntries = LEB128(len);
- for (UINT i = 0; i < numEntries; ++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)
- {
- nameLength = LEB128(length);
- CheckBytesLeft(nameLength);
- LPCUTF8 rawName = m_pc;
- m_pc += nameLength;
- length += nameLength;
- return CvtUtf8Str(rawName, nameLength, &nameLength);
- }
- const char16*
- WasmBinaryReader::CvtUtf8Str(LPCUTF8 name, uint32 nameLen, charcount_t* dstLength)
- {
- utf8::DecodeOptions decodeOptions = utf8::doDefault;
- charcount_t utf16Len = utf8::ByteIndexIntoCharacterIndex(name, nameLen, decodeOptions);
- char16* contents = AnewArray(m_alloc, char16, utf16Len + 1);
- if (contents == nullptr)
- {
- Js::Throw::OutOfMemory();
- }
- utf8::DecodeUnitsIntoAndNullTerminate(contents, name, name + nameLen, decodeOptions);
- if (dstLength)
- {
- *dstLength = utf16Len;
- }
- return contents;
- }
- void
- WasmBinaryReader::ReadImportEntries()
- {
- uint32 len = 0;
- uint32 entries = LEB128(len);
- for (uint32 i = 0; i < entries; ++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);
- 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);
- 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(UINT &length, bool sgn)
- {
- MaxAllowedType result = 0;
- uint shamt = 0;
- byte b = 0;
- length = 1;
- uint maxReads = sizeof(MaxAllowedType) == 4 ? 5 : 10;
- CompileAssert(sizeof(MaxAllowedType) == 4 || sizeof(MaxAllowedType) == 8);
- for (uint 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<>
- INT
- WasmBinaryReader::SLEB128(UINT &length)
- {
- INT result = LEB128<UINT>(length, true);
- TRACE_WASM_LEB128(_u("Binary decoder: SLEB128 length = %u, value = %d (0x%x)"), length, result, result);
- return result;
- }
- template<>
- INT64
- WasmBinaryReader::SLEB128(UINT &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;
- }
- 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(UINT bytesNeeded)
- {
- UINT bytesLeft = (UINT)(m_end - m_pc);
- if (bytesNeeded > bytesLeft)
- {
- ThrowDecodingError(_u("Out of file: Needed: %d, Left: %d"), bytesNeeded, bytesLeft);
- }
- }
- } // namespace Wasm
- #undef TRACE_WASM_DECODER
- #endif // ENABLE_WASM
|