WebKit Bugzilla
Attachment 348102 Details for
Bug 188943
: [WebAssembly] Parse wasm modules in a streaming fashion
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188943-20180827065444.patch (text/plain), 116.91 KB, created by
Yusuke Suzuki
on 2018-08-26 14:54:45 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-08-26 14:54:45 PDT
Size:
116.91 KB
patch
obsolete
>Subversion Revision: 235338 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 4dcf16a4470fb9a46f998e5a3d8cbceb3dd4171e..3b979b8e9865d3e785f75250c8e8deac9dcec38f 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,87 @@ >+2018-08-26 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ [WebAssembly] Parse wasm modules in a streaming fashion >+ https://bugs.webkit.org/show_bug.cgi?id=188943 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Sources.txt: >+ * tools/JSDollarVM.cpp: >+ (WTF::WasmStreamingParser::WasmStreamingParser): >+ (WTF::WasmStreamingParser::create): >+ (WTF::WasmStreamingParser::createStructure): >+ (WTF::WasmStreamingParser::streamingParser): >+ (WTF::WasmStreamingParser::finishCreation): >+ (WTF::functionWasmStreamingParserAddBytes): >+ (WTF::functionWasmStreamingParserFinalize): >+ (JSC::functionCreateWasmStreamingParser): >+ (JSC::JSDollarVM::finishCreation): >+ * wasm/WasmModuleInformation.h: >+ (JSC::Wasm::ModuleInformation::memoryCount const): >+ (JSC::Wasm::ModuleInformation::tableCount const): >+ * wasm/WasmModuleParser.cpp: >+ (JSC::Wasm::ModuleParser::parse): >+ (JSC::Wasm::makeI32InitExpr): Deleted. >+ (JSC::Wasm::ModuleParser::parseType): Deleted. >+ (JSC::Wasm::ModuleParser::parseImport): Deleted. >+ (JSC::Wasm::ModuleParser::parseFunction): Deleted. >+ (JSC::Wasm::ModuleParser::parseResizableLimits): Deleted. >+ (JSC::Wasm::ModuleParser::parseTableHelper): Deleted. >+ (JSC::Wasm::ModuleParser::parseTable): Deleted. >+ (JSC::Wasm::ModuleParser::parseMemoryHelper): Deleted. >+ (JSC::Wasm::ModuleParser::parseMemory): Deleted. >+ (JSC::Wasm::ModuleParser::parseGlobal): Deleted. >+ (JSC::Wasm::ModuleParser::parseExport): Deleted. >+ (JSC::Wasm::ModuleParser::parseStart): Deleted. >+ (JSC::Wasm::ModuleParser::parseElement): Deleted. >+ (JSC::Wasm::ModuleParser::parseCode): Deleted. >+ (JSC::Wasm::ModuleParser::parseInitExpr): Deleted. >+ (JSC::Wasm::ModuleParser::parseGlobalType): Deleted. >+ (JSC::Wasm::ModuleParser::parseData): Deleted. >+ (JSC::Wasm::ModuleParser::parseCustom): Deleted. >+ * wasm/WasmModuleParser.h: >+ * wasm/WasmParser.h: >+ (JSC::Wasm::Parser::source const): >+ (JSC::Wasm::Parser::length const): >+ (JSC::Wasm::Parser::offset const): >+ (JSC::Wasm::Parser::fail const): >+ (JSC::Wasm::makeI32InitExpr): >+ * wasm/WasmSectionParser.cpp: Copied from Source/JavaScriptCore/wasm/WasmModuleParser.cpp. >+ (JSC::Wasm::SectionParser::parseType): >+ (JSC::Wasm::SectionParser::parseImport): >+ (JSC::Wasm::SectionParser::parseFunction): >+ (JSC::Wasm::SectionParser::parseResizableLimits): >+ (JSC::Wasm::SectionParser::parseTableHelper): >+ (JSC::Wasm::SectionParser::parseTable): >+ (JSC::Wasm::SectionParser::parseMemoryHelper): >+ (JSC::Wasm::SectionParser::parseMemory): >+ (JSC::Wasm::SectionParser::parseGlobal): >+ (JSC::Wasm::SectionParser::parseExport): >+ (JSC::Wasm::SectionParser::parseStart): >+ (JSC::Wasm::SectionParser::parseElement): >+ (JSC::Wasm::SectionParser::parseCode): >+ (JSC::Wasm::SectionParser::parseInitExpr): >+ (JSC::Wasm::SectionParser::parseGlobalType): >+ (JSC::Wasm::SectionParser::parseData): >+ (JSC::Wasm::SectionParser::parseCustom): >+ * wasm/WasmSectionParser.h: Copied from Source/JavaScriptCore/wasm/WasmModuleParser.h. >+ * wasm/WasmStreamingParser.cpp: Added. >+ (JSC::Wasm::parseUInt7): >+ (JSC::Wasm::StreamingParser::StreamingParser): >+ (JSC::Wasm::StreamingParser::parseModuleHeader): >+ (JSC::Wasm::StreamingParser::parseSectionHeader): >+ (JSC::Wasm::StreamingParser::parseSectionSize): >+ (JSC::Wasm::StreamingParser::parseCodeSectionSize): >+ (JSC::Wasm::StreamingParser::parseFunctionHeader): >+ (JSC::Wasm::StreamingParser::parseFunctionBody): >+ (JSC::Wasm::StreamingParser::parseSectionBody): >+ (JSC::Wasm::StreamingParser::consume): >+ (JSC::Wasm::StreamingParser::consumeVarUInt32): >+ (JSC::Wasm::StreamingParser::addBytes): >+ (JSC::Wasm::StreamingParser::finalize): >+ * wasm/WasmStreamingParser.h: Added. >+ (JSC::Wasm::StreamingParser::addBytes): >+ > 2018-08-24 Michael Saboff <msaboff@apple.com> > > YARR: Update UCS canonicalization tables for Unicode 11 >diff --git a/Source/JavaScriptCore/Sources.txt b/Source/JavaScriptCore/Sources.txt >index 897698c6e059ae1d262131ac520400e3178edcc5..04d48e85b50fb83fb12505fee14a85359cc1e309 100644 >--- a/Source/JavaScriptCore/Sources.txt >+++ b/Source/JavaScriptCore/Sources.txt >@@ -992,7 +992,9 @@ wasm/WasmOMGPlan.cpp > wasm/WasmOpcodeOrigin.cpp > wasm/WasmPageCount.cpp > wasm/WasmPlan.cpp >+wasm/WasmSectionParser.cpp > wasm/WasmSignature.cpp >+wasm/WasmStreamingParser.cpp > wasm/WasmTable.cpp > wasm/WasmTable.h > wasm/WasmThunks.cpp >diff --git a/Source/JavaScriptCore/tools/JSDollarVM.cpp b/Source/JavaScriptCore/tools/JSDollarVM.cpp >index eb57c784c98180462d4a8e43c86b50baaae8493b..0536b78cc89151d386acaeabb51ce3ce72f09e76 100644 >--- a/Source/JavaScriptCore/tools/JSDollarVM.cpp >+++ b/Source/JavaScriptCore/tools/JSDollarVM.cpp >@@ -51,6 +51,11 @@ > #include <wtf/ProcessID.h> > #include <wtf/StringPrintStream.h> > >+#if ENABLE(WEBASSEMBLY) >+#include "JSWebAssemblyHelpers.h" >+#include "WasmStreamingParser.h" >+#endif >+ > using namespace JSC; > using namespace WTF; > >@@ -1093,6 +1098,80 @@ void Element::finishCreation(VM& vm, Root* root) > m_root->setElement(this); > } > >+#if ENABLE(WEBASSEMBLY) >+ >+static EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState*); >+static EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserFinalize(ExecState*); >+ >+class WasmStreamingParser : public JSDestructibleObject { >+public: >+ WasmStreamingParser(VM& vm, Structure* structure) >+ : Base(vm, structure) >+ , m_info(adoptRef(*new Wasm::ModuleInformation(Vector<uint8_t>()))) >+ , m_streamingParser(m_info.get()) >+ { >+ } >+ >+ using Base = JSDestructibleObject; >+ >+ static WasmStreamingParser* create(VM& vm, JSGlobalObject* globalObject) >+ { >+ Structure* structure = createStructure(vm, globalObject, jsNull()); >+ WasmStreamingParser* result = new (NotNull, allocateCell<WasmStreamingParser>(vm.heap, sizeof(WasmStreamingParser))) WasmStreamingParser(vm, structure); >+ result->finishCreation(vm); >+ return result; >+ } >+ >+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) >+ { >+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); >+ } >+ >+ Wasm::StreamingParser& streamingParser() { return m_streamingParser; } >+ >+ void finishCreation(VM& vm) >+ { >+ Base::finishCreation(vm); >+ >+ JSGlobalObject* globalObject = this->globalObject(vm); >+ putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "addBytes"), 0, functionWasmStreamingParserAddBytes, NoIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); >+ putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "finalize"), 0, functionWasmStreamingParserFinalize, NoIntrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); >+ } >+ >+ DECLARE_INFO; >+ >+ Ref<Wasm::ModuleInformation> m_info; >+ Wasm::StreamingParser m_streamingParser; >+}; >+ >+const ClassInfo WasmStreamingParser::s_info = { "WasmStreamingParser", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(WasmStreamingParser) }; >+ >+EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserAddBytes(ExecState* exec) >+{ >+ VM& vm = exec->vm(); >+ auto scope = DECLARE_THROW_SCOPE(exec->vm()); >+ auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue()); >+ if (!thisObject) { >+ scope.release(); >+ return JSValue::encode(jsBoolean(false)); >+ } >+ auto data = getWasmBufferFromValue(exec, exec->argument(0)); >+ RETURN_IF_EXCEPTION(scope, encodedJSValue()); >+ scope.release(); >+ return JSValue::encode(jsNumber(static_cast<int32_t>(thisObject->streamingParser().addBytes(bitwise_cast<const uint8_t*>(data.first), data.second)))); >+} >+ >+EncodedJSValue JSC_HOST_CALL functionWasmStreamingParserFinalize(ExecState* exec) >+{ >+ VM& vm = exec->vm(); >+ auto* thisObject = jsDynamicCast<WasmStreamingParser*>(vm, exec->thisValue()); >+ if (!thisObject) >+ return JSValue::encode(jsBoolean(false)); >+ return JSValue::encode(jsNumber(static_cast<int32_t>(thisObject->streamingParser().finalize()))); >+} >+ >+#endif >+ > } // namespace > > namespace JSC { >@@ -1640,6 +1719,15 @@ static EncodedJSValue JSC_HOST_CALL functionCreateDOMJITGetterBaseJSObject(ExecS > return JSValue::encode(result); > } > >+#if ENABLE(WEBASSEMBLY) >+static EncodedJSValue JSC_HOST_CALL functionCreateWasmStreamingParser(ExecState* exec) >+{ >+ VM& vm = exec->vm(); >+ JSLockHolder lock(vm); >+ return JSValue::encode(WasmStreamingParser::create(vm, exec->lexicalGlobalObject())); >+} >+#endif >+ > static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState* exec) > { > VM& vm = exec->vm(); >@@ -2040,6 +2128,9 @@ void JSDollarVM::finishCreation(VM& vm) > addFunction(vm, "createDOMJITCheckSubClassObject", functionCreateDOMJITCheckSubClassObject, 0); > addFunction(vm, "createDOMJITGetterBaseJSObject", functionCreateDOMJITGetterBaseJSObject, 0); > addFunction(vm, "createBuiltin", functionCreateBuiltin, 2); >+#if ENABLE(WEBASSEMBLY) >+ addFunction(vm, "createWasmStreamingParser", functionCreateWasmStreamingParser, 0); >+#endif > addFunction(vm, "getPrivateProperty", functionGetPrivateProperty, 2); > addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2); > >diff --git a/Source/JavaScriptCore/wasm/WasmModuleInformation.h b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >index 0bab57e070d2ea33062f363658a2415e9bd51e2d..16d5259a7257a5790c048f89dd3e4294d67e34fe 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleInformation.h >+++ b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >@@ -58,6 +58,9 @@ struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { > uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); } > uint32_t internalFunctionCount() const { return internalFunctionSignatureIndices.size(); } > >+ uint32_t memoryCount() const { return memory ? 1 : 0; } >+ uint32_t tableCount() const { return tableInformation ? 1 : 0; } >+ > const Vector<uint8_t> source; > const std::optional<CString> hash; > >diff --git a/Source/JavaScriptCore/wasm/WasmModuleParser.cpp b/Source/JavaScriptCore/wasm/WasmModuleParser.cpp >index f03e6987f4a502591df71dc815782080996138b4..0d540f166e871c160fe5f06805d984d8694003ca 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleParser.cpp >+++ b/Source/JavaScriptCore/wasm/WasmModuleParser.cpp >@@ -32,18 +32,11 @@ > #include "WasmMemoryInformation.h" > #include "WasmNameSectionParser.h" > #include "WasmOps.h" >+#include "WasmSectionParser.h" > #include "WasmSections.h" > > namespace JSC { namespace Wasm { > >-ALWAYS_INLINE I32InitExpr makeI32InitExpr(uint8_t opcode, uint32_t bits) >-{ >- RELEASE_ASSERT(opcode == I32Const || opcode == GetGlobal); >- if (opcode == I32Const) >- return I32InitExpr::constValue(bits); >- return I32InitExpr::globalImport(bits); >-} >- > auto ModuleParser::parse() -> Result > { > const size_t minSize = 8; >@@ -71,19 +64,19 @@ auto ModuleParser::parse() -> Result > WASM_PARSER_FAIL_IF(!parseVarUInt32(sectionLength), "can't get ", section, " section's length"); > WASM_PARSER_FAIL_IF(sectionLength > length() - m_offset, section, " section of size ", sectionLength, " would overflow Module's size"); > >- auto end = m_offset + sectionLength; >+ SectionParser parser(source() + m_offset, sectionLength, m_offset, m_info.get()); > > switch (section) { > #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \ > case Section::NAME: { \ >- WASM_FAIL_IF_HELPER_FAILS(parse ## NAME()); \ >+ WASM_FAIL_IF_HELPER_FAILS(parser.parse ## NAME()); \ > break; \ > } > FOR_EACH_KNOWN_WASM_SECTION(WASM_SECTION_PARSE) > #undef WASM_SECTION_PARSE > > case Section::Custom: { >- WASM_FAIL_IF_HELPER_FAILS(parseCustom(sectionLength)); >+ WASM_FAIL_IF_HELPER_FAILS(parser.parseCustom()); > break; > } > >@@ -93,7 +86,9 @@ auto ModuleParser::parse() -> Result > } > } > >- WASM_PARSER_FAIL_IF(end != m_offset, "parsing ended before the end of ", section, " section"); >+ WASM_PARSER_FAIL_IF(parser.length() != parser.offset(), "parsing ended before the end of ", section, " section"); >+ >+ m_offset += sectionLength; > > > if (isKnownSection(section)) >@@ -103,528 +98,6 @@ auto ModuleParser::parse() -> Result > return { }; > } > >-auto ModuleParser::parseType() -> PartialResult >-{ >- uint32_t count; >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count"); >- WASM_PARSER_FAIL_IF(count > maxTypes, "Type section's count is too big ", count, " maximum ", maxTypes); >- WASM_PARSER_FAIL_IF(!m_info->usedSignatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries"); >- >- for (uint32_t i = 0; i < count; ++i) { >- int8_t type; >- uint32_t argumentCount; >- Vector<Type> argumentTypes; >- >- WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type"); >- WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count"); >- WASM_PARSER_FAIL_IF(argumentCount > maxFunctionParams, i, "th argument count is too big ", argumentCount, " maximum ", maxFunctionParams); >- RefPtr<Signature> maybeSignature = Signature::tryCreate(argumentCount); >- WASM_PARSER_FAIL_IF(!maybeSignature, "can't allocate enough memory for Type section's ", i, "th signature"); >- Ref<Signature> signature = maybeSignature.releaseNonNull(); >- >- for (unsigned i = 0; i < argumentCount; ++i) { >- Type argumentType; >- WASM_PARSER_FAIL_IF(!parseValueType(argumentType), "can't get ", i, "th argument Type"); >- signature->argument(i) = argumentType; >- } >- >- uint8_t returnCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count"); >- Type returnType; >- if (returnCount) { >- Type value; >- WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value"); >- returnType = static_cast<Type>(value); >- } else >- returnType = Type::Void; >- signature->returnType() = returnType; >- >- std::pair<SignatureIndex, Ref<Signature>> result = SignatureInformation::adopt(WTFMove(signature)); >- m_info->usedSignatures.uncheckedAppend(WTFMove(result.second)); >- } >- return { }; >-} >- >-auto ModuleParser::parseImport() -> PartialResult >-{ >- uint32_t importCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count"); >- WASM_PARSER_FAIL_IF(importCount > maxImports, "Import section's count is too big ", importCount, " maximum ", maxImports); >- WASM_PARSER_FAIL_IF(!m_info->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below. >- WASM_PARSER_FAIL_IF(!m_info->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below. >- WASM_PARSER_FAIL_IF(!m_info->importFunctionSignatureIndices.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import function signatures"); // FIXME this over-allocates when we fix the FIXMEs below. >- >- for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) { >- uint32_t moduleLen; >- uint32_t fieldLen; >- Name moduleString; >- Name fieldString; >- ExternalKind kind; >- unsigned kindIndex { 0 }; >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length"); >- WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen); >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'"); >- WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'"); >- >- WASM_PARSER_FAIL_IF(!parseExternalKind(kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'"); >- switch (kind) { >- case ExternalKind::Function: { >- uint32_t functionSignatureIndex; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'"); >- WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_info->usedSignatures.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_info->usedSignatures.size(), " in module '", moduleString, "' field '", fieldString, "'"); >- kindIndex = m_info->importFunctionSignatureIndices.size(); >- SignatureIndex signatureIndex = SignatureInformation::get(m_info->usedSignatures[functionSignatureIndex]); >- m_info->importFunctionSignatureIndices.uncheckedAppend(signatureIndex); >- break; >- } >- case ExternalKind::Table: { >- bool isImport = true; >- PartialResult result = parseTableHelper(isImport); >- if (UNLIKELY(!result)) >- return makeUnexpected(WTFMove(result.error())); >- break; >- } >- case ExternalKind::Memory: { >- bool isImport = true; >- PartialResult result = parseMemoryHelper(isImport); >- if (UNLIKELY(!result)) >- return makeUnexpected(WTFMove(result.error())); >- break; >- } >- case ExternalKind::Global: { >- Global global; >- WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); >- WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported"); >- >- kindIndex = m_info->globals.size(); >- m_info->globals.uncheckedAppend(WTFMove(global)); >- break; >- } >- } >- >- m_info->imports.uncheckedAppend({ WTFMove(moduleString), WTFMove(fieldString), kind, kindIndex }); >- } >- >- m_info->firstInternalGlobal = m_info->globals.size(); >- return { }; >-} >- >-auto ModuleParser::parseFunction() -> PartialResult >-{ >- uint32_t count; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count"); >- WASM_PARSER_FAIL_IF(count > maxFunctions, "Function section's count is too big ", count, " maximum ", maxFunctions); >- WASM_PARSER_FAIL_IF(!m_info->internalFunctionSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures"); >- WASM_PARSER_FAIL_IF(!m_info->functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations"); >- >- for (uint32_t i = 0; i < count; ++i) { >- uint32_t typeNumber; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number"); >- WASM_PARSER_FAIL_IF(typeNumber >= m_info->usedSignatures.size(), i, "th Function type number is invalid ", typeNumber); >- >- SignatureIndex signatureIndex = SignatureInformation::get(m_info->usedSignatures[typeNumber]); >- // The Code section fixes up start and end. >- size_t start = 0; >- size_t end = 0; >- m_info->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex); >- m_info->functionLocationInBinary.uncheckedAppend({ start, end }); >- } >- >- return { }; >-} >- >-auto ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult >-{ >- ASSERT(!maximum); >- >- uint8_t flags; >- WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags"); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count"); >- >- if (flags) { >- uint32_t maximumInt; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count"); >- WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt); >- maximum = maximumInt; >- } >- >- return { }; >-} >- >-auto ModuleParser::parseTableHelper(bool isImport) -> PartialResult >-{ >- WASM_PARSER_FAIL_IF(m_tableCount > 0, "Cannot have more than one Table for now"); >- >- ++m_tableCount; >- >- int8_t type; >- WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type"); >- WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type); >- >- uint32_t initial; >- std::optional<uint32_t> maximum; >- PartialResult limits = parseResizableLimits(initial, maximum); >- if (UNLIKELY(!limits)) >- return makeUnexpected(WTFMove(limits.error())); >- WASM_PARSER_FAIL_IF(initial > maxTableEntries, "Table's initial page count of ", initial, " is too big, maximum ", maxTableEntries); >- >- ASSERT(!maximum || *maximum >= initial); >- >- m_info->tableInformation = TableInformation(initial, maximum, isImport); >- >- return { }; >-} >- >-auto ModuleParser::parseTable() -> PartialResult >-{ >- uint32_t count; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count"); >- WASM_PARSER_FAIL_IF(count > 1, "Table count of ", count, " is invalid, at most 1 is allowed for now"); >- >- if (!count) >- return { }; >- >- bool isImport = false; >- PartialResult result = parseTableHelper(isImport); >- if (UNLIKELY(!result)) >- return makeUnexpected(WTFMove(result.error())); >- >- return { }; >-} >- >-auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult >-{ >- WASM_PARSER_FAIL_IF(m_memoryCount, "there can at most be one Memory section for now"); >- >- ++m_memoryCount; >- >- PageCount initialPageCount; >- PageCount maximumPageCount; >- { >- uint32_t initial; >- std::optional<uint32_t> maximum; >- PartialResult limits = parseResizableLimits(initial, maximum); >- if (UNLIKELY(!limits)) >- return makeUnexpected(WTFMove(limits.error())); >- ASSERT(!maximum || *maximum >= initial); >- WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid"); >- >- initialPageCount = PageCount(initial); >- >- if (maximum) { >- WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid"); >- maximumPageCount = PageCount(*maximum); >- } >- } >- ASSERT(initialPageCount); >- ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount); >- >- m_info->memory = MemoryInformation(initialPageCount, maximumPageCount, isImport); >- return { }; >-} >- >-auto ModuleParser::parseMemory() -> PartialResult >-{ >- uint8_t count; >- WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count"); >- >- if (!count) >- return { }; >- >- WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one"); >- >- bool isImport = false; >- return parseMemoryHelper(isImport); >-} >- >-auto ModuleParser::parseGlobal() -> PartialResult >-{ >- uint32_t globalCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count"); >- WASM_PARSER_FAIL_IF(globalCount > maxGlobals, "Global section's count is too big ", globalCount, " maximum ", maxGlobals); >- size_t totalBytes = globalCount + m_info->firstInternalGlobal; >- WASM_PARSER_FAIL_IF((static_cast<uint32_t>(totalBytes) < globalCount) || !m_info->globals.tryReserveCapacity(totalBytes), "can't allocate memory for ", totalBytes, " globals"); >- >- for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) { >- Global global; >- uint8_t initOpcode; >- >- WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); >- Type typeForInitOpcode; >- WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber, typeForInitOpcode)); >- if (initOpcode == GetGlobal) >- global.initializationType = Global::FromGlobalImport; >- else >- global.initializationType = Global::FromExpression; >- WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type); >- >- m_info->globals.uncheckedAppend(WTFMove(global)); >- } >- >- return { }; >-} >- >-auto ModuleParser::parseExport() -> PartialResult >-{ >- uint32_t exportCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count"); >- WASM_PARSER_FAIL_IF(exportCount > maxExports, "Export section's count is too big ", exportCount, " maximum ", maxExports); >- WASM_PARSER_FAIL_IF(!m_info->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports"); >- >- HashSet<String> exportNames; >- for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) { >- uint32_t fieldLen; >- Name fieldString; >- ExternalKind kind; >- unsigned kindIndex; >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length"); >- WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen); >- String fieldName = String::fromUTF8(fieldString); >- WASM_PARSER_FAIL_IF(exportNames.contains(fieldName), "duplicate export: '", fieldString, "'"); >- exportNames.add(fieldName); >- >- WASM_PARSER_FAIL_IF(!parseExternalKind(kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'"); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'"); >- switch (kind) { >- case ExternalKind::Function: { >- WASM_PARSER_FAIL_IF(kindIndex >= m_info->functionIndexSpaceSize(), exportNumber, "th Export has invalid function number ", kindIndex, " it exceeds the function index space ", m_info->functionIndexSpaceSize(), ", named '", fieldString, "'"); >- break; >- } >- case ExternalKind::Table: { >- WASM_PARSER_FAIL_IF(kindIndex >= m_tableCount, "can't export Table ", kindIndex, " there are ", m_tableCount, " Tables"); >- break; >- } >- case ExternalKind::Memory: { >- WASM_PARSER_FAIL_IF(!m_info->memory, "can't export a non-existent Memory"); >- WASM_PARSER_FAIL_IF(kindIndex, "can't export Memory ", kindIndex, " only one Table is currently supported"); >- break; >- } >- case ExternalKind::Global: { >- WASM_PARSER_FAIL_IF(kindIndex >= m_info->globals.size(), exportNumber, "th Export has invalid global number ", kindIndex, " it exceeds the globals count ", m_info->globals.size(), ", named '", fieldString, "'"); >- WASM_PARSER_FAIL_IF(m_info->globals[kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'"); >- break; >- } >- } >- >- m_info->exports.uncheckedAppend({ WTFMove(fieldString), kind, kindIndex }); >- } >- >- return { }; >-} >- >-auto ModuleParser::parseStart() -> PartialResult >-{ >- uint32_t startFunctionIndex; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index"); >- WASM_PARSER_FAIL_IF(startFunctionIndex >= m_info->functionIndexSpaceSize(), "Start index ", startFunctionIndex, " exceeds function index space ", m_info->functionIndexSpaceSize()); >- SignatureIndex signatureIndex = m_info->signatureIndexFromFunctionIndexSpace(startFunctionIndex); >- const Signature& signature = SignatureInformation::get(signatureIndex); >- WASM_PARSER_FAIL_IF(signature.argumentCount(), "Start function can't have arguments"); >- WASM_PARSER_FAIL_IF(signature.returnType() != Void, "Start function can't return a value"); >- m_info->startFunctionIndexSpace = startFunctionIndex; >- return { }; >-} >- >-auto ModuleParser::parseElement() -> PartialResult >-{ >- uint32_t elementCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count"); >- WASM_PARSER_FAIL_IF(elementCount > maxTableEntries, "Element section's count is too big ", elementCount, " maximum ", maxTableEntries); >- WASM_PARSER_FAIL_IF(!m_info->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements"); >- for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) { >- uint32_t tableIndex; >- uint64_t initExprBits; >- uint8_t initOpcode; >- uint32_t indexCount; >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index"); >- WASM_PARSER_FAIL_IF(tableIndex >= m_tableCount, "Element section for Table ", tableIndex, " exceeds available Table ", m_tableCount); >- Type initExprType; >- WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType)); >- WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32"); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section"); >- WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount); >- >- ASSERT(!!m_info->tableInformation); >- >- Element element(makeI32InitExpr(initOpcode, initExprBits)); >- WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices"); >- >- for (unsigned index = 0; index < indexCount; ++index) { >- uint32_t functionIndex; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index"); >- WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize()); >- >- element.functionIndices.uncheckedAppend(functionIndex); >- } >- >- m_info->elements.uncheckedAppend(WTFMove(element)); >- } >- >- return { }; >-} >- >-auto ModuleParser::parseCode() -> PartialResult >-{ >- uint32_t count; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count"); >- WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count); >- WASM_PARSER_FAIL_IF(count != m_info->functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_info->functionLocationInBinary.size()); >- >- for (uint32_t i = 0; i < count; ++i) { >- uint32_t functionSize; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size"); >- WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length()); >- WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset); >- WASM_PARSER_FAIL_IF(functionSize > maxFunctionSize, "Code function's size ", functionSize, " is too big"); >- >- m_info->functionLocationInBinary[i].start = m_offset; >- m_info->functionLocationInBinary[i].end = m_offset + functionSize; >- m_offset = m_info->functionLocationInBinary[i].end; >- } >- >- return { }; >-} >- >-auto ModuleParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber, Type& resultType) -> PartialResult >-{ >- WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode"); >- >- switch (opcode) { >- case I32Const: { >- int32_t constant; >- WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const"); >- bitsOrImportNumber = static_cast<uint64_t>(constant); >- resultType = I32; >- break; >- } >- >- case I64Const: { >- int64_t constant; >- WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const"); >- bitsOrImportNumber = constant; >- resultType = I64; >- break; >- } >- >- case F32Const: { >- uint32_t constant; >- WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const"); >- bitsOrImportNumber = constant; >- resultType = F32; >- break; >- } >- >- case F64Const: { >- uint64_t constant; >- WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const"); >- bitsOrImportNumber = constant; >- resultType = F64; >- break; >- } >- >- case GetGlobal: { >- uint32_t index; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index"); >- >- WASM_PARSER_FAIL_IF(index >= m_info->globals.size(), "get_global's index ", index, " exceeds the number of globals ", m_info->globals.size()); >- WASM_PARSER_FAIL_IF(index >= m_info->firstInternalGlobal, "get_global import kind index ", index, " exceeds the first internal global ", m_info->firstInternalGlobal); >- >- ASSERT(m_info->globals[index].mutability == Global::Immutable); >- resultType = m_info->globals[index].type; >- bitsOrImportNumber = index; >- break; >- } >- >- default: >- WASM_PARSER_FAIL_IF(true, "unknown init_expr opcode ", opcode); >- } >- >- uint8_t endOpcode; >- WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode"); >- WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode); >- >- return { }; >-} >- >-auto ModuleParser::parseGlobalType(Global& global) -> PartialResult >-{ >- uint8_t mutability; >- WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type"); >- WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability"); >- global.mutability = static_cast<Global::Mutability>(mutability); >- return { }; >-} >- >-auto ModuleParser::parseData() -> PartialResult >-{ >- uint32_t segmentCount; >- WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count"); >- WASM_PARSER_FAIL_IF(segmentCount > maxDataSegments, "Data section's count is too big ", segmentCount, " maximum ", maxDataSegments); >- WASM_PARSER_FAIL_IF(!m_info->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments"); >- >- for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) { >- uint32_t memoryIndex; >- uint64_t initExprBits; >- uint8_t initOpcode; >- uint32_t dataByteLength; >- >- WASM_PARSER_FAIL_IF(!parseVarUInt32(memoryIndex), "can't get ", segmentNumber, "th Data segment's index"); >- WASM_PARSER_FAIL_IF(memoryIndex >= m_memoryCount, segmentNumber, "th Data segment has index ", memoryIndex, " which exceeds the number of Memories ", m_memoryCount); >- Type initExprType; >- WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType)); >- WASM_PARSER_FAIL_IF(initExprType != I32, segmentNumber, "th Data segment's init_expr must produce an i32"); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length"); >- WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize); >- >- Segment* segment = Segment::create(makeI32InitExpr(initOpcode, initExprBits), dataByteLength); >- WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength); >- m_info->data.uncheckedAppend(Segment::adoptPtr(segment)); >- for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) { >- uint8_t byte; >- WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment"); >- segment->byte(dataByte) = byte; >- } >- } >- return { }; >-} >- >-auto ModuleParser::parseCustom(uint32_t sectionLength) -> PartialResult >-{ >- const uint32_t customSectionStartOffset = m_offset; >- >- CustomSection section; >- uint32_t customSectionNumber = m_info->customSections.size() + 1; >- uint32_t nameLen; >- WASM_PARSER_FAIL_IF(!m_info->customSections.tryReserveCapacity(customSectionNumber), "can't allocate enough memory for ", customSectionNumber, "th custom section"); >- WASM_PARSER_FAIL_IF(!parseVarUInt32(nameLen), "can't get ", customSectionNumber, "th custom section's name length"); >- WASM_PARSER_FAIL_IF(!consumeUTF8String(section.name, nameLen), "nameLen get ", customSectionNumber, "th custom section's name of length ", nameLen); >- >- uint32_t payloadBytes = sectionLength - (m_offset - customSectionStartOffset); >- WASM_PARSER_FAIL_IF(!section.payload.tryReserveCapacity(payloadBytes), "can't allocate enough memory for ", customSectionNumber, "th custom section's ", payloadBytes, " bytes"); >- for (uint32_t byteNumber = 0; byteNumber < payloadBytes; ++byteNumber) { >- uint8_t byte; >- WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", byteNumber, "th data byte from ", customSectionNumber, "th custom section"); >- section.payload.uncheckedAppend(byte); >- } >- >- Name nameName = { 'n', 'a', 'm', 'e' }; >- if (section.name == nameName) { >- NameSectionParser nameSectionParser(section.payload.begin(), section.payload.size(), m_info); >- if (auto nameSection = nameSectionParser.parse()) >- m_info->nameSection = WTFMove(*nameSection); >- } >- >- m_info->customSections.uncheckedAppend(WTFMove(section)); >- >- return { }; >-} >- > } } // namespace JSC::Wasm > > #endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmModuleParser.h b/Source/JavaScriptCore/wasm/WasmModuleParser.h >index a651be17ce23b85fbb97bbb685703b39b64b72c4..2e9f687ba3c0c908c940b60dbd2beea8a433a707 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleParser.h >+++ b/Source/JavaScriptCore/wasm/WasmModuleParser.h >@@ -46,18 +46,6 @@ class ModuleParser : public Parser<void> { > Result WARN_UNUSED_RETURN parse(); > > private: >- >-#define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) PartialResult WARN_UNUSED_RETURN parse ## NAME(); >- FOR_EACH_KNOWN_WASM_SECTION(WASM_SECTION_DECLARE_PARSER) >-#undef WASM_SECTION_DECLARE_PARSER >- >- PartialResult WARN_UNUSED_RETURN parseCustom(uint32_t); >- PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&); >- PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport); >- PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport); >- PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum); >- PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType); >- > Ref<ModuleInformation> m_info; > uint32_t m_memoryCount { 0 }; > uint32_t m_tableCount { 0 }; >diff --git a/Source/JavaScriptCore/wasm/WasmParser.h b/Source/JavaScriptCore/wasm/WasmParser.h >index 6510705eaf578ce33e3bd76b2bc838adda5f5b00..9fc4a454c9b726fa13e84a4b473fead812bb99f0 100644 >--- a/Source/JavaScriptCore/wasm/WasmParser.h >+++ b/Source/JavaScriptCore/wasm/WasmParser.h >@@ -58,6 +58,10 @@ class Parser { > typedef Expected<void, ErrorType> PartialResult; > typedef Expected<SuccessType, ErrorType> Result; > >+ const uint8_t* source() const { return m_source; } >+ size_t length() const { return m_sourceLength; } >+ size_t offset() const { return m_offset; } >+ > protected: > Parser(const uint8_t*, size_t); > >@@ -81,16 +85,13 @@ class Parser { > bool WARN_UNUSED_RETURN parseValueType(Type&); > bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&); > >- const uint8_t* source() const { return m_source; } >- size_t length() const { return m_sourceLength; } >- > size_t m_offset = 0; > > template <typename ...Args> > NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const > { > using namespace FailureHelper; // See ADL comment in namespace above. >- return UnexpectedResult(makeString("WebAssembly.Module doesn't parse at byte "_s, String::number(m_offset), " / "_s, String::number(m_sourceLength), ": "_s, makeString(args)...)); >+ return UnexpectedResult(makeString("WebAssembly.Module doesn't parse at byte "_s, String::number(m_offset), ": "_s, makeString(args)...)); > } > #define WASM_PARSER_FAIL_IF(condition, ...) do { \ > if (UNLIKELY(condition)) \ >@@ -285,6 +286,14 @@ ALWAYS_INLINE bool Parser<SuccessType>::parseExternalKind(ExternalKind& result) > return true; > } > >+ALWAYS_INLINE I32InitExpr makeI32InitExpr(uint8_t opcode, uint32_t bits) >+{ >+ RELEASE_ASSERT(opcode == I32Const || opcode == GetGlobal); >+ if (opcode == I32Const) >+ return I32InitExpr::constValue(bits); >+ return I32InitExpr::globalImport(bits); >+} >+ > } } // namespace JSC::Wasm > > #endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..3b9bdf018086d14e87d30d3568becc79d1774ebf >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >@@ -0,0 +1,558 @@ >+/* >+ * Copyright (C) 2016-2018 Apple Inc. All rights reserved. >+ * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "WasmSectionParser.h" >+ >+#if ENABLE(WEBASSEMBLY) >+ >+#include "IdentifierInlines.h" >+#include "WasmMemoryInformation.h" >+#include "WasmNameSectionParser.h" >+#include "WasmOps.h" >+#include "WasmSections.h" >+ >+namespace JSC { namespace Wasm { >+ >+auto SectionParser::parseType() -> PartialResult >+{ >+ uint32_t count; >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Type section's count"); >+ WASM_PARSER_FAIL_IF(count > maxTypes, "Type section's count is too big ", count, " maximum ", maxTypes); >+ WASM_PARSER_FAIL_IF(!m_info->usedSignatures.tryReserveCapacity(count), "can't allocate enough memory for Type section's ", count, " entries"); >+ >+ for (uint32_t i = 0; i < count; ++i) { >+ int8_t type; >+ uint32_t argumentCount; >+ Vector<Type> argumentTypes; >+ >+ WASM_PARSER_FAIL_IF(!parseInt7(type), "can't get ", i, "th Type's type"); >+ WASM_PARSER_FAIL_IF(type != Func, i, "th Type is non-Func ", type); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(argumentCount), "can't get ", i, "th Type's argument count"); >+ WASM_PARSER_FAIL_IF(argumentCount > maxFunctionParams, i, "th argument count is too big ", argumentCount, " maximum ", maxFunctionParams); >+ RefPtr<Signature> maybeSignature = Signature::tryCreate(argumentCount); >+ WASM_PARSER_FAIL_IF(!maybeSignature, "can't allocate enough memory for Type section's ", i, "th signature"); >+ Ref<Signature> signature = maybeSignature.releaseNonNull(); >+ >+ for (unsigned i = 0; i < argumentCount; ++i) { >+ Type argumentType; >+ WASM_PARSER_FAIL_IF(!parseValueType(argumentType), "can't get ", i, "th argument Type"); >+ signature->argument(i) = argumentType; >+ } >+ >+ uint8_t returnCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt1(returnCount), "can't get ", i, "th Type's return count"); >+ Type returnType; >+ if (returnCount) { >+ Type value; >+ WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value"); >+ returnType = static_cast<Type>(value); >+ } else >+ returnType = Type::Void; >+ signature->returnType() = returnType; >+ >+ std::pair<SignatureIndex, Ref<Signature>> result = SignatureInformation::adopt(WTFMove(signature)); >+ m_info->usedSignatures.uncheckedAppend(WTFMove(result.second)); >+ } >+ return { }; >+} >+ >+auto SectionParser::parseImport() -> PartialResult >+{ >+ uint32_t importCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(importCount), "can't get Import section's count"); >+ WASM_PARSER_FAIL_IF(importCount > maxImports, "Import section's count is too big ", importCount, " maximum ", maxImports); >+ WASM_PARSER_FAIL_IF(!m_info->globals.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " globals"); // FIXME this over-allocates when we fix the FIXMEs below. >+ WASM_PARSER_FAIL_IF(!m_info->imports.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " imports"); // FIXME this over-allocates when we fix the FIXMEs below. >+ WASM_PARSER_FAIL_IF(!m_info->importFunctionSignatureIndices.tryReserveCapacity(importCount), "can't allocate enough memory for ", importCount, " import function signatures"); // FIXME this over-allocates when we fix the FIXMEs below. >+ >+ for (uint32_t importNumber = 0; importNumber < importCount; ++importNumber) { >+ uint32_t moduleLen; >+ uint32_t fieldLen; >+ Name moduleString; >+ Name fieldString; >+ ExternalKind kind; >+ unsigned kindIndex { 0 }; >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(moduleLen), "can't get ", importNumber, "th Import's module name length"); >+ WASM_PARSER_FAIL_IF(!consumeUTF8String(moduleString, moduleLen), "can't get ", importNumber, "th Import's module name of length ", moduleLen); >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", importNumber, "th Import's field name length in module '", moduleString, "'"); >+ WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", importNumber, "th Import's field name of length ", moduleLen, " in module '", moduleString, "'"); >+ >+ WASM_PARSER_FAIL_IF(!parseExternalKind(kind), "can't get ", importNumber, "th Import's kind in module '", moduleString, "' field '", fieldString, "'"); >+ switch (kind) { >+ case ExternalKind::Function: { >+ uint32_t functionSignatureIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSignatureIndex), "can't get ", importNumber, "th Import's function signature in module '", moduleString, "' field '", fieldString, "'"); >+ WASM_PARSER_FAIL_IF(functionSignatureIndex >= m_info->usedSignatures.size(), "invalid function signature for ", importNumber, "th Import, ", functionSignatureIndex, " is out of range of ", m_info->usedSignatures.size(), " in module '", moduleString, "' field '", fieldString, "'"); >+ kindIndex = m_info->importFunctionSignatureIndices.size(); >+ SignatureIndex signatureIndex = SignatureInformation::get(m_info->usedSignatures[functionSignatureIndex]); >+ m_info->importFunctionSignatureIndices.uncheckedAppend(signatureIndex); >+ break; >+ } >+ case ExternalKind::Table: { >+ bool isImport = true; >+ PartialResult result = parseTableHelper(isImport); >+ if (UNLIKELY(!result)) >+ return makeUnexpected(WTFMove(result.error())); >+ break; >+ } >+ case ExternalKind::Memory: { >+ bool isImport = true; >+ PartialResult result = parseMemoryHelper(isImport); >+ if (UNLIKELY(!result)) >+ return makeUnexpected(WTFMove(result.error())); >+ break; >+ } >+ case ExternalKind::Global: { >+ Global global; >+ WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); >+ WASM_PARSER_FAIL_IF(global.mutability == Global::Mutable, "Mutable Globals aren't supported"); >+ >+ kindIndex = m_info->globals.size(); >+ m_info->globals.uncheckedAppend(WTFMove(global)); >+ break; >+ } >+ } >+ >+ m_info->imports.uncheckedAppend({ WTFMove(moduleString), WTFMove(fieldString), kind, kindIndex }); >+ } >+ >+ m_info->firstInternalGlobal = m_info->globals.size(); >+ return { }; >+} >+ >+auto SectionParser::parseFunction() -> PartialResult >+{ >+ uint32_t count; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Function section's count"); >+ WASM_PARSER_FAIL_IF(count > maxFunctions, "Function section's count is too big ", count, " maximum ", maxFunctions); >+ WASM_PARSER_FAIL_IF(!m_info->internalFunctionSignatureIndices.tryReserveCapacity(count), "can't allocate enough memory for ", count, " Function signatures"); >+ WASM_PARSER_FAIL_IF(!m_info->functionLocationInBinary.tryReserveCapacity(count), "can't allocate enough memory for ", count, "Function locations"); >+ >+ for (uint32_t i = 0; i < count; ++i) { >+ uint32_t typeNumber; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(typeNumber), "can't get ", i, "th Function's type number"); >+ WASM_PARSER_FAIL_IF(typeNumber >= m_info->usedSignatures.size(), i, "th Function type number is invalid ", typeNumber); >+ >+ SignatureIndex signatureIndex = SignatureInformation::get(m_info->usedSignatures[typeNumber]); >+ // The Code section fixes up start and end. >+ size_t start = 0; >+ size_t end = 0; >+ m_info->internalFunctionSignatureIndices.uncheckedAppend(signatureIndex); >+ m_info->functionLocationInBinary.uncheckedAppend({ start, end }); >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum) -> PartialResult >+{ >+ ASSERT(!maximum); >+ >+ uint8_t flags; >+ WASM_PARSER_FAIL_IF(!parseVarUInt1(flags), "can't parse resizable limits flags"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(initial), "can't parse resizable limits initial page count"); >+ >+ if (flags) { >+ uint32_t maximumInt; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(maximumInt), "can't parse resizable limits maximum page count"); >+ WASM_PARSER_FAIL_IF(initial > maximumInt, "resizable limits has a initial page count of ", initial, " which is greater than its maximum ", maximumInt); >+ maximum = maximumInt; >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseTableHelper(bool isImport) -> PartialResult >+{ >+ WASM_PARSER_FAIL_IF(m_info->tableCount() > 0, "Cannot have more than one Table for now"); >+ >+ int8_t type; >+ WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type"); >+ WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type); >+ >+ uint32_t initial; >+ std::optional<uint32_t> maximum; >+ PartialResult limits = parseResizableLimits(initial, maximum); >+ if (UNLIKELY(!limits)) >+ return makeUnexpected(WTFMove(limits.error())); >+ WASM_PARSER_FAIL_IF(initial > maxTableEntries, "Table's initial page count of ", initial, " is too big, maximum ", maxTableEntries); >+ >+ ASSERT(!maximum || *maximum >= initial); >+ >+ m_info->tableInformation = TableInformation(initial, maximum, isImport); >+ >+ return { }; >+} >+ >+auto SectionParser::parseTable() -> PartialResult >+{ >+ uint32_t count; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count"); >+ WASM_PARSER_FAIL_IF(count > 1, "Table count of ", count, " is invalid, at most 1 is allowed for now"); >+ >+ if (!count) >+ return { }; >+ >+ bool isImport = false; >+ PartialResult result = parseTableHelper(isImport); >+ if (UNLIKELY(!result)) >+ return makeUnexpected(WTFMove(result.error())); >+ >+ return { }; >+} >+ >+auto SectionParser::parseMemoryHelper(bool isImport) -> PartialResult >+{ >+ WASM_PARSER_FAIL_IF(m_info->memoryCount(), "there can at most be one Memory section for now"); >+ >+ PageCount initialPageCount; >+ PageCount maximumPageCount; >+ { >+ uint32_t initial; >+ std::optional<uint32_t> maximum; >+ PartialResult limits = parseResizableLimits(initial, maximum); >+ if (UNLIKELY(!limits)) >+ return makeUnexpected(WTFMove(limits.error())); >+ ASSERT(!maximum || *maximum >= initial); >+ WASM_PARSER_FAIL_IF(!PageCount::isValid(initial), "Memory's initial page count of ", initial, " is invalid"); >+ >+ initialPageCount = PageCount(initial); >+ >+ if (maximum) { >+ WASM_PARSER_FAIL_IF(!PageCount::isValid(*maximum), "Memory's maximum page count of ", *maximum, " is invalid"); >+ maximumPageCount = PageCount(*maximum); >+ } >+ } >+ ASSERT(initialPageCount); >+ ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount); >+ >+ m_info->memory = MemoryInformation(initialPageCount, maximumPageCount, isImport); >+ return { }; >+} >+ >+auto SectionParser::parseMemory() -> PartialResult >+{ >+ uint8_t count; >+ WASM_PARSER_FAIL_IF(!parseVarUInt1(count), "can't parse Memory section's count"); >+ >+ if (!count) >+ return { }; >+ >+ WASM_PARSER_FAIL_IF(count != 1, "Memory section has more than one memory, WebAssembly currently only allows zero or one"); >+ >+ bool isImport = false; >+ return parseMemoryHelper(isImport); >+} >+ >+auto SectionParser::parseGlobal() -> PartialResult >+{ >+ uint32_t globalCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(globalCount), "can't get Global section's count"); >+ WASM_PARSER_FAIL_IF(globalCount > maxGlobals, "Global section's count is too big ", globalCount, " maximum ", maxGlobals); >+ size_t totalBytes = globalCount + m_info->firstInternalGlobal; >+ WASM_PARSER_FAIL_IF((static_cast<uint32_t>(totalBytes) < globalCount) || !m_info->globals.tryReserveCapacity(totalBytes), "can't allocate memory for ", totalBytes, " globals"); >+ >+ for (uint32_t globalIndex = 0; globalIndex < globalCount; ++globalIndex) { >+ Global global; >+ uint8_t initOpcode; >+ >+ WASM_FAIL_IF_HELPER_FAILS(parseGlobalType(global)); >+ Type typeForInitOpcode; >+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber, typeForInitOpcode)); >+ if (initOpcode == GetGlobal) >+ global.initializationType = Global::FromGlobalImport; >+ else >+ global.initializationType = Global::FromExpression; >+ WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type); >+ >+ m_info->globals.uncheckedAppend(WTFMove(global)); >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseExport() -> PartialResult >+{ >+ uint32_t exportCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(exportCount), "can't get Export section's count"); >+ WASM_PARSER_FAIL_IF(exportCount > maxExports, "Export section's count is too big ", exportCount, " maximum ", maxExports); >+ WASM_PARSER_FAIL_IF(!m_info->exports.tryReserveCapacity(exportCount), "can't allocate enough memory for ", exportCount, " exports"); >+ >+ HashSet<String> exportNames; >+ for (uint32_t exportNumber = 0; exportNumber < exportCount; ++exportNumber) { >+ uint32_t fieldLen; >+ Name fieldString; >+ ExternalKind kind; >+ unsigned kindIndex; >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(fieldLen), "can't get ", exportNumber, "th Export's field name length"); >+ WASM_PARSER_FAIL_IF(!consumeUTF8String(fieldString, fieldLen), "can't get ", exportNumber, "th Export's field name of length ", fieldLen); >+ String fieldName = String::fromUTF8(fieldString); >+ WASM_PARSER_FAIL_IF(exportNames.contains(fieldName), "duplicate export: '", fieldString, "'"); >+ exportNames.add(fieldName); >+ >+ WASM_PARSER_FAIL_IF(!parseExternalKind(kind), "can't get ", exportNumber, "th Export's kind, named '", fieldString, "'"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(kindIndex), "can't get ", exportNumber, "th Export's kind index, named '", fieldString, "'"); >+ switch (kind) { >+ case ExternalKind::Function: { >+ WASM_PARSER_FAIL_IF(kindIndex >= m_info->functionIndexSpaceSize(), exportNumber, "th Export has invalid function number ", kindIndex, " it exceeds the function index space ", m_info->functionIndexSpaceSize(), ", named '", fieldString, "'"); >+ break; >+ } >+ case ExternalKind::Table: { >+ WASM_PARSER_FAIL_IF(kindIndex >= m_info->tableCount(), "can't export Table ", kindIndex, " there are ", m_info->tableCount(), " Tables"); >+ break; >+ } >+ case ExternalKind::Memory: { >+ WASM_PARSER_FAIL_IF(!m_info->memory, "can't export a non-existent Memory"); >+ WASM_PARSER_FAIL_IF(kindIndex, "can't export Memory ", kindIndex, " only one Table is currently supported"); >+ break; >+ } >+ case ExternalKind::Global: { >+ WASM_PARSER_FAIL_IF(kindIndex >= m_info->globals.size(), exportNumber, "th Export has invalid global number ", kindIndex, " it exceeds the globals count ", m_info->globals.size(), ", named '", fieldString, "'"); >+ WASM_PARSER_FAIL_IF(m_info->globals[kindIndex].mutability != Global::Immutable, exportNumber, "th Export isn't immutable, named '", fieldString, "'"); >+ break; >+ } >+ } >+ >+ m_info->exports.uncheckedAppend({ WTFMove(fieldString), kind, kindIndex }); >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseStart() -> PartialResult >+{ >+ uint32_t startFunctionIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(startFunctionIndex), "can't get Start index"); >+ WASM_PARSER_FAIL_IF(startFunctionIndex >= m_info->functionIndexSpaceSize(), "Start index ", startFunctionIndex, " exceeds function index space ", m_info->functionIndexSpaceSize()); >+ SignatureIndex signatureIndex = m_info->signatureIndexFromFunctionIndexSpace(startFunctionIndex); >+ const Signature& signature = SignatureInformation::get(signatureIndex); >+ WASM_PARSER_FAIL_IF(signature.argumentCount(), "Start function can't have arguments"); >+ WASM_PARSER_FAIL_IF(signature.returnType() != Void, "Start function can't return a value"); >+ m_info->startFunctionIndexSpace = startFunctionIndex; >+ return { }; >+} >+ >+auto SectionParser::parseElement() -> PartialResult >+{ >+ uint32_t elementCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(elementCount), "can't get Element section's count"); >+ WASM_PARSER_FAIL_IF(elementCount > maxTableEntries, "Element section's count is too big ", elementCount, " maximum ", maxTableEntries); >+ WASM_PARSER_FAIL_IF(!m_info->elements.tryReserveCapacity(elementCount), "can't allocate memory for ", elementCount, " Elements"); >+ for (unsigned elementNum = 0; elementNum < elementCount; ++elementNum) { >+ uint32_t tableIndex; >+ uint64_t initExprBits; >+ uint8_t initOpcode; >+ uint32_t indexCount; >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index"); >+ WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount()); >+ Type initExprType; >+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType)); >+ WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section"); >+ WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount); >+ >+ ASSERT(!!m_info->tableInformation); >+ >+ Element element(makeI32InitExpr(initOpcode, initExprBits)); >+ WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices"); >+ >+ for (unsigned index = 0; index < indexCount; ++index) { >+ uint32_t functionIndex; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionIndex), "can't get Element section's ", elementNum, "th element's ", index, "th index"); >+ WASM_PARSER_FAIL_IF(functionIndex >= m_info->functionIndexSpaceSize(), "Element section's ", elementNum, "th element's ", index, "th index is ", functionIndex, " which exceeds the function index space size of ", m_info->functionIndexSpaceSize()); >+ >+ element.functionIndices.uncheckedAppend(functionIndex); >+ } >+ >+ m_info->elements.uncheckedAppend(WTFMove(element)); >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseCode() -> PartialResult >+{ >+ uint32_t count; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Code section's count"); >+ WASM_PARSER_FAIL_IF(count == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", count); >+ WASM_PARSER_FAIL_IF(count != m_info->functionLocationInBinary.size(), "Code section count ", count, " exceeds the declared number of functions ", m_info->functionLocationInBinary.size()); >+ >+ for (uint32_t i = 0; i < count; ++i) { >+ uint32_t functionSize; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(functionSize), "can't get ", i, "th Code function's size"); >+ WASM_PARSER_FAIL_IF(functionSize > length(), "Code function's size ", functionSize, " exceeds the module's size ", length()); >+ WASM_PARSER_FAIL_IF(functionSize > length() - m_offset, "Code function's size ", functionSize, " exceeds the module's remaining size", length() - m_offset); >+ WASM_PARSER_FAIL_IF(functionSize > maxFunctionSize, "Code function's size ", functionSize, " is too big"); >+ >+ m_info->functionLocationInBinary[i].start = m_offsetInSource + m_offset; >+ m_info->functionLocationInBinary[i].end = m_offsetInSource + m_offset + functionSize; >+ m_offset += functionSize; >+ } >+ >+ return { }; >+} >+ >+auto SectionParser::parseInitExpr(uint8_t& opcode, uint64_t& bitsOrImportNumber, Type& resultType) -> PartialResult >+{ >+ WASM_PARSER_FAIL_IF(!parseUInt8(opcode), "can't get init_expr's opcode"); >+ >+ switch (opcode) { >+ case I32Const: { >+ int32_t constant; >+ WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't get constant value for init_expr's i32.const"); >+ bitsOrImportNumber = static_cast<uint64_t>(constant); >+ resultType = I32; >+ break; >+ } >+ >+ case I64Const: { >+ int64_t constant; >+ WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't get constant value for init_expr's i64.const"); >+ bitsOrImportNumber = constant; >+ resultType = I64; >+ break; >+ } >+ >+ case F32Const: { >+ uint32_t constant; >+ WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't get constant value for init_expr's f32.const"); >+ bitsOrImportNumber = constant; >+ resultType = F32; >+ break; >+ } >+ >+ case F64Const: { >+ uint64_t constant; >+ WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't get constant value for init_expr's f64.const"); >+ bitsOrImportNumber = constant; >+ resultType = F64; >+ break; >+ } >+ >+ case GetGlobal: { >+ uint32_t index; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index"); >+ >+ WASM_PARSER_FAIL_IF(index >= m_info->globals.size(), "get_global's index ", index, " exceeds the number of globals ", m_info->globals.size()); >+ WASM_PARSER_FAIL_IF(index >= m_info->firstInternalGlobal, "get_global import kind index ", index, " exceeds the first internal global ", m_info->firstInternalGlobal); >+ >+ ASSERT(m_info->globals[index].mutability == Global::Immutable); >+ resultType = m_info->globals[index].type; >+ bitsOrImportNumber = index; >+ break; >+ } >+ >+ default: >+ WASM_PARSER_FAIL_IF(true, "unknown init_expr opcode ", opcode); >+ } >+ >+ uint8_t endOpcode; >+ WASM_PARSER_FAIL_IF(!parseUInt8(endOpcode), "can't get init_expr's end opcode"); >+ WASM_PARSER_FAIL_IF(endOpcode != OpType::End, "init_expr should end with end, ended with ", endOpcode); >+ >+ return { }; >+} >+ >+auto SectionParser::parseGlobalType(Global& global) -> PartialResult >+{ >+ uint8_t mutability; >+ WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt1(mutability), "can't get Global type's mutability"); >+ global.mutability = static_cast<Global::Mutability>(mutability); >+ return { }; >+} >+ >+auto SectionParser::parseData() -> PartialResult >+{ >+ uint32_t segmentCount; >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(segmentCount), "can't get Data section's count"); >+ WASM_PARSER_FAIL_IF(segmentCount > maxDataSegments, "Data section's count is too big ", segmentCount, " maximum ", maxDataSegments); >+ WASM_PARSER_FAIL_IF(!m_info->data.tryReserveCapacity(segmentCount), "can't allocate enough memory for Data section's ", segmentCount, " segments"); >+ >+ for (uint32_t segmentNumber = 0; segmentNumber < segmentCount; ++segmentNumber) { >+ uint32_t memoryIndex; >+ uint64_t initExprBits; >+ uint8_t initOpcode; >+ uint32_t dataByteLength; >+ >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(memoryIndex), "can't get ", segmentNumber, "th Data segment's index"); >+ WASM_PARSER_FAIL_IF(memoryIndex >= m_info->memoryCount(), segmentNumber, "th Data segment has index ", memoryIndex, " which exceeds the number of Memories ", m_info->memoryCount()); >+ Type initExprType; >+ WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType)); >+ WASM_PARSER_FAIL_IF(initExprType != I32, segmentNumber, "th Data segment's init_expr must produce an i32"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(dataByteLength), "can't get ", segmentNumber, "th Data segment's data byte length"); >+ WASM_PARSER_FAIL_IF(dataByteLength > maxModuleSize, segmentNumber, "th Data segment's data byte length is too big ", dataByteLength, " maximum ", maxModuleSize); >+ >+ Segment* segment = Segment::create(makeI32InitExpr(initOpcode, initExprBits), dataByteLength); >+ WASM_PARSER_FAIL_IF(!segment, "can't allocate enough memory for ", segmentNumber, "th Data segment of size ", dataByteLength); >+ m_info->data.uncheckedAppend(Segment::adoptPtr(segment)); >+ for (uint32_t dataByte = 0; dataByte < dataByteLength; ++dataByte) { >+ uint8_t byte; >+ WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", dataByte, "th data byte from ", segmentNumber, "th Data segment"); >+ segment->byte(dataByte) = byte; >+ } >+ } >+ return { }; >+} >+ >+auto SectionParser::parseCustom() -> PartialResult >+{ >+ CustomSection section; >+ uint32_t customSectionNumber = m_info->customSections.size() + 1; >+ uint32_t nameLen; >+ WASM_PARSER_FAIL_IF(!m_info->customSections.tryReserveCapacity(customSectionNumber), "can't allocate enough memory for ", customSectionNumber, "th custom section"); >+ WASM_PARSER_FAIL_IF(!parseVarUInt32(nameLen), "can't get ", customSectionNumber, "th custom section's name length"); >+ WASM_PARSER_FAIL_IF(!consumeUTF8String(section.name, nameLen), "nameLen get ", customSectionNumber, "th custom section's name of length ", nameLen); >+ >+ uint32_t payloadBytes = length() - m_offset; >+ WASM_PARSER_FAIL_IF(!section.payload.tryReserveCapacity(payloadBytes), "can't allocate enough memory for ", customSectionNumber, "th custom section's ", payloadBytes, " bytes"); >+ for (uint32_t byteNumber = 0; byteNumber < payloadBytes; ++byteNumber) { >+ uint8_t byte; >+ WASM_PARSER_FAIL_IF(!parseUInt8(byte), "can't get ", byteNumber, "th data byte from ", customSectionNumber, "th custom section"); >+ section.payload.uncheckedAppend(byte); >+ } >+ >+ Name nameName = { 'n', 'a', 'm', 'e' }; >+ if (section.name == nameName) { >+ NameSectionParser nameSectionParser(section.payload.begin(), section.payload.size(), m_info); >+ if (auto nameSection = nameSectionParser.parse()) >+ m_info->nameSection = WTFMove(*nameSection); >+ } >+ >+ m_info->customSections.uncheckedAppend(WTFMove(section)); >+ >+ return { }; >+} >+ >+} } // namespace JSC::Wasm >+ >+#endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.h b/Source/JavaScriptCore/wasm/WasmSectionParser.h >new file mode 100644 >index 0000000000000000000000000000000000000000..78d02836fc9f32bc2b78fbf90ad2c5da9f91283d >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.h >@@ -0,0 +1,74 @@ >+/* >+ * Copyright (C) 2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBASSEMBLY) >+ >+#include "WasmFormat.h" >+#include "WasmOps.h" >+#include "WasmParser.h" >+#include <wtf/Optional.h> >+#include <wtf/Vector.h> >+ >+namespace JSC { namespace Wasm { >+ >+class SectionParser final : public Parser<void> { >+public: >+ SectionParser(const uint8_t* data, size_t size, size_t offsetInSource, ModuleInformation& info) >+ : Parser(data, size) >+ , m_offsetInSource(offsetInSource) >+ , m_info(info) >+ { >+ } >+ >+#define WASM_SECTION_DECLARE_PARSER(NAME, ID, DESCRIPTION) PartialResult WARN_UNUSED_RETURN parse ## NAME(); >+ FOR_EACH_KNOWN_WASM_SECTION(WASM_SECTION_DECLARE_PARSER) >+#undef WASM_SECTION_DECLARE_PARSER >+ >+ PartialResult WARN_UNUSED_RETURN parseCustom(); >+ >+private: >+ template <typename ...Args> >+ NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const >+ { >+ using namespace FailureHelper; // See ADL comment in namespace above. >+ return UnexpectedResult(makeString("WebAssembly.Module doesn't parse at byte "_s, String::number(m_offset + m_offsetInSource), ": "_s, makeString(args)...)); >+ } >+ >+ PartialResult WARN_UNUSED_RETURN parseGlobalType(Global&); >+ PartialResult WARN_UNUSED_RETURN parseMemoryHelper(bool isImport); >+ PartialResult WARN_UNUSED_RETURN parseTableHelper(bool isImport); >+ PartialResult WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum); >+ PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType); >+ >+ size_t m_offsetInSource; >+ Ref<ModuleInformation> m_info; >+}; >+ >+} } // namespace JSC::Wasm >+ >+#endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmStreamingParser.cpp b/Source/JavaScriptCore/wasm/WasmStreamingParser.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..28e8b4187272cabed5f840521f7c3f2a2921729c >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmStreamingParser.cpp >@@ -0,0 +1,331 @@ >+/* >+ * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "WasmStreamingParser.h" >+ >+#if ENABLE(WEBASSEMBLY) >+ >+#include "WasmModuleParser.h" >+#include "WasmSectionParser.h" >+#include <wtf/UnalignedAccess.h> >+ >+namespace JSC { namespace Wasm { >+ >+namespace WasmStreamingParserInternal { >+static constexpr bool verbose = true; >+} >+ >+#define WASM_STREAMING_PARSER_FAIL_IF(condition, ...) \ >+ do { \ >+ if (UNLIKELY(condition)) { \ >+ dataLogLnIf(WasmStreamingParserInternal::verbose, __VA_ARGS__); \ >+ return State::FatalError; \ >+ } \ >+ } while (0) >+ >+#define WASM_STREAMING_PARSER_FAIL_IF_HELPER_FAILS(helper) \ >+ do { \ >+ auto helperResult = helper; \ >+ if (UNLIKELY(!helperResult)) \ >+ return State::FatalError; \ >+ } while (0) >+ >+ALWAYS_INLINE std::optional<uint8_t> parseUInt7(const uint8_t* data, size_t& offset, size_t size) >+{ >+ if (offset >= size) >+ return false; >+ uint8_t result = data[offset++]; >+ if (result < 0x80) >+ return result; >+ return std::nullopt; >+} >+ >+StreamingParser::StreamingParser(ModuleInformation& info) >+ : m_info(info) >+{ >+ dataLogLnIf(WasmStreamingParserInternal::verbose, "starting validation"); >+} >+ >+auto StreamingParser::parseModuleHeader(Vector<uint8_t>&& data) -> State >+{ >+ ASSERT(data.size() == moduleHeaderSize); >+ dataLogLnIf(WasmStreamingParserInternal::verbose, "header validation"); >+ WASM_STREAMING_PARSER_FAIL_IF(data[0] != '\0' || data[1] != 'a' || data[2] != 's' || data[3] != 'm', "modules doesn't start with '\\0asm'"); >+ uint32_t versionNumber = WTF::unalignedLoad<uint32_t>(data.data() + 4); >+ WASM_STREAMING_PARSER_FAIL_IF(versionNumber != expectedVersionNumber, "unexpected version number ", versionNumber, " expected ", expectedVersionNumber); >+ m_versionNumber = versionNumber; >+ return State::SectionHeader; >+} >+ >+auto StreamingParser::parseSectionHeader(Vector<uint8_t>&& data) -> State >+{ >+ ASSERT(data.size() == sectionHeaderSize); >+ size_t offset = 0; >+ auto result = parseUInt7(data.data(), offset, data.size()); >+ WASM_STREAMING_PARSER_FAIL_IF(!result, "can't get section byte"); >+ >+ Section section = Section::Custom; >+ WASM_STREAMING_PARSER_FAIL_IF(!decodeSection(*result, section), "invalid section"); >+ ASSERT(section != Section::Begin); >+ WASM_STREAMING_PARSER_FAIL_IF(!validateOrder(m_previousKnownSection, section), "invalid section order, ", makeString(m_previousKnownSection), " followed by ", makeString(section)); >+ m_section = section; >+ if (isKnownSection(section)) >+ m_previousKnownSection = section; >+ return State::SectionSize; >+} >+ >+auto StreamingParser::parseSectionSize(uint32_t sectionLength) -> State >+{ >+ m_sectionLength = sectionLength; >+ if (m_section == Section::Code) >+ return State::CodeSectionSize; >+ return State::SectionBody; >+} >+ >+auto StreamingParser::parseCodeSectionSize(uint32_t functionCount) -> State >+{ >+ m_functionCount = functionCount; >+ m_functionIndex = 0; >+ m_codeOffset = m_offset; >+ >+ WASM_STREAMING_PARSER_FAIL_IF(functionCount == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", functionCount); >+ WASM_STREAMING_PARSER_FAIL_IF(functionCount != m_info->functionLocationInBinary.size(), "Code section count ", functionCount, " exceeds the declared number of functions ", m_info->functionLocationInBinary.size()); >+ >+ if (m_functionIndex == m_functionCount) { >+ if ((m_codeOffset + m_sectionLength) == m_offset) >+ return State::SectionHeader; >+ return State::FatalError; >+ } >+ return State::FunctionHeader; >+} >+ >+auto StreamingParser::parseFunctionHeader(uint32_t functionSize) -> State >+{ >+ m_functionSize = functionSize; >+ WASM_STREAMING_PARSER_FAIL_IF(functionSize > maxFunctionSize, "Code function's size ", functionSize, " is too big"); >+ return State::FunctionBody; >+} >+ >+auto StreamingParser::parseFunctionBody(Vector<uint8_t>&& data) -> State >+{ >+ m_info->functionLocationInBinary[m_functionIndex].start = m_offset; >+ m_info->functionLocationInBinary[m_functionIndex].end = m_offset + m_functionSize; >+ dataLogLnIf(WasmStreamingParserInternal::verbose, "Processing function starting at: ", m_info->functionLocationInBinary[m_functionIndex].start, " and ending at: ", m_info->functionLocationInBinary[m_functionIndex].end); >+ ++m_functionIndex; >+ if (m_functionIndex == m_functionCount) { >+ if ((m_codeOffset + m_sectionLength) == m_offset + m_functionSize) >+ return State::SectionHeader; >+ return State::FatalError; >+ } >+ return State::FunctionHeader; >+} >+ >+auto StreamingParser::parseSectionBody(Vector<uint8_t>&& data) -> State >+{ >+ SectionParser parser(data.data(), data.size(), m_offset, m_info.get()); >+ switch (m_section) { >+#define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \ >+ case Section::NAME: { \ >+ WASM_STREAMING_PARSER_FAIL_IF_HELPER_FAILS(parser.parse ## NAME()); \ >+ break; \ >+ } >+ FOR_EACH_KNOWN_WASM_SECTION(WASM_SECTION_PARSE) >+#undef WASM_SECTION_PARSE >+ >+ case Section::Custom: { >+ WASM_STREAMING_PARSER_FAIL_IF_HELPER_FAILS(parser.parseCustom()); >+ break; >+ } >+ >+ case Section::Begin: { >+ RELEASE_ASSERT_NOT_REACHED(); >+ break; >+ } >+ } >+ >+ WASM_STREAMING_PARSER_FAIL_IF(parser.length() != parser.offset(), "parsing ended before the end of ", makeString(m_section), " section"); >+ >+ return State::SectionHeader; >+} >+ >+auto StreamingParser::consume(const uint8_t* bytes, size_t bytesSize, size_t& offsetInBytes, size_t requiredSize) -> Expected<Vector<uint8_t>, State> >+{ >+ if (m_remaining.size() == requiredSize) { >+ Vector<uint8_t> result = WTFMove(m_remaining); >+ m_nextOffset += requiredSize; >+ return WTFMove(result); >+ } >+ >+ if (m_remaining.size() >= requiredSize) { >+ Vector<uint8_t> result(requiredSize); >+ memcpy(result.data(), m_remaining.data(), requiredSize); >+ m_remaining.remove(0, requiredSize); >+ m_nextOffset += requiredSize; >+ return WTFMove(result); >+ } >+ >+ ASSERT(m_remaining.size() < requiredSize); >+ size_t bytesRemainingSize = bytesSize - offsetInBytes; >+ size_t totalDataSize = m_remaining.size() + bytesRemainingSize; >+ if (totalDataSize < requiredSize) { >+ m_remaining.append(bytes + offsetInBytes, bytesRemainingSize); >+ offsetInBytes = bytesSize; >+ return makeUnexpected(m_state); >+ } >+ >+ size_t usedSize = requiredSize - m_remaining.size(); >+ m_remaining.append(bytes + offsetInBytes, usedSize); >+ offsetInBytes += usedSize; >+ Vector<uint8_t> result = WTFMove(m_remaining); >+ m_nextOffset += requiredSize; >+ return WTFMove(result); >+} >+ >+auto StreamingParser::consumeVarUInt32(const uint8_t* bytes, size_t bytesSize, size_t& offsetInBytes, IsEndOfStream isEndOfStream) -> Expected<uint32_t, State> >+{ >+ constexpr size_t maxSize = 5; >+ size_t bytesRemainingSize = bytesSize - offsetInBytes; >+ size_t totalDataSize = m_remaining.size() + bytesRemainingSize; >+ if (m_remaining.size() >= maxSize) { >+ // Do nothing. >+ } else if (totalDataSize >= maxSize) { >+ size_t usedSize = maxSize - m_remaining.size(); >+ m_remaining.append(bytes + offsetInBytes, usedSize); >+ offsetInBytes += usedSize; >+ } else { >+ m_remaining.append(bytes + offsetInBytes, bytesRemainingSize); >+ offsetInBytes += bytesRemainingSize; >+ if (isEndOfStream == IsEndOfStream::No) >+ return makeUnexpected(m_state); >+ } >+ >+ size_t offset = 0; >+ uint32_t result = 0; >+ if (!WTF::LEBDecoder::decodeUInt32(m_remaining.data(), m_remaining.size(), offset, result)) >+ return makeUnexpected(State::FatalError); >+ size_t consumedSize = offset; >+ m_remaining.remove(0, consumedSize); >+ m_nextOffset += consumedSize; >+ return result; >+} >+ >+auto StreamingParser::addBytes(const uint8_t* bytes, size_t bytesSize, IsEndOfStream isEndOfStream) -> State >+{ >+ size_t offsetInBytes = 0; >+ while (true) { >+ switch (m_state) { >+ case State::ModuleHeader: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, moduleHeaderSize); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseModuleHeader(WTFMove(*result)); >+ break; >+ } >+ >+ case State::SectionHeader: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, sectionHeaderSize); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseSectionHeader(WTFMove(*result)); >+ break; >+ } >+ >+ case State::SectionSize: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseSectionSize(*result); >+ break; >+ } >+ >+ case State::SectionBody: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, m_sectionLength); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseSectionBody(WTFMove(*result)); >+ break; >+ } >+ >+ case State::CodeSectionSize: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseCodeSectionSize(*result); >+ break; >+ } >+ >+ case State::FunctionHeader: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseFunctionHeader(*result); >+ break; >+ } >+ >+ case State::FunctionBody: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, m_functionSize); >+ if (!result) { >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseFunctionBody(WTFMove(*result)); >+ break; >+ } >+ >+ case State::Finished: >+ case State::FatalError: >+ return m_state; >+ } >+ >+ m_offset = m_nextOffset; >+ } >+} >+ >+auto StreamingParser::finalize() -> State >+{ >+ addBytes(nullptr, 0, IsEndOfStream::Yes); >+ if (m_remaining.size() == 0 && m_state == State::SectionHeader) >+ m_state = State::Finished; >+ else >+ m_state = State::FatalError; >+ return m_state; >+} >+ >+} } // namespace JSC::Wasm >+ >+#endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/WasmStreamingParser.h b/Source/JavaScriptCore/wasm/WasmStreamingParser.h >new file mode 100644 >index 0000000000000000000000000000000000000000..c4299d47353e7a06b32df0f417626a1f2f70ac14 >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmStreamingParser.h >@@ -0,0 +1,107 @@ >+/* >+ * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBASSEMBLY) >+ >+#include "WasmModuleInformation.h" >+#include "WasmSections.h" >+#include <wtf/Expected.h> >+#include <wtf/Optional.h> >+#include <wtf/Vector.h> >+#include <wtf/text/WTFString.h> >+ >+namespace JSC { namespace Wasm { >+ >+class StreamingParserClient { >+}; >+ >+class StreamingParser { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ enum class State : uint8_t { >+ ModuleHeader, >+ SectionHeader, >+ SectionSize, >+ SectionBody, >+ CodeSectionSize, >+ FunctionHeader, >+ FunctionBody, >+ Finished, >+ FatalError, >+ }; >+ >+ enum class IsEndOfStream { Yes, No }; >+ >+ StreamingParser(ModuleInformation&); >+ >+ State addBytes(const uint8_t* bytes, size_t length) { return addBytes(bytes, length, IsEndOfStream::No); } >+ State finalize(); >+ >+private: >+ static constexpr unsigned moduleHeaderSize = 8; >+ static constexpr unsigned sectionHeaderSize = 1; >+ >+ State addBytes(const uint8_t* bytes, size_t length, IsEndOfStream); >+ >+ State parseModuleHeader(Vector<uint8_t>&&); >+ State parseSectionHeader(Vector<uint8_t>&&); >+ State parseSectionSize(uint32_t); >+ State parseSectionBody(Vector<uint8_t>&&); >+ >+ State parseCodeSectionSize(uint32_t); >+ State parseFunctionHeader(uint32_t); >+ State parseFunctionBody(Vector<uint8_t>&&); >+ >+ >+ Expected<Vector<uint8_t>, State> consume(const uint8_t* bytes, size_t, size_t&, size_t); >+ Expected<uint32_t, State> consumeVarUInt32(const uint8_t* bytes, size_t, size_t&, IsEndOfStream); >+ >+ Ref<ModuleInformation> m_info; >+ Vector<uint8_t> m_remaining; >+ String m_errorMessage; >+ >+ size_t m_offset { 0 }; >+ size_t m_nextOffset { 0 }; >+ size_t m_codeOffset { 0 }; >+ >+ uint32_t m_versionNumber { 0 }; >+ uint32_t m_sectionLength { 0 }; >+ >+ uint32_t m_functionCount { 0 }; >+ uint32_t m_functionIndex { 0 }; >+ >+ uint32_t m_functionSize { 0 }; >+ >+ State m_state { State::ModuleHeader }; >+ Section m_section { Section::Begin }; >+ Section m_previousKnownSection { Section::Begin }; >+}; >+ >+ >+} } // namespace JSC::Wasm >+ >+#endif // ENABLE(WEBASSEMBLY) >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index a19ab57c19fee5594555833960f6a260f8a31754..4178d989a4b7fbece1fb39a2e26298ac48cabcdf 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,35 @@ >+2018-08-26 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ [WebAssembly] Parse wasm modules in a streaming fashion >+ https://bugs.webkit.org/show_bug.cgi?id=188943 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * wasm/function-tests/invalid-duplicate-export.js: >+ * wasm/function-tests/memory-alignment.js: >+ (const.op.of.WASM.opcodes): >+ * wasm/function-tests/memory-section-and-import.js: >+ * wasm/function-tests/void-argument-type-should-be-a-validation-error.js: >+ * wasm/js-api/Module-compile.js: >+ (async.testPromiseAPI): >+ * wasm/js-api/element.js: >+ (assert.throws.new.WebAssembly.Module.builder.WebAssembly): >+ (assert.throws): >+ * wasm/js-api/global-error.js: >+ (assert.throws.new.WebAssembly.Module.bin): >+ (assert.throws): >+ * wasm/js-api/table.js: >+ (new.WebAssembly.Module): >+ (assert.throws): >+ (assertBadTableImport): >+ * wasm/js-api/test_Data.js: >+ (DataSectionWithoutMemory): >+ * wasm/js-api/test_Start.js: >+ (InvalidStartFunctionIndex): >+ * wasm/js-api/test_basic_api.js: >+ (const.c.in.constructorProperties.switch): >+ * wasm/js-api/version.js: >+ > 2018-08-22 Saam barati <sbarati@apple.com> > > Make data-view-access.js run less time to prevent timeouts on 32-bit >diff --git a/JSTests/wasm/function-tests/invalid-duplicate-export.js b/JSTests/wasm/function-tests/invalid-duplicate-export.js >index c47b1e1662c2cb60c93d6c9b95739bdaba780e73..418d51aa499019aa2469baa5f1fd8e1abd3bf291 100644 >--- a/JSTests/wasm/function-tests/invalid-duplicate-export.js >+++ b/JSTests/wasm/function-tests/invalid-duplicate-export.js >@@ -15,5 +15,5 @@ > .End(); > > const bin = builder.WebAssembly().get(); >- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 31 / 39: duplicate export: 'foo'"); >+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 31: duplicate export: 'foo'"); > } >diff --git a/JSTests/wasm/function-tests/memory-alignment.js b/JSTests/wasm/function-tests/memory-alignment.js >index abc57412146f2e397261e7326ecc8a5c819a049c..e605898900aa1bed67b9d32ac6f2aa012eb299ee 100644 >--- a/JSTests/wasm/function-tests/memory-alignment.js >+++ b/JSTests/wasm/function-tests/memory-alignment.js >@@ -42,7 +42,7 @@ > if (alignLog2 <= maxAlignLog2) > instance(); > else >- assert.throws(instance, WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte ${start} / ${end}: byte alignment ${1 << alignLog2} exceeds ${info.type}'s natural alignment ${1 << maxAlignLog2}, in function at index 0`); >+ assert.throws(instance, WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte ${start}: byte alignment ${1 << alignLog2} exceeds ${info.type}'s natural alignment ${1 << maxAlignLog2}, in function at index 0`); > > } > } >diff --git a/JSTests/wasm/function-tests/memory-section-and-import.js b/JSTests/wasm/function-tests/memory-section-and-import.js >index a1db9ce25779350b5bd5577f767e667774bd8b0b..15207ef7188efa0f6923573c1dfea5a3ea5b71ff 100644 >--- a/JSTests/wasm/function-tests/memory-section-and-import.js >+++ b/JSTests/wasm/function-tests/memory-section-and-import.js >@@ -28,4 +28,4 @@ > .Code().End(); > > const i0 = instantiate(builder0); >-assert.throws(() => instantiate(builder1, { imp: { memory: i0.exports.memory } }), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 35 / 41: there can at most be one Memory section for now`); >+assert.throws(() => instantiate(builder1, { imp: { memory: i0.exports.memory } }), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 35: there can at most be one Memory section for now`); >diff --git a/JSTests/wasm/function-tests/void-argument-type-should-be-a-validation-error.js b/JSTests/wasm/function-tests/void-argument-type-should-be-a-validation-error.js >index 47149b1d7fb93231c25d078a86298b7502bff68a..2178810a7817d97335e62f78b3fc517e3fe77e41 100644 >--- a/JSTests/wasm/function-tests/void-argument-type-should-be-a-validation-error.js >+++ b/JSTests/wasm/function-tests/void-argument-type-should-be-a-validation-error.js >@@ -17,6 +17,6 @@ function getBinary(params) { > return builder.WebAssembly().get(); > } > >-assert.throws(() => new WebAssembly.Module(getBinary(["i32", "void"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 15 / 47: can't get 1th argument Type"); >-assert.throws(() => new WebAssembly.Module(getBinary(["void"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 14 / 46: can't get 0th argument Type"); >-assert.throws(() => new WebAssembly.Module(getBinary(["i32", "void", "i32"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 15 / 48: can't get 1th argument Type"); >+assert.throws(() => new WebAssembly.Module(getBinary(["i32", "void"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 15: can't get 1th argument Type"); >+assert.throws(() => new WebAssembly.Module(getBinary(["void"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 14: can't get 0th argument Type"); >+assert.throws(() => new WebAssembly.Module(getBinary(["i32", "void", "i32"])), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 15: can't get 1th argument Type"); >diff --git a/JSTests/wasm/js-api/Module-compile.js b/JSTests/wasm/js-api/Module-compile.js >index d3beb332577aedb058c8e41d23adda9c91f1df78..d723bf4d70b49c49a1365fdc67b45242b38272e6 100644 >--- a/JSTests/wasm/js-api/Module-compile.js >+++ b/JSTests/wasm/js-api/Module-compile.js >@@ -21,7 +21,7 @@ async function testPromiseAPI() { > await WebAssembly.compile(builder.WebAssembly().get()); > } catch(e) { > assert.truthy(e instanceof WebAssembly.CompileError); >- assert.truthy(e.message === "WebAssembly.Module doesn't parse at byte 34 / 43: there can at most be one Memory section for now"); >+ assert.truthy(e.message === "WebAssembly.Module doesn't parse at byte 34: there can at most be one Memory section for now"); > } > } > >diff --git a/JSTests/wasm/js-api/element.js b/JSTests/wasm/js-api/element.js >index 188ac74151126048b827248dc4738205aa86a149..fcbe2827f371663aa84fdf5c10100b8178177390 100644 >--- a/JSTests/wasm/js-api/element.js >+++ b/JSTests/wasm/js-api/element.js >@@ -18,7 +18,7 @@ > .End() > .End(); > >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 24 / 41: Element section for Table 0 exceeds available Table 0"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 24: Element section for Table 0 exceeds available Table 0"); > } > > { >@@ -41,7 +41,7 @@ > .End() > .End(); > >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 47: Element section for Table 1 exceeds available Table 1"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30: Element section for Table 1 exceeds available Table 1"); > } > > { >@@ -112,7 +112,7 @@ > .End() > .End(); > >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 38 / 50: Element section's 0th element's 2th index is 1 which exceeds the function index space size of 1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 38: Element section's 0th element's 2th index is 1 which exceeds the function index space size of 1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); > } > > { >@@ -215,5 +215,5 @@ function badModule() { > return new WebAssembly.Module(bin); > } > >- assert.throws(() => badModule(), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 58 / 72: Element init_expr must produce an i32"); >+ assert.throws(() => badModule(), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 58: Element init_expr must produce an i32"); > } >diff --git a/JSTests/wasm/js-api/global-error.js b/JSTests/wasm/js-api/global-error.js >index 09f8d799dc4e2f39d9a54302caabde7a76d5107b..d3edf898e7d9fa07e470cfc32c6ab36f1731b513 100644 >--- a/JSTests/wasm/js-api/global-error.js >+++ b/JSTests/wasm/js-api/global-error.js >@@ -23,7 +23,7 @@ > const bin = builder.WebAssembly(); > bin.trim(); > >- assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 26 / 59: get_global's index 0 exceeds the number of globals 0 (evaluating 'new WebAssembly.Module(bin.get())')"); >+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 26: get_global's index 0 exceeds the number of globals 0 (evaluating 'new WebAssembly.Module(bin.get())')"); > } > > >@@ -52,7 +52,7 @@ > const bin = builder.WebAssembly(); > bin.trim(); > >- assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 32 / 76: Mutable Globals aren't supported (evaluating 'new WebAssembly.Module(bin.get())')"); >+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 32: Mutable Globals aren't supported (evaluating 'new WebAssembly.Module(bin.get())')"); > } > > { >@@ -77,7 +77,7 @@ > const bin = builder.WebAssembly(); > bin.trim(); > >- assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 51 / 59: 1th Export isn't immutable, named 'global' (evaluating 'new WebAssembly.Module(bin.get())')"); >+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 51: 1th Export isn't immutable, named 'global' (evaluating 'new WebAssembly.Module(bin.get())')"); > } > > { >diff --git a/JSTests/wasm/js-api/table.js b/JSTests/wasm/js-api/table.js >index b832e117664130230fc80bfb130c1366a312e325..cf68b440495f6be6f8b27947712456d7ca7c8c6f 100644 >--- a/JSTests/wasm/js-api/table.js >+++ b/JSTests/wasm/js-api/table.js >@@ -13,7 +13,7 @@ > .End() > .Code() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34 / 41: Cannot have more than one Table for now"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34: Cannot have more than one Table for now"); > } > > { >@@ -38,7 +38,7 @@ > .End() > .Code() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17 / 28: Table count of 2 is invalid, at most 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17: Table count of 2 is invalid, at most 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); > } > > { >@@ -54,7 +54,7 @@ > .CallIndirect(0, 0) > .End() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 4 / 7: call_indirect is only valid when a table is defined or imported, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 4: call_indirect is only valid when a table is defined or imported, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); > } > > { >@@ -73,7 +73,7 @@ > .CallIndirect(0, 1) > .End() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6 / 7: call_indirect's 'reserved' varuint1 must be 0x0, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6: call_indirect's 'reserved' varuint1 must be 0x0, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"); > } > > { >@@ -86,7 +86,7 @@ > .End() > .Code() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23 / 26: can't export Table 0 there are 0 Tables"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23: can't export Table 0 there are 0 Tables"); > } > > { >@@ -102,7 +102,7 @@ > .End() > .Code() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 33: can't export Table 1 there are 1 Tables"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30: can't export Table 1 there are 1 Tables"); > } > > function assertBadTable(tableDescription, message) { >@@ -132,42 +132,42 @@ function assertBadTableImport(tableDescription, message) { > { > let badDescriptions = [ > [{initial: 10, element: "i32"}, >- "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, element: "f32"}, >- "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, element: "f64"}, >- "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, element: "i64"}, >- "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, maximum: 20, element: "i32"}, >- "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, maximum: 20, element: "f32"}, >- "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, maximum: 20, element: "f64"}, >- "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 10, maximum: 20, element: "i64"}, >- "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > > [{initial: 10, maximum: 9, element: "anyfunc"}, >- "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 21: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 1, maximum: 0, element: "anyfunc"}, >- "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 21: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"}, >- "WebAssembly.Module doesn't parse at byte 29 / 32: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 37 / 43: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 37: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > [{initial: 2**31, element: "anyfunc"}, >- "WebAssembly.Module doesn't parse at byte 24 / 27: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >- "WebAssembly.Module doesn't parse at byte 32 / 38: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], >+ "WebAssembly.Module doesn't parse at byte 24: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')", >+ "WebAssembly.Module doesn't parse at byte 32: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"], > ]; > > for (const d of badDescriptions) { >@@ -186,7 +186,7 @@ function assertBadTableImport(tableDescription, message) { > .Function().End() > .Code() > .End(); >- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39 / 48: Cannot have more than one Table for now"); >+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39: Cannot have more than one Table for now"); > } > > >diff --git a/JSTests/wasm/js-api/test_Data.js b/JSTests/wasm/js-api/test_Data.js >index cca0cf3bc45d0f4dd33bd9ca59798954d2d45b18..4171435128a084d5949d8ff2b8b12570b7f23375 100644 >--- a/JSTests/wasm/js-api/test_Data.js >+++ b/JSTests/wasm/js-api/test_Data.js >@@ -52,7 +52,7 @@ > .Segment([0xff]).Offset(0).End() > .End(); > const bin = builder.WebAssembly().get(); >- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15 / 20: 0th Data segment has index 0 which exceeds the number of Memories 0`); >+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15: 0th Data segment has index 0 which exceeds the number of Memories 0`); > })(); > > (function EmptyDataSectionWithoutMemory() { >@@ -62,7 +62,7 @@ > .Segment([]).Offset(0).End() > .End(); > const bin = builder.WebAssembly().get(); >- assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15 / 19: 0th Data segment has index 0 which exceeds the number of Memories 0`); >+ assert.throws(() => new WebAssembly.Module(bin), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 15: 0th Data segment has index 0 which exceeds the number of Memories 0`); > })(); > > (function DataSectionBiggerThanMemory() { >diff --git a/JSTests/wasm/js-api/test_Start.js b/JSTests/wasm/js-api/test_Start.js >index b44456932d90b5c833145ec3f342fc5046f79e0b..5c3150e1cabebfb84333ef71423a8886cde0eae8 100644 >--- a/JSTests/wasm/js-api/test_Start.js >+++ b/JSTests/wasm/js-api/test_Start.js >@@ -31,5 +31,5 @@ > .Start(0).End() // Invalid index. > .Code().End(); > const bin = b.WebAssembly().get(); >- assert.throws(() => new WebAssembly.Module(bin), Error, `WebAssembly.Module doesn't parse at byte 17 / 20: Start index 0 exceeds function index space 0 (evaluating 'new WebAssembly.Module(bin)')`); >+ assert.throws(() => new WebAssembly.Module(bin), Error, `WebAssembly.Module doesn't parse at byte 17: Start index 0 exceeds function index space 0 (evaluating 'new WebAssembly.Module(bin)')`); > })(); >diff --git a/JSTests/wasm/js-api/test_basic_api.js b/JSTests/wasm/js-api/test_basic_api.js >index 08e74aa324a71788e5819c4a8bbe7747585b1a89..1a2d2221030451df0645b30ea31bb2748f5536d0 100644 >--- a/JSTests/wasm/js-api/test_basic_api.js >+++ b/JSTests/wasm/js-api/test_basic_api.js >@@ -67,7 +67,7 @@ > assert.throws(() => new WebAssembly[c](invalid), TypeError, `first argument must be an ArrayBufferView or an ArrayBuffer (evaluating 'new WebAssembly[c](invalid)')`); > for (const buffer of [new ArrayBuffer(), new DataView(new ArrayBuffer()), new Int8Array(), new Uint8Array(), new Uint8ClampedArray(), new Int16Array(), new Uint16Array(), new Int32Array(), new Uint32Array(), new Float32Array(), new Float64Array()]) > // FIXME the following should be WebAssembly.CompileError. https://bugs.webkit.org/show_bug.cgi?id=163768 >- assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0 / 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`); >+ assert.throws(() => new WebAssembly[c](buffer), Error, `WebAssembly.Module doesn't parse at byte 0: expected a module of at least 8 bytes (evaluating 'new WebAssembly[c](buffer)')`); > assert.instanceof(new WebAssembly[c](emptyModuleArray), WebAssembly.Module); > break; > case "Instance": >diff --git a/JSTests/wasm/js-api/version.js b/JSTests/wasm/js-api/version.js >index 81cd7ff0122fb21ce91f80fb51e4c69e14598c47..0486fcfddefd0821d39246cb6408734bfebf22e2 100644 >--- a/JSTests/wasm/js-api/version.js >+++ b/JSTests/wasm/js-api/version.js >@@ -5,5 +5,5 @@ > if (version === 1) > continue; > const emptyModuleArray = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, version, 0x00, 0x00, 0x00); >- assert.throws(() => new WebAssembly.Module(emptyModuleArray), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 8 / 8: unexpected version number ${version} expected 1`); >+ assert.throws(() => new WebAssembly.Module(emptyModuleArray), WebAssembly.CompileError, `WebAssembly.Module doesn't parse at byte 8: unexpected version number ${version} expected 1`); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188943
:
348102
|
348136
|
348139
|
348140
|
348141
|
348142
|
348144
|
348146
|
348147
|
348167