WebKit Bugzilla
Attachment 348136 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-20180827221125.patch (text/plain), 163.13 KB, created by
Yusuke Suzuki
on 2018-08-27 06:11:26 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-08-27 06:11:26 PDT
Size:
163.13 KB
patch
obsolete
>Subversion Revision: 235359 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 2d2ac0bfa067180707e0a5bb5aae74ef2eb3ae60..0b531abd8ffc8b86244e61843d512b1fe5aaad81 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,165 @@ >+2018-08-27 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!). >+ >+ This patch adds Wasm::StreamingParser, which parses wasm binary in a streaming fashion. >+ Currently, this StreamingParser is not enabled and integrated. In subsequent patches, >+ we start integrating it into BBQPlan and dropping the old ModuleParser. >+ >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * 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): >+ This object is introduced for testing purpose. Added new stress test uses this interface >+ to test streaming parser in the JSC shell. >+ >+ * wasm/WasmBBQPlan.cpp: >+ (JSC::Wasm::BBQPlan::BBQPlan): >+ (JSC::Wasm::BBQPlan::parseAndValidateModule): >+ (JSC::Wasm::BBQPlan::prepare): >+ (JSC::Wasm::BBQPlan::compileFunctions): >+ (JSC::Wasm::BBQPlan::complete): >+ (JSC::Wasm::BBQPlan::work): >+ * wasm/WasmBBQPlan.h: >+ BBQPlan has m_source, but once ModuleInformation is parsed, it is no longer necessary. >+ In subsequent patches, we will remove this, and stream the data into the BBQPlan. >+ >+ * wasm/WasmFormat.h: >+ * wasm/WasmModuleInformation.cpp: >+ (JSC::Wasm::ModuleInformation::ModuleInformation): >+ * wasm/WasmModuleInformation.h: >+ One of the largest change in this patch is that ModuleInformation no longer holds source bytes, >+ since source bytes can be added in a streaming fashion. Instead of holding all the source bytes >+ in ModuleInformation, each function (ModuleInformation::functions, FunctionData) should have >+ Vector<uint8_t> for its data. This data is eventually filled by StreamingParser, and compiling >+ a function with this data can be done concurrently with StreamingParser. >+ >+ (JSC::Wasm::ModuleInformation::create): >+ (JSC::Wasm::ModuleInformation::memoryCount const): >+ (JSC::Wasm::ModuleInformation::tableCount const): >+ memoryCount and tableCount should be recoreded in ModuleInformation. >+ >+ * 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. >+ Extract section parsing code out from ModuleParser. We create SectionParser and ModuleParser uses it. >+ SectionParser is also used by StreamingParser. >+ >+ * wasm/WasmModuleParser.h: >+ * wasm/WasmNameSection.h: >+ (JSC::Wasm::NameSection::NameSection): >+ (JSC::Wasm::NameSection::create): >+ (JSC::Wasm::NameSection::setHash): >+ Hash calculation is deferred since all the source is not available in streaming parsing. >+ >+ * wasm/WasmNameSectionParser.cpp: >+ (JSC::Wasm::NameSectionParser::parse): >+ * wasm/WasmNameSectionParser.h: >+ Use Ref<NameSection>. >+ >+ * wasm/WasmOMGPlan.cpp: >+ (JSC::Wasm::OMGPlan::work): >+ Wasm::Plan no longer have m_source since data will be eventually filled in a streaming fashion. >+ OMGPlan can get data of the function by using ModuleInformation::functions. >+ >+ * 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/WasmPlan.cpp: >+ (JSC::Wasm::Plan::Plan): >+ Wasm::Plan should not have all the source apriori. Streamed data will be pumped from the provider. >+ >+ * wasm/WasmPlan.h: >+ * 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. >+ SectionParser is extracted from ModuleParser. And it is used both the old (currently working) ModuleParser >+ and the new StreamingParser. >+ >+ * wasm/WasmStreamingParser.cpp: Added. >+ (JSC::Wasm::parseUInt7): >+ (JSC::Wasm::StreamingParser::fail): >+ (JSC::Wasm::StreamingParser::StreamingParser): >+ (JSC::Wasm::StreamingParser::parseModuleHeader): >+ (JSC::Wasm::StreamingParser::parseSectionHeader): >+ (JSC::Wasm::StreamingParser::parseSectionSize): >+ (JSC::Wasm::StreamingParser::parseCodeSectionSize): >+ Code section in Wasm binary is specially handled compared with the other sections since it includes >+ bunch of functions. StreamingParser extracts each function in a streaming fashion and enable streaming >+ validation / compilation of Wasm functions. >+ >+ (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::failOnState): >+ (JSC::Wasm::StreamingParser::finalize): >+ * wasm/WasmStreamingParser.h: Added. >+ (JSC::Wasm::StreamingParser::addBytes): >+ (JSC::Wasm::StreamingParser::errorMessage const): >+ This is our new StreamingParser implementation. StreamingParser::consumeXXX functions get data, and >+ StreamingParser::parseXXX functions parse consumed data. The user of StreamingParser calls >+ StreamingParser::addBytes() to pump the bytes stream into the parser. And once all the data is pumped, >+ the user calls StreamingParser::finalize. StreamingParser is a state machine which feeds the incoming >+ byte stream. >+ >+ * wasm/js/JSWebAssemblyModule.cpp: >+ (JSC::JSWebAssemblyModule::source const): Deleted. >+ All the source should not be held. >+ >+ * wasm/js/JSWebAssemblyModule.h: >+ * wasm/js/WebAssemblyPrototype.cpp: >+ (JSC::webAssemblyValidateFunc): >+ > 2018-08-24 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > [JSC] Array.prototype.reverse modifies JSImmutableButterfly >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 17a48bda6d4be397b08e946cbd48610674799dae..426d19dce95482e851bfe9c9387d2cf633f55d48 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -1734,6 +1734,8 @@ > E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E393ADD71FE702CC0022D681 /* WeakMapImplInlines.h */; }; > E39D45F51D39005600B3B377 /* InterpreterInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E39D9D841D39000600667282 /* InterpreterInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E39DA4A71B7E8B7C0084F33A /* JSModuleRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ E3A0531A21342B680022EC14 /* WasmStreamingParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531621342B660022EC14 /* WasmStreamingParser.h */; }; >+ E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A0531821342B670022EC14 /* WasmSectionParser.h */; }; > E3A32BC71FC83147007D7E76 /* WeakMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A32BC61FC8312E007D7E76 /* WeakMapImpl.h */; }; > E3A421431D6F58930007C617 /* PreciseJumpTargetsInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E3BFD0BC1DAF808E0065DEA2 /* AccessCaseSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E3BFD0BA1DAF807C0065DEA2 /* AccessCaseSnippetParams.h */; }; >@@ -4622,6 +4624,10 @@ > E39D9D841D39000600667282 /* InterpreterInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterpreterInlines.h; sourceTree = "<group>"; }; > E39DA4A41B7E8B7C0084F33A /* JSModuleRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleRecord.cpp; sourceTree = "<group>"; }; > E39DA4A51B7E8B7C0084F33A /* JSModuleRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleRecord.h; sourceTree = "<group>"; }; >+ E3A0531621342B660022EC14 /* WasmStreamingParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmStreamingParser.h; sourceTree = "<group>"; }; >+ E3A0531721342B660022EC14 /* WasmSectionParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmSectionParser.cpp; sourceTree = "<group>"; }; >+ E3A0531821342B670022EC14 /* WasmSectionParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmSectionParser.h; sourceTree = "<group>"; }; >+ E3A0531921342B670022EC14 /* WasmStreamingParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmStreamingParser.cpp; sourceTree = "<group>"; }; > E3A32BC51FC8312D007D7E76 /* WeakMapImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WeakMapImpl.cpp; sourceTree = "<group>"; }; > E3A32BC61FC8312E007D7E76 /* WeakMapImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakMapImpl.h; sourceTree = "<group>"; }; > E3A421421D6F588F0007C617 /* PreciseJumpTargetsInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreciseJumpTargetsInlines.h; sourceTree = "<group>"; }; >@@ -6348,9 +6354,13 @@ > 53F40E8C1D5901F20099A1B6 /* WasmParser.h */, > 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */, > 531374BC1D5CE67600AF7A0B /* WasmPlan.h */, >+ E3A0531721342B660022EC14 /* WasmSectionParser.cpp */, >+ E3A0531821342B670022EC14 /* WasmSectionParser.h */, > 53F40E841D58F9770099A1B6 /* WasmSections.h */, > AD7438BE1E04579200FD0C2A /* WasmSignature.cpp */, > AD7438BF1E04579200FD0C2A /* WasmSignature.h */, >+ E3A0531921342B670022EC14 /* WasmStreamingParser.cpp */, >+ E3A0531621342B660022EC14 /* WasmStreamingParser.h */, > AD5C36E31F69EC8B000BCAAF /* WasmTable.cpp */, > AD5C36E41F69EC8B000BCAAF /* WasmTable.h */, > 5250D2CF1E8DA05A0029A932 /* WasmThunks.cpp */, >@@ -8448,7 +8458,6 @@ > C2FCAE1317A9C24E0034C735 /* BytecodeLivenessAnalysis.h in Headers */, > 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */, > E328DAEB1D38D005001A2529 /* BytecodeRewriter.h in Headers */, >- FEA3BBAC212C97CB00E93AD1 /* DFGCFG.h in Headers */, > 6514F21918B3E1670098FF8B /* Bytecodes.h in Headers */, > 0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */, > 0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */, >@@ -8581,6 +8590,7 @@ > 0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */, > 0F7B294B14C3CD2F007C3DB1 /* DFGCapabilities.h in Headers */, > 0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */, >+ FEA3BBAC212C97CB00E93AD1 /* DFGCFG.h in Headers */, > 0F3B3A281544C997003ED0FF /* DFGCFGSimplificationPhase.h in Headers */, > 0F9D36951AE9CC33000D4DFB /* DFGCleanUpPhase.h in Headers */, > A77A424017A0BBFD00A8DB81 /* DFGClobberize.h in Headers */, >@@ -9607,8 +9617,10 @@ > 79B759761DFA4C600052174C /* WasmPageCount.h in Headers */, > 53F40E8D1D5901F20099A1B6 /* WasmParser.h in Headers */, > 531374BD1D5CE67600AF7A0B /* WasmPlan.h in Headers */, >+ E3A0531C21342B680022EC14 /* WasmSectionParser.h in Headers */, > 53F40E851D58F9770099A1B6 /* WasmSections.h in Headers */, > AD7438C01E0457A400FD0C2A /* WasmSignature.h in Headers */, >+ E3A0531A21342B680022EC14 /* WasmStreamingParser.h in Headers */, > AD5C36E61F69EC91000BCAAF /* WasmTable.h in Headers */, > 5250D2D21E8DA05A0029A932 /* WasmThunks.h in Headers */, > 53E9E0AF1EAEC45700FEE251 /* WasmTierUpCount.h in Headers */, >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..ef255724bc6a1120016b7f22f969dbffd9cae23f 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(Wasm::ModuleInformation::create()) >+ , 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/WasmBBQPlan.cpp b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp >index f672686d3f99a0d0d2e9c321f27bc0a1cbf5b2dd..43c8f562afa1c3633a7e6c61f40922ec0be97213 100644 >--- a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp >+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp >@@ -59,13 +59,15 @@ BBQPlan::BBQPlan(Context* context, Ref<ModuleInformation> info, AsyncWork work, > } > > BBQPlan::BBQPlan(Context* context, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException) >- : BBQPlan(context, adoptRef(*new ModuleInformation(WTFMove(source))), work, WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException) >+ : Base(context, ModuleInformation::create(), WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException) >+ , m_source(WTFMove(source)) >+ , m_state(State::Initial) >+ , m_asyncWork(work) > { >- m_state = State::Initial; > } > >-BBQPlan::BBQPlan(Context* context, const uint8_t* source, size_t sourceLength, AsyncWork work, CompletionTask&& task) >- : Base(context, source, sourceLength, WTFMove(task)) >+BBQPlan::BBQPlan(Context* context, AsyncWork work, CompletionTask&& task) >+ : Base(context, WTFMove(task)) > , m_state(State::Initial) > , m_asyncWork(work) > { >@@ -90,7 +92,7 @@ void BBQPlan::moveToState(State state) > m_state = state; > } > >-bool BBQPlan::parseAndValidateModule() >+bool BBQPlan::parseAndValidateModule(const uint8_t* source, size_t sourceLength) > { > if (m_state != State::Initial) > return true; >@@ -101,7 +103,7 @@ bool BBQPlan::parseAndValidateModule() > startTime = MonotonicTime::now(); > > { >- ModuleParser moduleParser(m_source, m_sourceLength, m_moduleInformation); >+ ModuleParser moduleParser(source, sourceLength, m_moduleInformation); > auto parseResult = moduleParser.parse(); > if (!parseResult) { > Base::fail(holdLock(m_lock), WTFMove(parseResult.error())); >@@ -109,20 +111,21 @@ bool BBQPlan::parseAndValidateModule() > } > } > >- const auto& functionLocations = m_moduleInformation->functionLocationInBinary; >- for (unsigned functionIndex = 0; functionIndex < functionLocations.size(); ++functionIndex) { >- dataLogLnIf(WasmBBQPlanInternal::verbose, "Processing function starting at: ", functionLocations[functionIndex].start, " and ending at: ", functionLocations[functionIndex].end); >- const uint8_t* functionStart = m_source + functionLocations[functionIndex].start; >- size_t functionLength = functionLocations[functionIndex].end - functionLocations[functionIndex].start; >- ASSERT(functionLength <= m_sourceLength); >+ const auto& functions = m_moduleInformation->functions; >+ for (unsigned functionIndex = 0; functionIndex < functions.size(); ++functionIndex) { >+ const auto& function = functions[functionIndex]; >+ dataLogLnIf(WasmBBQPlanInternal::verbose, "Processing function starting at: ", function.start, " and ending at: ", function.end); >+ size_t functionLength = function.end - function.start; >+ ASSERT(functionLength <= sourceLength); >+ ASSERT(functionLength == function.data.size()); > SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex]; > const Signature& signature = SignatureInformation::get(signatureIndex); > >- auto validationResult = validateFunction(functionStart, functionLength, signature, m_moduleInformation.get()); >+ auto validationResult = validateFunction(function.data.data(), function.data.size(), signature, m_moduleInformation.get()); > if (!validationResult) { > if (WasmBBQPlanInternal::verbose) { > for (unsigned i = 0; i < functionLength; ++i) >- dataLog(RawPointer(reinterpret_cast<void*>(functionStart[i])), ", "); >+ dataLog(RawPointer(reinterpret_cast<void*>(function.data[i])), ", "); > dataLogLn(); > } > Base::fail(holdLock(m_lock), makeString(validationResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected. >@@ -156,18 +159,18 @@ void BBQPlan::prepare() > return true; > }; > >- const auto& functionLocations = m_moduleInformation->functionLocationInBinary; >+ const auto& functions = m_moduleInformation->functions; > if (!tryReserveCapacity(m_wasmToWasmExitStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs") >- || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, functionLocations.size(), " unlinked WebAssembly to WebAssembly calls") >- || !tryReserveCapacity(m_wasmInternalFunctions, functionLocations.size(), " WebAssembly functions") >- || !tryReserveCapacity(m_compilationContexts, functionLocations.size(), " compilation contexts") >- || !tryReserveCapacity(m_tierUpCounts, functionLocations.size(), " tier-up counts")) >+ || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, functions.size(), " unlinked WebAssembly to WebAssembly calls") >+ || !tryReserveCapacity(m_wasmInternalFunctions, functions.size(), " WebAssembly functions") >+ || !tryReserveCapacity(m_compilationContexts, functions.size(), " compilation contexts") >+ || !tryReserveCapacity(m_tierUpCounts, functions.size(), " tier-up counts")) > return; > >- m_unlinkedWasmToWasmCalls.resize(functionLocations.size()); >- m_wasmInternalFunctions.resize(functionLocations.size()); >- m_compilationContexts.resize(functionLocations.size()); >- m_tierUpCounts.resize(functionLocations.size()); >+ m_unlinkedWasmToWasmCalls.resize(functions.size()); >+ m_wasmInternalFunctions.resize(functions.size()); >+ m_compilationContexts.resize(functions.size()); >+ m_tierUpCounts.resize(functions.size()); > > for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) { > Import* import = &m_moduleInformation->imports[importIndex]; >@@ -241,7 +244,7 @@ void BBQPlan::compileFunctions(CompilationEffort effort) > ThreadCountHolder holder(*this); > > size_t bytesCompiled = 0; >- const auto& functionLocations = m_moduleInformation->functionLocationInBinary; >+ const auto& functions = m_moduleInformation->functions; > while (true) { > if (effort == Partial && bytesCompiled >= Options::webAssemblyPartialCompileLimit()) > return; >@@ -249,7 +252,7 @@ void BBQPlan::compileFunctions(CompilationEffort effort) > uint32_t functionIndex; > { > auto locker = holdLock(m_lock); >- if (m_currentIndex >= functionLocations.size()) { >+ if (m_currentIndex >= functions.size()) { > if (hasWork()) > moveToState(State::Compiled); > return; >@@ -258,18 +261,16 @@ void BBQPlan::compileFunctions(CompilationEffort effort) > ++m_currentIndex; > } > >- const uint8_t* functionStart = m_source + functionLocations[functionIndex].start; >- size_t functionLength = functionLocations[functionIndex].end - functionLocations[functionIndex].start; >- ASSERT(functionLength <= m_sourceLength); >+ const auto& function = functions[functionIndex]; > SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex]; > const Signature& signature = SignatureInformation::get(signatureIndex); > unsigned functionIndexSpace = m_wasmToWasmExitStubs.size() + functionIndex; > ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex); >- ASSERT(validateFunction(functionStart, functionLength, signature, m_moduleInformation.get())); >+ ASSERT(validateFunction(function.data.data(), function.data.size(), signature, m_moduleInformation.get())); > > m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>(); > TierUpCount* tierUp = Options::useBBQTierUpChecks() ? &m_tierUpCounts[functionIndex] : nullptr; >- auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp, m_throwWasmException); >+ auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], function.data.data(), function.data.size(), signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp, m_throwWasmException); > > if (UNLIKELY(!parseAndCompileResult)) { > auto locker = holdLock(m_lock); >@@ -277,7 +278,7 @@ void BBQPlan::compileFunctions(CompilationEffort effort) > // Multiple compiles could fail simultaneously. We arbitrarily choose the first. > fail(locker, makeString(parseAndCompileResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected. > } >- m_currentIndex = functionLocations.size(); >+ m_currentIndex = functions.size(); > return; > } > >@@ -289,17 +290,17 @@ void BBQPlan::compileFunctions(CompilationEffort effort) > ASSERT_UNUSED(result, result.isNewEntry); > } > >- bytesCompiled += functionLength; >+ bytesCompiled += function.data.size(); > } > } > > void BBQPlan::complete(const AbstractLocker& locker) > { >- ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functionLocationInBinary.size()); >+ ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functions.size()); > dataLogLnIf(WasmBBQPlanInternal::verbose, "Starting Completion"); > > if (!failed() && m_state == State::Compiled) { >- for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functionLocationInBinary.size(); functionIndex++) { >+ for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functions.size(); functionIndex++) { > CompilationContext& context = m_compilationContexts[functionIndex]; > SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex]; > const Signature& signature = SignatureInformation::get(signatureIndex); >@@ -351,7 +352,7 @@ void BBQPlan::work(CompilationEffort effort) > { > switch (m_state) { > case State::Initial: >- parseAndValidateModule(); >+ parseAndValidateModule(m_source.data(), m_source.size()); > if (!hasWork()) { > ASSERT(isComplete()); > return; >diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlan.h b/Source/JavaScriptCore/wasm/WasmBBQPlan.h >index d88145d7dddbd6b1910577817ce7cb8db4121d1e..941ac75f70e6f911b9fbb3ddb1378ccf969941ad 100644 >--- a/Source/JavaScriptCore/wasm/WasmBBQPlan.h >+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.h >@@ -52,11 +52,14 @@ class BBQPlan final : public Plan { > // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle. > BBQPlan(Context*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException); > JS_EXPORT_PRIVATE BBQPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException); >- // Note: This constructor should only be used if you are not actually building a module e.g. validation/function tests >- // FIXME: When we get rid of function tests we should remove AsyncWork from this constructor. >- JS_EXPORT_PRIVATE BBQPlan(Context*, const uint8_t*, size_t, AsyncWork, CompletionTask&&); >+ BBQPlan(Context*, AsyncWork, CompletionTask&&); > >- bool parseAndValidateModule(); >+ >+ bool parseAndValidateModule() >+ { >+ return parseAndValidateModule(m_source.data(), m_source.size()); >+ } >+ bool parseAndValidateModule(const uint8_t*, size_t); > > JS_EXPORT_PRIVATE void prepare(); > void compileFunctions(CompilationEffort); >@@ -136,6 +139,7 @@ class BBQPlan final : public Plan { > > const char* stateString(State); > >+ Vector<uint8_t> m_source; > Bag<CallLinkInfo> m_callLinkInfos; > Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>> m_wasmToWasmExitStubs; > Vector<std::unique_ptr<InternalFunction>> m_wasmInternalFunctions; >diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h >index 2784e90af3841a02e5873332cff8bb06487e33de..e43f4ed936167ff2938d837a0ce088d43d20a4e6 100644 >--- a/Source/JavaScriptCore/wasm/WasmFormat.h >+++ b/Source/JavaScriptCore/wasm/WasmFormat.h >@@ -140,9 +140,10 @@ struct Global { > uint64_t initialBitsOrImportNumber { 0 }; > }; > >-struct FunctionLocationInBinary { >+struct FunctionData { > size_t start; > size_t end; >+ Vector<uint8_t> data; > }; > > class I32InitExpr { >diff --git a/Source/JavaScriptCore/wasm/WasmModuleInformation.cpp b/Source/JavaScriptCore/wasm/WasmModuleInformation.cpp >index cb8db0e093f94cda316dd24baf39e512eda20314..8a254c002fbe9ef90cef1abdfc4169c1e46c53dc 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleInformation.cpp >+++ b/Source/JavaScriptCore/wasm/WasmModuleInformation.cpp >@@ -31,21 +31,10 @@ > #include "WasmNameSection.h" > #include <wtf/SHA1.h> > >-namespace { >-CString sha1(const Vector<uint8_t>& input) >-{ >- SHA1 hash; >- hash.addBytes(input); >- return hash.computeHexDigest(); >-} >-} >- > namespace JSC { namespace Wasm { > >-ModuleInformation::ModuleInformation(Vector<uint8_t>&& sourceBytes) >- : source(WTFMove(sourceBytes)) >- , hash(Options::useEagerWebAssemblyModuleHashing() ? std::make_optional(sha1(source)) : std::nullopt) >- , nameSection(new NameSection(hash)) >+ModuleInformation::ModuleInformation() >+ : nameSection(NameSection::create()) > { > } > ModuleInformation::~ModuleInformation() { } >diff --git a/Source/JavaScriptCore/wasm/WasmModuleInformation.h b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >index 0bab57e070d2ea33062f363658a2415e9bd51e2d..fb5e3a0cded4e738024303be5e0f567af55ba025 100644 >--- a/Source/JavaScriptCore/wasm/WasmModuleInformation.h >+++ b/Source/JavaScriptCore/wasm/WasmModuleInformation.h >@@ -34,11 +34,14 @@ > namespace JSC { namespace Wasm { > > struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { >- ModuleInformation() = delete; >+ ModuleInformation(); > ModuleInformation(const ModuleInformation&) = delete; > ModuleInformation(ModuleInformation&&) = delete; > >- ModuleInformation(Vector<uint8_t>&& sourceBytes); >+ static Ref<ModuleInformation> create() >+ { >+ return adoptRef(*new ModuleInformation); >+ } > > JS_EXPORT_PRIVATE ~ModuleInformation(); > >@@ -58,8 +61,8 @@ struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { > uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); } > uint32_t internalFunctionCount() const { return internalFunctionSignatureIndices.size(); } > >- const Vector<uint8_t> source; >- const std::optional<CString> hash; >+ uint32_t memoryCount() const { return memory ? 1 : 0; } >+ uint32_t tableCount() const { return tableInformation ? 1 : 0; } > > Vector<Import> imports; > Vector<SignatureIndex> importFunctionSignatureIndices; >@@ -68,7 +71,7 @@ struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { > > MemoryInformation memory; > >- Vector<FunctionLocationInBinary> functionLocationInBinary; >+ Vector<FunctionData> functions; > > Vector<Export> exports; > std::optional<uint32_t> startFunctionIndexSpace; >@@ -78,7 +81,7 @@ struct ModuleInformation : public ThreadSafeRefCounted<ModuleInformation> { > Vector<Global> globals; > unsigned firstInternalGlobal { 0 }; > Vector<CustomSection> customSections; >- RefPtr<NameSection> nameSection; >+ Ref<NameSection> nameSection; > }; > > >diff --git a/Source/JavaScriptCore/wasm/WasmModuleParser.cpp b/Source/JavaScriptCore/wasm/WasmModuleParser.cpp >index f03e6987f4a502591df71dc815782080996138b4..a8ed8d2e6b19c95f671ffcbc54783da74c65080f 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,538 +86,24 @@ 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)) > previousKnownSection = section; > } > >- 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 }); >+ if (Options::useEagerWebAssemblyModuleHashing()) { >+ SHA1 hasher; >+ hasher.addBytes(source(), length()); >+ m_info->nameSection->setHash(hasher.computeHexDigest()); > } > > 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/WasmNameSection.h b/Source/JavaScriptCore/wasm/WasmNameSection.h >index 7c02f2f4197705ac8beeef4418990d28ee34f084..fe63cf5547366fc1740c1f0c70ba81be7536a88e 100644 >--- a/Source/JavaScriptCore/wasm/WasmNameSection.h >+++ b/Source/JavaScriptCore/wasm/WasmNameSection.h >@@ -36,11 +36,20 @@ namespace JSC { namespace Wasm { > > struct NameSection : public ThreadSafeRefCounted<NameSection> { > WTF_MAKE_NONCOPYABLE(NameSection); >- > public: >- NameSection(const std::optional<CString> &hash) >- : moduleHash(hash ? hash->length() : 3) >+ NameSection() >+ { >+ setHash(std::nullopt); >+ } >+ >+ static Ref<NameSection> create() >+ { >+ return adoptRef(*new NameSection); >+ } >+ >+ void setHash(const std::optional<CString> &hash) > { >+ moduleHash = Name(hash ? hash->length() : 3); > if (hash) { > for (size_t i = 0; i < hash->length(); ++i) > moduleHash[i] = static_cast<uint8_t>(*(hash->data() + i)); >diff --git a/Source/JavaScriptCore/wasm/WasmNameSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmNameSectionParser.cpp >index 73396215cf58bc526b348cc0a88c713d4dec5977..c7fe884c3234abaac5eba7c89465489cd822f291 100644 >--- a/Source/JavaScriptCore/wasm/WasmNameSectionParser.cpp >+++ b/Source/JavaScriptCore/wasm/WasmNameSectionParser.cpp >@@ -35,7 +35,7 @@ namespace JSC { namespace Wasm { > > auto NameSectionParser::parse() -> Result > { >- RefPtr<NameSection> nameSection(adoptRef(*new NameSection(m_info.hash))); >+ Ref<NameSection> nameSection = NameSection::create(); > WASM_PARSER_FAIL_IF(!nameSection->functionNames.tryReserveCapacity(m_info.functionIndexSpaceSize()), "can't allocate enough memory for function names"); > nameSection->functionNames.resize(m_info.functionIndexSpaceSize()); > >diff --git a/Source/JavaScriptCore/wasm/WasmNameSectionParser.h b/Source/JavaScriptCore/wasm/WasmNameSectionParser.h >index b7af0d9b90a6d526e92d4d824feedb44d5987683..d8e6ae71b26b4becc8b888bbfd5eb27985c6d219 100644 >--- a/Source/JavaScriptCore/wasm/WasmNameSectionParser.h >+++ b/Source/JavaScriptCore/wasm/WasmNameSectionParser.h >@@ -33,7 +33,7 @@ > > namespace JSC { namespace Wasm { > >-class NameSectionParser : public Parser<RefPtr<NameSection>> { >+class NameSectionParser : public Parser<Ref<NameSection>> { > public: > NameSectionParser(const uint8_t* sourceBuffer, size_t sourceLength, const ModuleInformation& info) > : Parser(sourceBuffer, sourceLength) >diff --git a/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp b/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp >index 47dead64af8fd5c3699d2e8f640ed8beb0420c9d..9e0c4a5666e44e0eacc2312abbb765453b879f48 100644 >--- a/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp >+++ b/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp >@@ -69,21 +69,18 @@ void OMGPlan::work(CompilationEffort) > { > ASSERT(m_codeBlock->runnable()); > ASSERT(m_codeBlock.ptr() == m_module->codeBlockFor(mode())); >- const FunctionLocationInBinary& location = m_moduleInformation->functionLocationInBinary[m_functionIndex]; >- const uint8_t* functionStart = m_moduleInformation->source.data() + location.start; >- const size_t functionLength = location.end - location.start; >- ASSERT(functionStart + functionLength <= m_moduleInformation->source.end()); >+ const FunctionData& function = m_moduleInformation->functions[m_functionIndex]; > > const uint32_t functionIndexSpace = m_functionIndex + m_module->moduleInformation().importFunctionCount(); > ASSERT(functionIndexSpace < m_module->moduleInformation().functionIndexSpaceSize()); > > SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[m_functionIndex]; > const Signature& signature = SignatureInformation::get(signatureIndex); >- ASSERT(validateFunction(functionStart, functionLength, signature, m_moduleInformation.get())); >+ ASSERT(validateFunction(function.data.data(), function.data.size(), signature, m_moduleInformation.get())); > > Vector<UnlinkedWasmToWasmCall> unlinkedCalls; > CompilationContext context; >- auto parseAndCompileResult = parseAndCompile(context, functionStart, functionLength, signature, unlinkedCalls, m_moduleInformation.get(), m_mode, CompilationMode::OMGMode, m_functionIndex); >+ auto parseAndCompileResult = parseAndCompile(context, function.data.data(), function.data.size(), signature, unlinkedCalls, m_moduleInformation.get(), m_mode, CompilationMode::OMGMode, m_functionIndex); > > if (UNLIKELY(!parseAndCompileResult)) { > fail(holdLock(m_lock), makeString(parseAndCompileResult.error(), "when trying to tier up ", String::number(m_functionIndex))); >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/WasmPlan.cpp b/Source/JavaScriptCore/wasm/WasmPlan.cpp >index a34deecb16b140beb53b87c6e2a7039834930c2c..9974ecfe55baf289eec565066a1cd49ae23a820a 100644 >--- a/Source/JavaScriptCore/wasm/WasmPlan.cpp >+++ b/Source/JavaScriptCore/wasm/WasmPlan.cpp >@@ -53,8 +53,6 @@ Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task, > : m_moduleInformation(WTFMove(info)) > , m_createEmbedderWrapper(WTFMove(createEmbedderWrapper)) > , m_throwWasmException(throwWasmException) >- , m_source(m_moduleInformation->source.data()) >- , m_sourceLength(m_moduleInformation->source.size()) > { > m_completionTasks.append(std::make_pair(context, WTFMove(task))); > } >@@ -64,10 +62,8 @@ Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task) > { > } > >-Plan::Plan(Context* context, const uint8_t* source, size_t sourceLength, CompletionTask&& task) >- : m_moduleInformation(adoptRef(*new ModuleInformation(Vector<uint8_t>()))) >- , m_source(source) >- , m_sourceLength(sourceLength) >+Plan::Plan(Context* context, CompletionTask&& task) >+ : m_moduleInformation(ModuleInformation::create()) > { > m_completionTasks.append(std::make_pair(context, WTFMove(task))); > } >diff --git a/Source/JavaScriptCore/wasm/WasmPlan.h b/Source/JavaScriptCore/wasm/WasmPlan.h >index 7a07bfd3a0b06e93440957db36de6dddae63c64c..9ec6886581331bacc9f08dd26f9aabb4e9bd53bf 100644 >--- a/Source/JavaScriptCore/wasm/WasmPlan.h >+++ b/Source/JavaScriptCore/wasm/WasmPlan.h >@@ -54,7 +54,7 @@ class Plan : public ThreadSafeRefCounted<Plan> { > Plan(Context*, Ref<ModuleInformation>, CompletionTask&&); > > // Note: This constructor should only be used if you are not actually building a module e.g. validation/function tests >- JS_EXPORT_PRIVATE Plan(Context*, const uint8_t*, size_t, CompletionTask&&); >+ JS_EXPORT_PRIVATE Plan(Context*, CompletionTask&&); > virtual JS_EXPORT_PRIVATE ~Plan(); > > // If you guarantee the ordering here, you can rely on FIFO of the >@@ -90,8 +90,6 @@ class Plan : public ThreadSafeRefCounted<Plan> { > CreateEmbedderWrapper m_createEmbedderWrapper; > ThrowWasmException m_throwWasmException { nullptr }; > >- const uint8_t* m_source; >- const size_t m_sourceLength; > String m_errorMessage; > MemoryMode m_mode { MemoryMode::BoundsChecking }; > Lock m_lock; >diff --git a/Source/JavaScriptCore/wasm/WasmSectionParser.cpp b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..9a9bacb67ded2504535d8c2de5c5ed833def1602 >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmSectionParser.cpp >@@ -0,0 +1,562 @@ >+/* >+ * 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->functions.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->functions.uncheckedAppend({ start, end, Vector<uint8_t>() }); >+ } >+ >+ 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 { }; >+} >+ >+// This function will be changed to be RELEASE_ASSERT_NOT_REACHED once we switch our parsing infrastructure to the streaming parser. >+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->functions.size(), "Code section count ", count, " exceeds the declared number of functions ", m_info->functions.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"); >+ >+ Vector<uint8_t> data(functionSize); >+ std::memcpy(data.data(), source() + m_offset, functionSize); >+ m_info->functions[i].start = m_offsetInSource + m_offset; >+ m_info->functions[i].end = m_offsetInSource + m_offset + functionSize; >+ m_info->functions[i].data = WTFMove(data); >+ 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..3c2d3f9a31b12fd2faf5ccabbea513e3b4c7c240 >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmStreamingParser.cpp >@@ -0,0 +1,390 @@ >+/* >+ * 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 = false; >+} >+ >+#define WASM_STREAMING_PARSER_FAIL_IF_HELPER_FAILS(helper) \ >+ do { \ >+ auto helperResult = helper; \ >+ if (UNLIKELY(!helperResult)) { \ >+ m_errorMessage = helperResult.error(); \ >+ 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; >+} >+ >+template <typename ...Args> >+NEVER_INLINE auto WARN_UNUSED_RETURN StreamingParser::fail(Args... args) -> State >+{ >+ using namespace FailureHelper; // See ADL comment in namespace above. >+ m_errorMessage = makeString("WebAssembly.Module doesn't parse at byte "_s, String::number(m_offset), ": "_s, makeString(args)...); >+ dataLogLnIf(WasmStreamingParserInternal::verbose, m_errorMessage); >+ return State::FatalError; >+} >+ >+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_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_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_PARSER_FAIL_IF(!result, "can't get section byte"); >+ >+ Section section = Section::Custom; >+ WASM_PARSER_FAIL_IF(!decodeSection(*result, section), "invalid section"); >+ ASSERT(section != Section::Begin); >+ WASM_PARSER_FAIL_IF(!validateOrder(m_previousKnownSection, section), "invalid section order, ", m_previousKnownSection, " followed by ", 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_PARSER_FAIL_IF(functionCount == std::numeric_limits<uint32_t>::max(), "Code section's count is too big ", functionCount); >+ WASM_PARSER_FAIL_IF(functionCount != m_info->functions.size(), "Code section count ", functionCount, " exceeds the declared number of functions ", m_info->functions.size()); >+ >+ if (m_functionIndex == m_functionCount) { >+ WASM_PARSER_FAIL_IF((m_codeOffset + m_sectionLength) != m_offset, "parsing ended before the end of ", m_section, " section"); >+ return State::SectionHeader; >+ } >+ return State::FunctionHeader; >+} >+ >+auto StreamingParser::parseFunctionHeader(uint32_t functionSize) -> State >+{ >+ m_functionSize = functionSize; >+ WASM_PARSER_FAIL_IF(functionSize > maxFunctionSize, "Code function's size ", functionSize, " is too big"); >+ return State::FunctionBody; >+} >+ >+auto StreamingParser::parseFunctionBody(Vector<uint8_t>&& data) -> State >+{ >+ auto& function = m_info->functions[m_functionIndex]; >+ function.start = m_offset; >+ function.end = m_offset + m_functionSize; >+ function.data = WTFMove(data); >+ dataLogLnIf(WasmStreamingParserInternal::verbose, "Processing function starting at: ", function.start, " and ending at: ", function.end); >+ ++m_functionIndex; >+ if (m_functionIndex == m_functionCount) { >+ WASM_PARSER_FAIL_IF((m_codeOffset + m_sectionLength) != (m_offset + m_functionSize), "parsing ended before the end of ", m_section, " section"); >+ return State::SectionHeader; >+ } >+ 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_PARSER_FAIL_IF(parser.length() != parser.offset(), "parsing ended before the end of ", m_section, " section"); >+ >+ return State::SectionHeader; >+} >+ >+auto StreamingParser::consume(const uint8_t* bytes, size_t bytesSize, size_t& offsetInBytes, size_t requiredSize) -> std::optional<Vector<uint8_t>> >+{ >+ 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 std::nullopt; >+ } >+ >+ 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 >+{ >+ if (m_state == State::FatalError) >+ return m_state; >+ >+ m_totalSize += bytesSize; >+ if (UNLIKELY(m_totalSize.hasOverflowed() || m_totalSize.unsafeGet() > maxModuleSize)) { >+ m_state = fail("module size is too large, maximum ", maxModuleSize); >+ return m_state; >+ } >+ >+ if (Options::useEagerWebAssemblyModuleHashing()) >+ m_hasher.addBytes(bytes, bytesSize); >+ >+ size_t offsetInBytes = 0; >+ while (true) { >+ switch (m_state) { >+ case State::ModuleHeader: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, moduleHeaderSize); >+ if (!result) >+ return m_state; >+ m_state = parseModuleHeader(WTFMove(*result)); >+ break; >+ } >+ >+ case State::SectionHeader: { >+ auto result = consume(bytes, bytesSize, offsetInBytes, sectionHeaderSize); >+ if (!result) >+ return m_state; >+ m_state = parseSectionHeader(WTFMove(*result)); >+ break; >+ } >+ >+ case State::SectionSize: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ if (result.error() == State::FatalError) >+ m_state = failOnState(m_state); >+ else >+ 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) >+ return m_state; >+ m_state = parseSectionBody(WTFMove(*result)); >+ break; >+ } >+ >+ case State::CodeSectionSize: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ if (result.error() == State::FatalError) >+ m_state = failOnState(m_state); >+ else >+ m_state = result.error(); >+ return m_state; >+ } >+ m_state = parseCodeSectionSize(*result); >+ break; >+ } >+ >+ case State::FunctionHeader: { >+ auto result = consumeVarUInt32(bytes, bytesSize, offsetInBytes, isEndOfStream); >+ if (!result) { >+ if (result.error() == State::FatalError) >+ m_state = failOnState(m_state); >+ else >+ 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) >+ return m_state; >+ m_state = parseFunctionBody(WTFMove(*result)); >+ break; >+ } >+ >+ case State::Finished: >+ case State::FatalError: >+ return m_state; >+ } >+ >+ m_offset = m_nextOffset; >+ } >+} >+ >+auto StreamingParser::failOnState(State) -> State >+{ >+ switch (m_state) { >+ case State::ModuleHeader: >+ return fail("expected a module of at least ", moduleHeaderSize, " bytes"); >+ case State::SectionHeader: >+ return fail("can't get section byte"); >+ case State::SectionSize: >+ return fail("can't get ", m_section, " section's length"); >+ case State::SectionBody: >+ return fail(m_section, " section of size ", m_sectionLength, " would overflow Module's size"); >+ case State::CodeSectionSize: >+ return fail("can't get Code section's count"); >+ case State::FunctionHeader: >+ return fail("can't get ", m_functionIndex, "th Code function's size"); >+ case State::FunctionBody: >+ return fail("Code function's size ", m_functionSize, " exceeds the module's remaining size"); >+ case State::Finished: >+ case State::FatalError: >+ return m_state; >+ } >+ return m_state; >+} >+ >+auto StreamingParser::finalize() -> State >+{ >+ addBytes(nullptr, 0, IsEndOfStream::Yes); >+ switch (m_state) { >+ case State::ModuleHeader: >+ case State::SectionSize: >+ case State::SectionBody: >+ case State::CodeSectionSize: >+ case State::FunctionHeader: >+ case State::FunctionBody: >+ m_state = failOnState(m_state); >+ break; >+ >+ case State::Finished: >+ case State::FatalError: >+ break; >+ >+ case State::SectionHeader: >+ if (m_remaining.size() == 0) { >+ if (Options::useEagerWebAssemblyModuleHashing()) >+ m_info->nameSection->setHash(m_hasher.computeHexDigest()); >+ m_state = State::Finished; >+ } else >+ m_state = failOnState(State::SectionHeader); >+ break; >+ } >+ 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..e0cd10773b2c07c9c52d5997296d0460c1768c04 >--- /dev/null >+++ b/Source/JavaScriptCore/wasm/WasmStreamingParser.h >@@ -0,0 +1,117 @@ >+/* >+ * 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 "WasmParser.h" >+#include "WasmSections.h" >+#include <wtf/Expected.h> >+#include <wtf/Optional.h> >+#include <wtf/SHA1.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(); >+ >+ const String& errorMessage() const { return m_errorMessage; } >+ >+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>&&); >+ >+ std::optional<Vector<uint8_t>> 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); >+ >+ template <typename ...Args> NEVER_INLINE State WARN_UNUSED_RETURN fail(Args...); >+ >+ State failOnState(State); >+ >+ Ref<ModuleInformation> m_info; >+ Vector<uint8_t> m_remaining; >+ String m_errorMessage; >+ >+ CheckedSize m_totalSize { 0 }; >+ size_t m_offset { 0 }; >+ size_t m_nextOffset { 0 }; >+ size_t m_codeOffset { 0 }; >+ >+ SHA1 m_hasher; >+ >+ 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/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp >index 23fef22e58bee1efcc029bb768e05226a92036be..aebce0c4108391d61f1a92cdf25906d4e1ba824b 100644 >--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp >+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp >@@ -140,11 +140,6 @@ void JSWebAssemblyModule::visitChildren(JSCell* cell, SlotVisitor& visitor) > visitor.append(thisObject->m_codeBlocks[i]); > } > >-const Vector<uint8_t>& JSWebAssemblyModule::source() const >-{ >- return moduleInformation().source; >-} >- > } // namespace JSC > > #endif // ENABLE(WEBASSEMBLY) >diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h >index 17bed6125f4e7f319a8b7af2e1ddf864aeb2fa5a..d393006919d27ad17469fe2695db8438423d082e 100644 >--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h >+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h >@@ -68,8 +68,6 @@ class JSWebAssemblyModule final : public JSDestructibleObject { > JSWebAssemblyCodeBlock* codeBlock(Wasm::MemoryMode mode); > void setCodeBlock(VM&, Wasm::MemoryMode, JSWebAssemblyCodeBlock*); > >- const Vector<uint8_t>& source() const; >- > JS_EXPORT_PRIVATE Wasm::Module& module(); > > private: >diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp >index 96d4c14d74c7ee1af8aee7610c494aa7c94b06c5..dcadc0d0dbce5a9d2553a4dbdc8ce4b4fcc5d450 100644 >--- a/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp >+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp >@@ -294,10 +294,10 @@ static EncodedJSValue JSC_HOST_CALL webAssemblyValidateFunc(ExecState* exec) > size_t byteSize; > std::tie(base, byteSize) = getWasmBufferFromValue(exec, exec->argument(0)); > RETURN_IF_EXCEPTION(scope, encodedJSValue()); >- BBQPlan plan(&vm.wasmContext, base, byteSize, BBQPlan::Validation, Plan::dontFinalize()); >+ BBQPlan plan(&vm.wasmContext, BBQPlan::Validation, Plan::dontFinalize()); > // FIXME: We might want to throw an OOM exception here if we detect that something will OOM. > // https://bugs.webkit.org/show_bug.cgi?id=166015 >- return JSValue::encode(jsBoolean(plan.parseAndValidateModule())); >+ return JSValue::encode(jsBoolean(plan.parseAndValidateModule(base, byteSize))); > } > > EncodedJSValue JSC_HOST_CALL webAssemblyCompileStreamingInternal(ExecState* exec) >diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index 47100db70704f0d466468f84a6731f6429aba34e..94203818b4064f135fd645d29496b24e67bdac25 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,42 @@ >+2018-08-27 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 parsing error should not report the total byte size since streaming parsing does not >+ want to load all the bytes. >+ Add a simple test wasm/stress/streaming-basic.js for initial streaming parsing implementation. >+ >+ * 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: >+ * wasm/stress/nameSection.wasm: Added. >+ * wasm/stress/streaming-basic.js: Added. >+ (check): >+ > 2018-08-24 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > [JSC] Array.prototype.reverse modifies JSImmutableButterfly >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`); > } >diff --git a/JSTests/wasm/stress/nameSection.wasm b/JSTests/wasm/stress/nameSection.wasm >new file mode 100644 >index 0000000000000000000000000000000000000000..24b22b1aeea38e469c3260ba34d5da4a6db12153 >GIT binary patch >literal 13409 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 >J5Z`?Ke*s81TjBr! > >literal 0 >HcmV?d00001 > >diff --git a/JSTests/wasm/stress/streaming-basic.js b/JSTests/wasm/stress/streaming-basic.js >new file mode 100644 >index 0000000000000000000000000000000000000000..b3fbc2479f72163dfad32104056ba274359235da >--- /dev/null >+++ b/JSTests/wasm/stress/streaming-basic.js >@@ -0,0 +1,18 @@ >+import * as assert from '../assert.js'; >+ >+var data = read("./nameSection.wasm", "binary"); >+ >+function check(step) >+{ >+ var parser = $vm.createWasmStreamingParser(); >+ for (var i = 0; i < data.byteLength; i += step) { >+ parser.addBytes(data.subarray(i, i + Math.min(step, data.byteLength - i))); >+ } >+ assert.eq(parser.finalize(), 7); >+} >+ >+for (var i = 0; i < 10; ++i) >+ check(i + 1); >+check(100); >+check(1000); >+check(2000);
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