[WebAssembly] Validate and generate bytecode in one pass
authortzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Dec 2019 04:41:51 +0000 (04:41 +0000)
committertzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Dec 2019 04:41:51 +0000 (04:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204474

Reviewed by Saam Barati.

Currently, we traverse the WebAssembly code twice:
- a first serial pass that validates all functions
- a second concurrent pass that compiles all functions.
In this patch, we move the validation into the parser and update the LLIntPlan so that we no longer have
the first pass. Instead, we now validate concurrently at the same time we generate bytecode.

As a result, when we call WebAssembly.validate, we'll still generate bytecode for the module, but it will
be thrown away. If the module is constructed with new WebAssembly.Module, we'll also eagerly generate
bytecode, but in this case the bytecode is kept and shared across all instantiations of this module.

This is a 1.5x speedup when compiling the ZenGarden demo.

* DerivedSources.make:
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::ControlData::ControlData):
(JSC::Wasm::AirIRGenerator::ControlData::isIf):
(JSC::Wasm::AirIRGenerator::ControlData::isTopLevel):
(JSC::Wasm::AirIRGenerator::ControlData::branchTargetArity const):
(JSC::Wasm::AirIRGenerator::ControlData::branchTargetType const):
(JSC::Wasm::AirIRGenerator::emptyExpression):
(JSC::Wasm::AirIRGenerator::emitCallPatchpoint):
(JSC::Wasm::AirIRGenerator::tmpsForSignature):
(JSC::Wasm::AirIRGenerator::emitPatchpoint):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addRefIsNull):
(JSC::Wasm::AirIRGenerator::addTableGet):
(JSC::Wasm::AirIRGenerator::addTableSet):
(JSC::Wasm::AirIRGenerator::addTableGrow):
(JSC::Wasm::AirIRGenerator::addTableFill):
(JSC::Wasm::AirIRGenerator::emitLoopTierUpCheck):
(JSC::Wasm::AirIRGenerator::addLoop):
(JSC::Wasm::AirIRGenerator::addBlock):
(JSC::Wasm::AirIRGenerator::addIf):
(JSC::Wasm::AirIRGenerator::addReturn):
(JSC::Wasm::AirIRGenerator::addEndToUnreachable):
(JSC::Wasm::AirIRGenerator::addCall):
(JSC::Wasm::AirIRGenerator::addCallIndirect):
(JSC::Wasm::AirIRGenerator::unify):
(JSC::Wasm::dumpExpressionStack):
(JSC::Wasm::AirIRGenerator::dump):
(JSC::Wasm::parseAndCompileAir):
(JSC::Wasm::AirIRGenerator::addOp<OpType::I64TruncUF64>):
(JSC::Wasm::AirIRGenerator::addOp<OpType::I64TruncUF32>):
* wasm/WasmAirIRGenerator.h:
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::ControlData::ControlData):
(JSC::Wasm::B3IRGenerator::ControlData::isIf):
(JSC::Wasm::B3IRGenerator::ControlData::isTopLevel):
(JSC::Wasm::B3IRGenerator::ControlData::signature const):
(JSC::Wasm::B3IRGenerator::ControlData::hasNonVoidresult const):
(JSC::Wasm::B3IRGenerator::ControlData::branchTargetArity const):
(JSC::Wasm::B3IRGenerator::ControlData::branchTargetType const):
(JSC::Wasm::B3IRGenerator::emptyExpression):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::addRefIsNull):
(JSC::Wasm::B3IRGenerator::addTableGet):
(JSC::Wasm::B3IRGenerator::addTableSet):
(JSC::Wasm::B3IRGenerator::addTableGrow):
(JSC::Wasm::B3IRGenerator::addTableFill):
(JSC::Wasm::B3IRGenerator::emitLoopTierUpCheck):
(JSC::Wasm::B3IRGenerator::addLoop):
(JSC::Wasm::B3IRGenerator::addBlock):
(JSC::Wasm::B3IRGenerator::addIf):
(JSC::Wasm::B3IRGenerator::addReturn):
(JSC::Wasm::B3IRGenerator::endBlock):
(JSC::Wasm::B3IRGenerator::addEndToUnreachable):
(JSC::Wasm::dumpExpressionStack):
(JSC::Wasm::B3IRGenerator::dump):
(JSC::Wasm::parseAndCompile):
* wasm/WasmB3IRGenerator.h:
* wasm/WasmBBQPlan.cpp:
(JSC::Wasm::BBQPlan::BBQPlan):
(JSC::Wasm::BBQPlan::work):
(JSC::Wasm::BBQPlan::compileFunction):
(JSC::Wasm::BBQPlan::initializeCallees):
(JSC::Wasm::BBQPlan::didReceiveFunctionData):
* wasm/WasmBBQPlan.h:
* wasm/WasmCodeBlock.cpp:
(JSC::Wasm::CodeBlock::create):
(JSC::Wasm::CodeBlock::CodeBlock):
* wasm/WasmCodeBlock.h:
(JSC::Wasm::CodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
* wasm/WasmEntryPlan.cpp:
(JSC::Wasm::EntryPlan::EntryPlan):
(JSC::Wasm::EntryPlan::parseAndValidateModule):
(JSC::Wasm::EntryPlan::prepare):
(JSC::Wasm::EntryPlan::compileFunctions):
(JSC::Wasm::EntryPlan::complete):
* wasm/WasmEntryPlan.h:
* wasm/WasmFunctionParser.h:
(JSC::Wasm::splitStack):
(JSC::Wasm::FunctionParser::TypedExpression::TypedExpression):
(JSC::Wasm::FunctionParser::TypedExpression::type const):
(JSC::Wasm::FunctionParser::TypedExpression::value const):
(JSC::Wasm::FunctionParser::TypedExpression::operator ExpressionType const):
(JSC::Wasm::FunctionParser::TypedExpression::operator-> const):
(JSC::Wasm::FunctionParser::controlStack):
(JSC::Wasm::FunctionParser::validationFail const):
(JSC::Wasm::FunctionParser<Context>::parse):
(JSC::Wasm::FunctionParser<Context>::binaryCase):
(JSC::Wasm::FunctionParser<Context>::unaryCase):
(JSC::Wasm::FunctionParser<Context>::load):
(JSC::Wasm::FunctionParser<Context>::store):
(JSC::Wasm::FunctionParser<Context>::checkBranchTarget):
(JSC::Wasm::FunctionParser<Context>::unify):
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::ControlType::topLevel):
(JSC::Wasm::LLIntGenerator::ControlType::loop):
(JSC::Wasm::LLIntGenerator::ControlType::isIf):
(JSC::Wasm::LLIntGenerator::ControlType::isTopLevel):
(JSC::Wasm::LLIntGenerator::ControlType::stackSize const):
(JSC::Wasm::LLIntGenerator::ControlType::signature const):
(JSC::Wasm::LLIntGenerator::ControlType::branchTargetArity const):
(JSC::Wasm::LLIntGenerator::ControlType::branchTargetType const):
(JSC::Wasm::LLIntGenerator::emptyExpression):
(JSC::Wasm::LLIntGenerator::dump):
(JSC::Wasm::LLIntGenerator::getDropKeepCount):
(JSC::Wasm::LLIntGenerator::materializeConstantsAndLocals):
(JSC::Wasm::LLIntGenerator::splitStack):
(JSC::Wasm::parseAndCompileBytecode):
(JSC::Wasm::LLIntGenerator::LLIntGenerator):
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::addLocal):
(JSC::Wasm::LLIntGenerator::setLocal):
(JSC::Wasm::LLIntGenerator::addLoop):
(JSC::Wasm::LLIntGenerator::addBlock):
(JSC::Wasm::LLIntGenerator::addIf):
(JSC::Wasm::LLIntGenerator::addEndToUnreachable):
(JSC::Wasm::LLIntGenerator::addCall):
(JSC::Wasm::LLIntGenerator::addCallIndirect):
* wasm/WasmLLIntGenerator.h:
* wasm/WasmLLIntPlan.cpp:
(JSC::Wasm::LLIntPlan::LLIntPlan):
(JSC::Wasm::LLIntPlan::compileFunction):
(JSC::Wasm::LLIntPlan::didCompleteCompilation):
(JSC::Wasm::LLIntPlan::work):
(JSC::Wasm::LLIntPlan::didReceiveFunctionData):
* wasm/WasmLLIntPlan.h:
* wasm/WasmModule.cpp:
(JSC::Wasm::Module::Module):
(JSC::Wasm::makeValidationResult):
(JSC::Wasm::makeValidationCallback):
(JSC::Wasm::Module::validateSync):
(JSC::Wasm::Module::validateAsync):
(JSC::Wasm::Module::getOrCreateCodeBlock):
(JSC::Wasm::Module::compileSync):
(JSC::Wasm::Module::compileAsync):
* wasm/WasmModule.h:
(JSC::Wasm::Module::create):
* wasm/WasmOMGPlan.cpp:
(JSC::Wasm::OMGPlan::work):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::Plan):
* wasm/WasmPlan.h:
(JSC::Wasm::Plan::dontFinalize):
* wasm/WasmSlowPaths.cpp:
(JSC::LLInt::slow_path_wasm_throw_exception):
* wasm/WasmThunks.cpp:
(JSC::Wasm::throwExceptionFromWasmThunkGenerator):
* wasm/WasmThunks.h:
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::ControlData::isIf):
(JSC::Wasm::Validate::ControlData::isTopLevel):
(JSC::Wasm::Validate::ControlData::blockType const):
(JSC::Wasm::Validate::ControlData::signature const):
(JSC::Wasm::Validate::ControlData::branchTargetArity const):
(JSC::Wasm::Validate::ControlData::branchTargetType const):
(JSC::Wasm::Validate::emptyExpression):
(JSC::Wasm::Validate::addConstant):
(JSC::Wasm::Validate::Validate):
(JSC::Wasm::Validate::addArguments):
(JSC::Wasm::Validate::addTableGet):
(JSC::Wasm::Validate::addTableSet):
(JSC::Wasm::Validate::addTableSize):
(JSC::Wasm::Validate::addTableGrow):
(JSC::Wasm::Validate::addTableFill):
(JSC::Wasm::Validate::addRefIsNull):
(JSC::Wasm::Validate::addRefFunc):
(JSC::Wasm::Validate::addLocal):
(JSC::Wasm::Validate::getLocal):
(JSC::Wasm::Validate::setLocal):
(JSC::Wasm::Validate::getGlobal):
(JSC::Wasm::Validate::setGlobal):
(JSC::Wasm::Validate::addBlock):
(JSC::Wasm::Validate::addLoop):
(JSC::Wasm::Validate::addSelect):
(JSC::Wasm::Validate::addIf):
(JSC::Wasm::Validate::addElse):
(JSC::Wasm::Validate::addElseToUnreachable):
(JSC::Wasm::Validate::addReturn):
(JSC::Wasm::Validate::addBranch):
(JSC::Wasm::Validate::addSwitch):
(JSC::Wasm::Validate::addGrowMemory):
(JSC::Wasm::Validate::addCurrentMemory):
(JSC::Wasm::Validate::endBlock):
(JSC::Wasm::Validate::addEndToUnreachable):
(JSC::Wasm::Validate::addCall):
(JSC::Wasm::Validate::addCallIndirect):
(JSC::Wasm::Validate::load):
(JSC::Wasm::Validate::store):
(JSC::Wasm::Validate::addOp):
(JSC::Wasm::dumpExpressionStack):
(JSC::Wasm::Validate::dump):
(JSC::Wasm::validateFunction):
* wasm/WasmWorklist.cpp:
(JSC::Wasm::Worklist::enqueue):
* wasm/generateWasmOpsHeader.py:
(cppType):
(cppMacro):
(opcodeMacroizer):
(opcodeWithTypesMacroizer):
(opcodeWithTypesMacroizer.modifier):
(memoryLoadMacroizer):
(memoryLoadMacroizer.modifier):
(memoryStoreMacroizer):
(memoryStoreMacroizer.modifier):
* wasm/generateWasmValidateInlinesHeader.py: Removed.
* wasm/js/JSWebAssembly.cpp:
(JSC::instantiate):
(JSC::webAssemblyValidateFunc):
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@253140 268f45cc-cd09-0410-ab3c-d52691b4dbfc

34 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/DerivedSources-input.xcfilelist
Source/JavaScriptCore/DerivedSources-output.xcfilelist
Source/JavaScriptCore/DerivedSources.make
Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
Source/JavaScriptCore/wasm/WasmAirIRGenerator.h
Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
Source/JavaScriptCore/wasm/WasmBBQPlan.h
Source/JavaScriptCore/wasm/WasmCodeBlock.cpp
Source/JavaScriptCore/wasm/WasmCodeBlock.h
Source/JavaScriptCore/wasm/WasmEntryPlan.cpp
Source/JavaScriptCore/wasm/WasmEntryPlan.h
Source/JavaScriptCore/wasm/WasmFunctionParser.h
Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp
Source/JavaScriptCore/wasm/WasmLLIntGenerator.h
Source/JavaScriptCore/wasm/WasmLLIntPlan.cpp
Source/JavaScriptCore/wasm/WasmLLIntPlan.h
Source/JavaScriptCore/wasm/WasmModule.cpp
Source/JavaScriptCore/wasm/WasmModule.h
Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
Source/JavaScriptCore/wasm/WasmPlan.cpp
Source/JavaScriptCore/wasm/WasmPlan.h
Source/JavaScriptCore/wasm/WasmSlowPaths.cpp
Source/JavaScriptCore/wasm/WasmThunks.cpp
Source/JavaScriptCore/wasm/WasmThunks.h
Source/JavaScriptCore/wasm/WasmValidate.cpp
Source/JavaScriptCore/wasm/WasmWorklist.cpp
Source/JavaScriptCore/wasm/generateWasmOpsHeader.py
Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py [deleted file]
Source/JavaScriptCore/wasm/js/JSWebAssembly.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

index 5c9032e..c9a82a7 100644 (file)
@@ -366,7 +366,6 @@ macro(GENERATE_PYTHON _generator _additional_deps _input _output)
     WEBKIT_ADD_SOURCE_DEPENDENCIES(${_input} ${_output})
 endmacro()
 GENERATE_PYTHON(${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasmOpsHeader.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasm.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/wasm.json ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmOps.h)
-GENERATE_PYTHON(${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasmValidateInlinesHeader.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasm.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/wasm.json ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmValidateInlines.h)
 GENERATE_PYTHON(${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasmB3IRGeneratorInlinesHeader.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/generateWasm.py ${CMAKE_CURRENT_SOURCE_DIR}/wasm/wasm.json ${JavaScriptCore_DERIVED_SOURCES_DIR}/WasmB3IRGeneratorInlines.h)
 
 # LUT generator
index 2aa9f5a..c365963 100644 (file)
@@ -1,3 +1,235 @@
+2019-12-04  Tadeu Zagallo  <tzagallo@apple.com>
+
+        [WebAssembly] Validate and generate bytecode in one pass
+        https://bugs.webkit.org/show_bug.cgi?id=204474
+
+        Reviewed by Saam Barati.
+
+        Currently, we traverse the WebAssembly code twice:
+        - a first serial pass that validates all functions
+        - a second concurrent pass that compiles all functions.
+        In this patch, we move the validation into the parser and update the LLIntPlan so that we no longer have
+        the first pass. Instead, we now validate concurrently at the same time we generate bytecode.
+
+        As a result, when we call WebAssembly.validate, we'll still generate bytecode for the module, but it will
+        be thrown away. If the module is constructed with new WebAssembly.Module, we'll also eagerly generate
+        bytecode, but in this case the bytecode is kept and shared across all instantiations of this module.
+
+        This is a 1.5x speedup when compiling the ZenGarden demo.
+
+        * DerivedSources.make:
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::ControlData::ControlData):
+        (JSC::Wasm::AirIRGenerator::ControlData::isIf):
+        (JSC::Wasm::AirIRGenerator::ControlData::isTopLevel):
+        (JSC::Wasm::AirIRGenerator::ControlData::branchTargetArity const):
+        (JSC::Wasm::AirIRGenerator::ControlData::branchTargetType const):
+        (JSC::Wasm::AirIRGenerator::emptyExpression):
+        (JSC::Wasm::AirIRGenerator::emitCallPatchpoint):
+        (JSC::Wasm::AirIRGenerator::tmpsForSignature):
+        (JSC::Wasm::AirIRGenerator::emitPatchpoint):
+        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+        (JSC::Wasm::AirIRGenerator::addRefIsNull):
+        (JSC::Wasm::AirIRGenerator::addTableGet):
+        (JSC::Wasm::AirIRGenerator::addTableSet):
+        (JSC::Wasm::AirIRGenerator::addTableGrow):
+        (JSC::Wasm::AirIRGenerator::addTableFill):
+        (JSC::Wasm::AirIRGenerator::emitLoopTierUpCheck):
+        (JSC::Wasm::AirIRGenerator::addLoop):
+        (JSC::Wasm::AirIRGenerator::addBlock):
+        (JSC::Wasm::AirIRGenerator::addIf):
+        (JSC::Wasm::AirIRGenerator::addReturn):
+        (JSC::Wasm::AirIRGenerator::addEndToUnreachable):
+        (JSC::Wasm::AirIRGenerator::addCall):
+        (JSC::Wasm::AirIRGenerator::addCallIndirect):
+        (JSC::Wasm::AirIRGenerator::unify):
+        (JSC::Wasm::dumpExpressionStack):
+        (JSC::Wasm::AirIRGenerator::dump):
+        (JSC::Wasm::parseAndCompileAir):
+        (JSC::Wasm::AirIRGenerator::addOp<OpType::I64TruncUF64>):
+        (JSC::Wasm::AirIRGenerator::addOp<OpType::I64TruncUF32>):
+        * wasm/WasmAirIRGenerator.h:
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::ControlData::ControlData):
+        (JSC::Wasm::B3IRGenerator::ControlData::isIf):
+        (JSC::Wasm::B3IRGenerator::ControlData::isTopLevel):
+        (JSC::Wasm::B3IRGenerator::ControlData::signature const):
+        (JSC::Wasm::B3IRGenerator::ControlData::hasNonVoidresult const):
+        (JSC::Wasm::B3IRGenerator::ControlData::branchTargetArity const):
+        (JSC::Wasm::B3IRGenerator::ControlData::branchTargetType const):
+        (JSC::Wasm::B3IRGenerator::emptyExpression):
+        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+        (JSC::Wasm::B3IRGenerator::addRefIsNull):
+        (JSC::Wasm::B3IRGenerator::addTableGet):
+        (JSC::Wasm::B3IRGenerator::addTableSet):
+        (JSC::Wasm::B3IRGenerator::addTableGrow):
+        (JSC::Wasm::B3IRGenerator::addTableFill):
+        (JSC::Wasm::B3IRGenerator::emitLoopTierUpCheck):
+        (JSC::Wasm::B3IRGenerator::addLoop):
+        (JSC::Wasm::B3IRGenerator::addBlock):
+        (JSC::Wasm::B3IRGenerator::addIf):
+        (JSC::Wasm::B3IRGenerator::addReturn):
+        (JSC::Wasm::B3IRGenerator::endBlock):
+        (JSC::Wasm::B3IRGenerator::addEndToUnreachable):
+        (JSC::Wasm::dumpExpressionStack):
+        (JSC::Wasm::B3IRGenerator::dump):
+        (JSC::Wasm::parseAndCompile):
+        * wasm/WasmB3IRGenerator.h:
+        * wasm/WasmBBQPlan.cpp:
+        (JSC::Wasm::BBQPlan::BBQPlan):
+        (JSC::Wasm::BBQPlan::work):
+        (JSC::Wasm::BBQPlan::compileFunction):
+        (JSC::Wasm::BBQPlan::initializeCallees):
+        (JSC::Wasm::BBQPlan::didReceiveFunctionData):
+        * wasm/WasmBBQPlan.h:
+        * wasm/WasmCodeBlock.cpp:
+        (JSC::Wasm::CodeBlock::create):
+        (JSC::Wasm::CodeBlock::CodeBlock):
+        * wasm/WasmCodeBlock.h:
+        (JSC::Wasm::CodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
+        * wasm/WasmEntryPlan.cpp:
+        (JSC::Wasm::EntryPlan::EntryPlan):
+        (JSC::Wasm::EntryPlan::parseAndValidateModule):
+        (JSC::Wasm::EntryPlan::prepare):
+        (JSC::Wasm::EntryPlan::compileFunctions):
+        (JSC::Wasm::EntryPlan::complete):
+        * wasm/WasmEntryPlan.h:
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::splitStack):
+        (JSC::Wasm::FunctionParser::TypedExpression::TypedExpression):
+        (JSC::Wasm::FunctionParser::TypedExpression::type const):
+        (JSC::Wasm::FunctionParser::TypedExpression::value const):
+        (JSC::Wasm::FunctionParser::TypedExpression::operator ExpressionType const):
+        (JSC::Wasm::FunctionParser::TypedExpression::operator-> const):
+        (JSC::Wasm::FunctionParser::controlStack):
+        (JSC::Wasm::FunctionParser::validationFail const):
+        (JSC::Wasm::FunctionParser<Context>::parse):
+        (JSC::Wasm::FunctionParser<Context>::binaryCase):
+        (JSC::Wasm::FunctionParser<Context>::unaryCase):
+        (JSC::Wasm::FunctionParser<Context>::load):
+        (JSC::Wasm::FunctionParser<Context>::store):
+        (JSC::Wasm::FunctionParser<Context>::checkBranchTarget):
+        (JSC::Wasm::FunctionParser<Context>::unify):
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+        * wasm/WasmLLIntGenerator.cpp:
+        (JSC::Wasm::LLIntGenerator::ControlType::topLevel):
+        (JSC::Wasm::LLIntGenerator::ControlType::loop):
+        (JSC::Wasm::LLIntGenerator::ControlType::isIf):
+        (JSC::Wasm::LLIntGenerator::ControlType::isTopLevel):
+        (JSC::Wasm::LLIntGenerator::ControlType::stackSize const):
+        (JSC::Wasm::LLIntGenerator::ControlType::signature const):
+        (JSC::Wasm::LLIntGenerator::ControlType::branchTargetArity const):
+        (JSC::Wasm::LLIntGenerator::ControlType::branchTargetType const):
+        (JSC::Wasm::LLIntGenerator::emptyExpression):
+        (JSC::Wasm::LLIntGenerator::dump):
+        (JSC::Wasm::LLIntGenerator::getDropKeepCount):
+        (JSC::Wasm::LLIntGenerator::materializeConstantsAndLocals):
+        (JSC::Wasm::LLIntGenerator::splitStack):
+        (JSC::Wasm::parseAndCompileBytecode):
+        (JSC::Wasm::LLIntGenerator::LLIntGenerator):
+        (JSC::Wasm::LLIntGenerator::callInformationForCaller):
+        (JSC::Wasm::LLIntGenerator::addLocal):
+        (JSC::Wasm::LLIntGenerator::setLocal):
+        (JSC::Wasm::LLIntGenerator::addLoop):
+        (JSC::Wasm::LLIntGenerator::addBlock):
+        (JSC::Wasm::LLIntGenerator::addIf):
+        (JSC::Wasm::LLIntGenerator::addEndToUnreachable):
+        (JSC::Wasm::LLIntGenerator::addCall):
+        (JSC::Wasm::LLIntGenerator::addCallIndirect):
+        * wasm/WasmLLIntGenerator.h:
+        * wasm/WasmLLIntPlan.cpp:
+        (JSC::Wasm::LLIntPlan::LLIntPlan):
+        (JSC::Wasm::LLIntPlan::compileFunction):
+        (JSC::Wasm::LLIntPlan::didCompleteCompilation):
+        (JSC::Wasm::LLIntPlan::work):
+        (JSC::Wasm::LLIntPlan::didReceiveFunctionData):
+        * wasm/WasmLLIntPlan.h:
+        * wasm/WasmModule.cpp:
+        (JSC::Wasm::Module::Module):
+        (JSC::Wasm::makeValidationResult):
+        (JSC::Wasm::makeValidationCallback):
+        (JSC::Wasm::Module::validateSync):
+        (JSC::Wasm::Module::validateAsync):
+        (JSC::Wasm::Module::getOrCreateCodeBlock):
+        (JSC::Wasm::Module::compileSync):
+        (JSC::Wasm::Module::compileAsync):
+        * wasm/WasmModule.h:
+        (JSC::Wasm::Module::create):
+        * wasm/WasmOMGPlan.cpp:
+        (JSC::Wasm::OMGPlan::work):
+        * wasm/WasmPlan.cpp:
+        (JSC::Wasm::Plan::Plan):
+        * wasm/WasmPlan.h:
+        (JSC::Wasm::Plan::dontFinalize):
+        * wasm/WasmSlowPaths.cpp:
+        (JSC::LLInt::slow_path_wasm_throw_exception):
+        * wasm/WasmThunks.cpp:
+        (JSC::Wasm::throwExceptionFromWasmThunkGenerator):
+        * wasm/WasmThunks.h:
+        * wasm/WasmValidate.cpp:
+        (JSC::Wasm::Validate::ControlData::isIf):
+        (JSC::Wasm::Validate::ControlData::isTopLevel):
+        (JSC::Wasm::Validate::ControlData::blockType const):
+        (JSC::Wasm::Validate::ControlData::signature const):
+        (JSC::Wasm::Validate::ControlData::branchTargetArity const):
+        (JSC::Wasm::Validate::ControlData::branchTargetType const):
+        (JSC::Wasm::Validate::emptyExpression):
+        (JSC::Wasm::Validate::addConstant):
+        (JSC::Wasm::Validate::Validate):
+        (JSC::Wasm::Validate::addArguments):
+        (JSC::Wasm::Validate::addTableGet):
+        (JSC::Wasm::Validate::addTableSet):
+        (JSC::Wasm::Validate::addTableSize):
+        (JSC::Wasm::Validate::addTableGrow):
+        (JSC::Wasm::Validate::addTableFill):
+        (JSC::Wasm::Validate::addRefIsNull):
+        (JSC::Wasm::Validate::addRefFunc):
+        (JSC::Wasm::Validate::addLocal):
+        (JSC::Wasm::Validate::getLocal):
+        (JSC::Wasm::Validate::setLocal):
+        (JSC::Wasm::Validate::getGlobal):
+        (JSC::Wasm::Validate::setGlobal):
+        (JSC::Wasm::Validate::addBlock):
+        (JSC::Wasm::Validate::addLoop):
+        (JSC::Wasm::Validate::addSelect):
+        (JSC::Wasm::Validate::addIf):
+        (JSC::Wasm::Validate::addElse):
+        (JSC::Wasm::Validate::addElseToUnreachable):
+        (JSC::Wasm::Validate::addReturn):
+        (JSC::Wasm::Validate::addBranch):
+        (JSC::Wasm::Validate::addSwitch):
+        (JSC::Wasm::Validate::addGrowMemory):
+        (JSC::Wasm::Validate::addCurrentMemory):
+        (JSC::Wasm::Validate::endBlock):
+        (JSC::Wasm::Validate::addEndToUnreachable):
+        (JSC::Wasm::Validate::addCall):
+        (JSC::Wasm::Validate::addCallIndirect):
+        (JSC::Wasm::Validate::load):
+        (JSC::Wasm::Validate::store):
+        (JSC::Wasm::Validate::addOp):
+        (JSC::Wasm::dumpExpressionStack):
+        (JSC::Wasm::Validate::dump):
+        (JSC::Wasm::validateFunction):
+        * wasm/WasmWorklist.cpp:
+        (JSC::Wasm::Worklist::enqueue):
+        * wasm/generateWasmOpsHeader.py:
+        (cppType):
+        (cppMacro):
+        (opcodeMacroizer):
+        (opcodeWithTypesMacroizer):
+        (opcodeWithTypesMacroizer.modifier):
+        (memoryLoadMacroizer):
+        (memoryLoadMacroizer.modifier):
+        (memoryStoreMacroizer):
+        (memoryStoreMacroizer.modifier):
+        * wasm/generateWasmValidateInlinesHeader.py: Removed.
+        * wasm/js/JSWebAssembly.cpp:
+        (JSC::instantiate):
+        (JSC::webAssemblyValidateFunc):
+        * wasm/js/WebAssemblyInstanceConstructor.cpp:
+        (JSC::constructJSWebAssemblyInstance):
+
 2019-12-04  Mark Lam  <mark.lam@apple.com>
 
         Fix missing exception check in ArrayPrototype's fastJoin().
index e23c714..f8c1b4a 100644 (file)
@@ -173,7 +173,6 @@ $(PROJECT_DIR)/ucd/language-subtag-registry.txt
 $(PROJECT_DIR)/wasm/generateWasm.py
 $(PROJECT_DIR)/wasm/generateWasmB3IRGeneratorInlinesHeader.py
 $(PROJECT_DIR)/wasm/generateWasmOpsHeader.py
-$(PROJECT_DIR)/wasm/generateWasmValidateInlinesHeader.py
 $(PROJECT_DIR)/wasm/js/JSWebAssembly.cpp
 $(PROJECT_DIR)/wasm/js/WebAssemblyCompileErrorConstructor.cpp
 $(PROJECT_DIR)/wasm/js/WebAssemblyCompileErrorPrototype.cpp
index e3c1338..3d2e7dd 100644 (file)
@@ -60,7 +60,6 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/UnicodePatternTables.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WasmB3IRGeneratorInlines.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WasmLLIntGeneratorInlines.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WasmOps.h
-$(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WasmValidateInlines.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WebAssemblyCompileErrorConstructor.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WebAssemblyCompileErrorPrototype.lut.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/JavaScriptCore/WebAssemblyGlobalConstructor.lut.h
index 486026a..3866e2b 100644 (file)
@@ -60,7 +60,6 @@ all : \
     UnicodePatternTables.h \
     yarr/YarrCanonicalizeUnicode.cpp \
     WasmOps.h \
-    WasmValidateInlines.h \
     WasmB3IRGeneratorInlines.h \
 #
 
@@ -354,9 +353,6 @@ IntlCanonicalizeLanguage.h: $(JavaScriptCore)/Scripts/generateIntlCanonicalizeLa
 WasmOps.h: $(JavaScriptCore)/wasm/generateWasmOpsHeader.py $(JavaScriptCore)/wasm/generateWasm.py $(JavaScriptCore)/wasm/wasm.json
        $(PYTHON) $(JavaScriptCore)/wasm/generateWasmOpsHeader.py $(JavaScriptCore)/wasm/wasm.json ./WasmOps.h
 
-WasmValidateInlines.h: $(JavaScriptCore)/wasm/generateWasmValidateInlinesHeader.py $(JavaScriptCore)/wasm/generateWasm.py $(JavaScriptCore)/wasm/wasm.json
-       $(PYTHON) $(JavaScriptCore)/wasm/generateWasmValidateInlinesHeader.py $(JavaScriptCore)/wasm/wasm.json ./WasmValidateInlines.h
-
 WasmB3IRGeneratorInlines.h: $(JavaScriptCore)/wasm/generateWasmB3IRGeneratorInlinesHeader.py $(JavaScriptCore)/wasm/generateWasm.py $(JavaScriptCore)/wasm/wasm.json
        $(PYTHON) $(JavaScriptCore)/wasm/generateWasmB3IRGeneratorInlinesHeader.py $(JavaScriptCore)/wasm/wasm.json ./WasmB3IRGeneratorInlines.h
 
index e453260..258812a 100644 (file)
@@ -129,12 +129,13 @@ private:
     Type m_type;
 };
 
-using TypedTmps = Vector<TypedTmp, 1>;
-
 class AirIRGenerator {
 public:
+    using ExpressionType = TypedTmp;
+    using ResultList = Vector<ExpressionType, 8>;
+
     struct ControlData {
-        ControlData(B3::Origin origin, BlockSignature result, TypedTmps resultTmps, BlockType type, BasicBlock* continuation, BasicBlock* special = nullptr)
+        ControlData(B3::Origin origin, BlockSignature result, ResultList resultTmps, BlockType type, BasicBlock* continuation, BasicBlock* special = nullptr)
             : controlBlockType(type)
             , continuation(continuation)
             , special(special)
@@ -148,6 +149,9 @@ public:
         {
         }
 
+        static bool isIf(const ControlData& control) { return control.blockType() == BlockType::If; }
+        static bool isTopLevel(const ControlData& control) { return control.blockType() == BlockType::TopLevel; }
+
         void dump(PrintStream& out) const
         {
             switch (blockType()) {
@@ -194,31 +198,46 @@ public:
             special = nullptr;
         }
 
+        SignatureArgCount branchTargetArity() const
+        {
+            if (blockType() == BlockType::Loop)
+                return returnType->argumentCount();
+            return returnType->returnCount();
+        }
+
+        Type branchTargetType(unsigned i) const
+        {
+            ASSERT(i < branchTargetArity());
+            if (blockType() == BlockType::Loop)
+                return returnType->argument(i);
+            return returnType->returnType(i);
+        }
+
     private:
         friend class AirIRGenerator;
         BlockType controlBlockType;
         BasicBlock* continuation;
         BasicBlock* special;
-        TypedTmps results;
+        ResultList results;
         BlockSignature returnType;
     };
 
-    using ExpressionType = TypedTmp;
     using ControlType = ControlData;
-    using ExpressionList = Vector<ExpressionType, 1>;
-    using Stack = ExpressionList;
-    using ResultList = TypedTmps;
-    using ControlEntry = FunctionParser<AirIRGenerator>::ControlEntry;
 
-    static ExpressionType emptyExpression() { return { }; };
-    Stack createStack() { return Stack(); }
-    bool isControlTypeIf(const ControlType& control) { return control.blockType() == BlockType::If; }
+    using ControlEntry = FunctionParser<AirIRGenerator>::ControlEntry;
+    using ControlStack = FunctionParser<AirIRGenerator>::ControlStack;
+    using Stack = FunctionParser<AirIRGenerator>::Stack;
+    using TypedExpression = FunctionParser<AirIRGenerator>::TypedExpression;
 
     using ErrorType = String;
     using UnexpectedResult = Unexpected<ErrorType>;
     using Result = Expected<std::unique_ptr<InternalFunction>, ErrorType>;
     using PartialResult = Expected<void, ErrorType>;
 
+    static_assert(std::is_same_v<ResultList, FunctionParser<AirIRGenerator>::ResultList>);
+
+    static ExpressionType emptyExpression() { return { }; };
+
     template <typename ...Args>
     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
     {
@@ -231,7 +250,7 @@ public:
             return fail(__VA_ARGS__);             \
     } while (0)
 
-    AirIRGenerator(const ModuleInformation&, B3::Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, unsigned functionIndex, TierUpCount*, ThrowWasmException, const Signature&);
+    AirIRGenerator(const ModuleInformation&, B3::Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, unsigned functionIndex, TierUpCount*, const Signature&);
 
     PartialResult WARN_UNUSED_RETURN addArguments(const Signature&);
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
@@ -240,15 +259,15 @@ public:
     ExpressionType addBottom(BasicBlock*, Type);
 
     // References
-    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType value, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
+    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value);
     PartialResult WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count);
+    PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count);
 
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -279,7 +298,7 @@ public:
     PartialResult WARN_UNUSED_RETURN addElse(ControlData&, const Stack&);
     PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
 
-    PartialResult WARN_UNUSED_RETURN addReturn(const ControlData&, const ExpressionList& returnValues);
+    PartialResult WARN_UNUSED_RETURN addReturn(const ControlData&, const Stack& returnValues);
     PartialResult WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const Stack& returnValues);
     PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const Stack& expressionStack);
     PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, Stack& expressionStack);
@@ -288,29 +307,21 @@ public:
     PartialResult WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&) { return { }; }
 
     // Calls
-    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, Vector<ExpressionType, 1>& results);
-    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, Vector<ExpressionType, 1>& results);
+    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
+    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
-    B3::PatchpointValue* WARN_UNUSED_RETURN emitCallPatchpoint(BasicBlock*, const Signature&, const Vector<ExpressionType, 1>& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&& extraArgs = { });
+    B3::PatchpointValue* WARN_UNUSED_RETURN emitCallPatchpoint(BasicBlock*, const Signature&, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&& extraArgs = { });
 
     PartialResult addShift(Type, B3::Air::Opcode, ExpressionType value, ExpressionType shift, ExpressionType& result);
     PartialResult addIntegerSub(B3::Air::Opcode, ExpressionType lhs, ExpressionType rhs, ExpressionType& result);
     PartialResult addFloatingPointAbs(B3::Air::Opcode, ExpressionType value, ExpressionType& result);
     PartialResult addFloatingPointBinOp(Type, B3::Air::Opcode, ExpressionType lhs, ExpressionType rhs, ExpressionType& result);
 
-    void dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack);
+    void dump(const ControlStack&, const Stack* expressionStack);
     void setParser(FunctionParser<AirIRGenerator>* parser) { m_parser = parser; };
     void didFinishParsingLocals() { }
     void didPopValueFromStack() { }
 
-    static Vector<Tmp> toTmpVector(const Vector<TypedTmp>& vector)
-    {
-        Vector<Tmp> result;
-        for (const auto& item : vector)
-            result.append(item.tmp());
-        return result;
-    }
-
     const Bag<B3::PatchpointValue*>& patchpoints() const
     {
         return m_patchpoints;
@@ -401,9 +412,9 @@ private:
         }
     }
 
-    TypedTmps tmpsForSignature(BlockSignature signature)
+    ResultList tmpsForSignature(BlockSignature signature)
     {
-        TypedTmps result(signature->returnCount());
+        ResultList result(signature->returnCount());
         for (unsigned i = 0; i < signature->returnCount(); ++i)
             result[i] = tmpForType(signature->returnType(i));
         return result;
@@ -426,16 +437,16 @@ private:
     template <typename ...Args>
     void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, Tmp result, Args... theArgs)
     {
-        emitPatchpoint(basicBlock, patch, Vector<Tmp, 1> { result }, Vector<ConstrainedTmp, sizeof...(Args)>::from(theArgs...));
+        emitPatchpoint(basicBlock, patch, Vector<Tmp, 8> { result }, Vector<ConstrainedTmp, sizeof...(Args)>::from(theArgs...));
     }
 
     void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, Tmp result)
     {
-        emitPatchpoint(basicBlock, patch, Vector<Tmp, 1> { result }, Vector<ConstrainedTmp>());
+        emitPatchpoint(basicBlock, patch, Vector<Tmp, 8> { result }, Vector<ConstrainedTmp>());
     }
 
     template <typename ResultTmpType, size_t inlineSize>
-    void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, const Vector<ResultTmpType, 1>&  results, Vector<ConstrainedTmp, inlineSize>&& args)
+    void emitPatchpoint(BasicBlock* basicBlock, B3::PatchpointValue* patch, const Vector<ResultTmpType, 8>&  results, Vector<ConstrainedTmp, inlineSize>&& args)
     {
         if (!m_patchpointSpecial)
             m_patchpointSpecial = static_cast<B3::PatchpointSpecial*>(m_code.addSpecial(makeUnique<B3::PatchpointSpecial>()));
@@ -633,7 +644,7 @@ private:
     ExpressionType emitLoadOp(LoadOpType, ExpressionType pointer, uint32_t offset);
     void emitStoreOp(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
 
-    void unify(const ExpressionType& dst, const ExpressionType& source);
+    void unify(const ExpressionType dst, const ExpressionType source);
     void unifyValuesWithBlock(const Stack& resultStack, const ResultList& stack);
 
     template <typename IntType>
@@ -743,7 +754,7 @@ void AirIRGenerator::restoreWasmContextInstance(BasicBlock* block, TypedTmp inst
     emitPatchpoint(block, patchpoint, Tmp(), instance);
 }
 
-AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, unsigned functionIndex, TierUpCount* tierUp, ThrowWasmException throwWasmException, const Signature& signature)
+AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, unsigned functionIndex, TierUpCount* tierUp, const Signature& signature)
     : m_info(info)
     , m_mode(mode)
     , m_functionIndex(functionIndex)
@@ -771,9 +782,6 @@ AirIRGenerator::AirIRGenerator(const ModuleInformation& info, B3::Procedure& pro
         m_code.pinRegister(m_memorySizeGPR);
     }
 
-    if (throwWasmException)
-        Thunks::singleton().setThrowWasmException(throwWasmException);
-
     if (info.memory) {
         switch (m_mode) {
         case MemoryMode::BoundsChecking:
@@ -1045,7 +1053,7 @@ auto AirIRGenerator::addArguments(const Signature& signature) -> PartialResult
     return { };
 }
 
-auto AirIRGenerator::addRefIsNull(ExpressionType& value, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addRefIsNull(ExpressionType value, ExpressionType& result) -> PartialResult
 {
     ASSERT(value.tmp());
     result = tmpForType(Type::I32);
@@ -1066,7 +1074,7 @@ auto AirIRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> Parti
     return { };
 }
 
-auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType index, ExpressionType& result) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     ASSERT(index.tmp());
@@ -1083,7 +1091,7 @@ auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, Exp
     return { };
 }
 
-auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
+auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType index, ExpressionType value) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     ASSERT(index.tmp());
@@ -1112,7 +1120,7 @@ auto AirIRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) -
     return { };
 }
 
-auto AirIRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addTableGrow(unsigned tableIndex, ExpressionType fill, ExpressionType delta, ExpressionType& result) -> PartialResult
 {
     ASSERT(fill.tmp());
     ASSERT(isSubtype(fill.type(), m_info.tables[tableIndex].wasmType()));
@@ -1125,7 +1133,7 @@ auto AirIRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, Exp
     return { };
 }
 
-auto AirIRGenerator::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> PartialResult
+auto AirIRGenerator::addTableFill(unsigned tableIndex, ExpressionType offset, ExpressionType fill, ExpressionType count) -> PartialResult
 {
     ASSERT(fill.tmp());
     ASSERT(isSubtype(fill.type(), m_info.tables[tableIndex].wasmType()));
@@ -1791,9 +1799,9 @@ void AirIRGenerator::emitLoopTierUpCheck(uint32_t loopIndex)
     for (auto& local : m_locals)
         patchArgs.append(ConstrainedTmp(local, B3::ValueRep::ColdAny));
     for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
-        ExpressionList& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
-        for (auto& value : expressionStack)
-            patchArgs.append(ConstrainedTmp(value, B3::ValueRep::ColdAny));
+        Stack& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
+        for (TypedExpression value : expressionStack)
+            patchArgs.append(ConstrainedTmp(value.value(), B3::ValueRep::ColdAny));
     }
 
     TierUpCount::TriggerReason* forceEntryTrigger = &(m_tierUp->osrEntryTriggers().last());
@@ -1822,7 +1830,7 @@ void AirIRGenerator::emitLoopTierUpCheck(uint32_t loopIndex)
         });
     });
 
-    emitPatchpoint(m_currentBlock, patch, Vector<Tmp, 1>(), WTFMove(patchArgs));
+    emitPatchpoint(m_currentBlock, patch, ResultList { }, WTFMove(patchArgs));
 }
 
 AirIRGenerator::ControlData AirIRGenerator::addTopLevel(BlockSignature signature)
@@ -1835,8 +1843,12 @@ auto AirIRGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Co
     BasicBlock* body = m_code.addBlock();
     BasicBlock* continuation = m_code.addBlock();
 
-    newStack = splitStack(signature, enclosingStack);
-    block = ControlData(origin(), signature, newStack, BlockType::Loop, continuation, body);
+    splitStack(signature, enclosingStack, newStack);
+    ResultList results;
+    results.reserveInitialCapacity(newStack.size());
+    for (auto item : newStack)
+        results.uncheckedAppend(item);
+    block = ControlData(origin(), signature, WTFMove(results), BlockType::Loop, continuation, body);
 
     append(Jump);
     m_currentBlock->setSuccessors(body);
@@ -1849,7 +1861,7 @@ auto AirIRGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Co
 
 auto AirIRGenerator::addBlock(BlockSignature signature, Stack& enclosingStack, ControlType& newBlock, Stack& newStack) -> PartialResult
 {
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     newBlock = ControlData(origin(), signature, tmpsForSignature(signature), BlockType::Block, m_code.addBlock());
     return { };
 }
@@ -1865,7 +1877,7 @@ auto AirIRGenerator::addIf(ExpressionType condition, BlockSignature signature, S
     m_currentBlock->setSuccessors(taken, notTaken);
 
     m_currentBlock = taken;
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     result = ControlData(origin(), signature, tmpsForSignature(signature), BlockType::If, continuation, notTaken);
     return { };
 }
@@ -1886,7 +1898,7 @@ auto AirIRGenerator::addElseToUnreachable(ControlData& data) -> PartialResult
     return { };
 }
 
-auto AirIRGenerator::addReturn(const ControlData& data, const ExpressionList& returnValues) -> PartialResult
+auto AirIRGenerator::addReturn(const ControlData& data, const Stack& returnValues) -> PartialResult
 {
     CallInformation wasmCallInfo = wasmCallingConvention().callInformationFor(*data.signature(), CallRole::Callee);
     if (!wasmCallInfo.results.size()) {
@@ -1924,7 +1936,7 @@ auto AirIRGenerator::addReturn(const ControlData& data, const ExpressionList& re
         returnConstraints.append(ConstrainedTmp(tmp, wasmCallInfo.results[i]));
     }
 
-    emitPatchpoint(m_currentBlock, patch, Vector<Tmp, 1>(), WTFMove(returnConstraints));
+    emitPatchpoint(m_currentBlock, patch, ResultList { }, WTFMove(returnConstraints));
     return { };
 }
 
@@ -2039,12 +2051,14 @@ auto AirIRGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expre
         for (unsigned i = 0; i < data.signature()->returnCount(); ++i) {
             if (i < expressionStack.size())
                 entry.enclosedExpressionStack.append(expressionStack[i]);
-            else
-                entry.enclosedExpressionStack.append(addBottom(m_currentBlock, data.signature()->returnType(i)));
+            else {
+                Type type = data.signature()->returnType(i);
+                entry.enclosedExpressionStack.constructAndAppend(type, addBottom(m_currentBlock, type));
+            }
         }
     } else {
-        for (const auto& result : data.results)
-            entry.enclosedExpressionStack.append(result);
+        for (unsigned i = 0; i < data.signature()->returnCount(); ++i)
+            entry.enclosedExpressionStack.constructAndAppend(data.signature()->returnType(i), data.results[i]);
     }
 
     // TopLevel does not have any code after this so we need to make sure we emit a return here.
@@ -2054,7 +2068,7 @@ auto AirIRGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expre
     return { };
 }
 
-B3::PatchpointValue* AirIRGenerator::emitCallPatchpoint(BasicBlock* block, const Signature& signature, const Vector<ExpressionType, 1>& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&& patchArgs)
+B3::PatchpointValue* AirIRGenerator::emitCallPatchpoint(BasicBlock* block, const Signature& signature, const ResultList& results, const Vector<TypedTmp>& args, Vector<ConstrainedTmp>&& patchArgs)
 {
     auto* patchpoint = addPatchpoint(toB3ResultType(&signature));
     patchpoint->effects.writesPinned = true;
@@ -2079,7 +2093,7 @@ B3::PatchpointValue* AirIRGenerator::emitCallPatchpoint(BasicBlock* block, const
     return patchpoint;
 }
 
-auto AirIRGenerator::addCall(uint32_t functionIndex, const Signature& signature, Vector<ExpressionType>& args, Vector<ExpressionType, 1>& results) -> PartialResult
+auto AirIRGenerator::addCall(uint32_t functionIndex, const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
 {
     ASSERT(signature.argumentCount() == args.size());
 
@@ -2169,7 +2183,7 @@ auto AirIRGenerator::addCall(uint32_t functionIndex, const Signature& signature,
     return { };
 }
 
-auto AirIRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, Vector<ExpressionType, 1>& results) -> PartialResult
+auto AirIRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
 {
     ExpressionType calleeIndex = args.takeLast();
     ASSERT(signature.argumentCount() == args.size());
@@ -2325,7 +2339,7 @@ auto AirIRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signa
     return { };
 }
 
-void AirIRGenerator::unify(const ExpressionType& dst, const ExpressionType& source)
+void AirIRGenerator::unify(const ExpressionType dst, const ExpressionType source)
 {
     ASSERT(isSubtype(source.type(), dst.type()));
     append(moveOpForValueType(dst.type()), source, dst);
@@ -2343,10 +2357,10 @@ static void dumpExpressionStack(const CommaPrinter& comma, const AirIRGenerator:
 {
     dataLog(comma, "ExpressionStack:");
     for (const auto& expression : expressionStack)
-        dataLog(comma, expression);
+        dataLog(comma, expression.value());
 }
 
-void AirIRGenerator::dump(const Vector<ControlEntry>& controlStack, const Stack* stack)
+void AirIRGenerator::dump(const ControlStack& controlStack, const Stack* stack)
 {
     dataLogLn("Processing Graph:");
     dataLog(m_code);
@@ -2368,7 +2382,7 @@ auto AirIRGenerator::origin() -> B3::Origin
     return B3::Origin();
 }
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, uint32_t functionIndex, TierUpCount* tierUp, ThrowWasmException throwWasmException)
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, uint32_t functionIndex, TierUpCount* tierUp)
 {
     auto result = makeUnique<InternalFunction>();
 
@@ -2391,7 +2405,7 @@ Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(Compilati
     
     procedure.setOptLevel(Options::webAssemblyBBQAirOptimizationLevel());
 
-    AirIRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, functionIndex, tierUp, throwWasmException, signature);
+    AirIRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, functionIndex, tierUp, signature);
     FunctionParser<AirIRGenerator> parser(irGenerator, function.data.data(), function.data.size(), signature, info);
     WASM_FAIL_IF_HELPER_FAILS(parser.parse());
 
@@ -2980,7 +2994,7 @@ auto AirIRGenerator::addOp<OpType::I64TruncUF64>(ExpressionType arg, ExpressionT
     });
 
     result = g64();
-    emitPatchpoint(m_currentBlock, patchpoint, Vector<Tmp, 1> { result }, WTFMove(args));
+    emitPatchpoint(m_currentBlock, patchpoint, Vector<TypedTmp, 8> { result }, WTFMove(args));
     return { };
 }
 
@@ -3055,7 +3069,7 @@ auto AirIRGenerator::addOp<OpType::I64TruncUF32>(ExpressionType arg, ExpressionT
     });
 
     result = g64();
-    emitPatchpoint(m_currentBlock, patchpoint, Vector<Tmp, 1> { result }, WTFMove(args));
+    emitPatchpoint(m_currentBlock, patchpoint, Vector<TypedTmp, 8> { result }, WTFMove(args));
 
     return { };
 }
index 331b4b0..1c3f5ba 100644 (file)
@@ -31,7 +31,7 @@
 
 namespace JSC { namespace Wasm {
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, uint32_t functionIndex, TierUpCount* = nullptr, ThrowWasmException = nullptr);
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompileAir(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, uint32_t functionIndex, TierUpCount* = nullptr);
 
 } } // namespace JSC::Wasm
 
index 0330339..2366536 100644 (file)
@@ -86,12 +86,13 @@ static constexpr bool verbose = false;
 
 class B3IRGenerator {
 public:
-    using ResultList = Vector<Value*, 1>; // Value must be a Phi
+    using ExpressionType = Value*;
+    using ResultList = Vector<ExpressionType, 8>;
 
     struct ControlData {
         ControlData(Procedure& proc, Origin origin, BlockSignature signature, BlockType type, BasicBlock* continuation, BasicBlock* special = nullptr)
             : controlBlockType(type)
-            , signature(signature)
+            , m_signature(signature)
             , continuation(continuation)
             , special(special)
         {
@@ -108,6 +109,9 @@ public:
         {
         }
 
+        static bool isIf(const ControlData& control) { return control.blockType() == BlockType::If; }
+        static bool isTopLevel(const ControlData& control) { return control.blockType() == BlockType::TopLevel; }
+
         void dump(PrintStream& out) const
         {
             switch (blockType()) {
@@ -133,7 +137,9 @@ public:
 
         BlockType blockType() const { return controlBlockType; }
 
-        bool hasNonVoidresult() const { return signature->returnsVoid(); }
+        BlockSignature signature() const { return m_signature; }
+
+        bool hasNonVoidresult() const { return m_signature->returnsVoid(); }
 
         BasicBlock* targetBlockForBranch()
         {
@@ -149,29 +155,47 @@ public:
             special = nullptr;
         }
 
+        SignatureArgCount branchTargetArity() const
+        {
+            if (blockType() == BlockType::Loop)
+                return m_signature->argumentCount();
+            return m_signature->returnCount();
+        }
+
+        Type branchTargetType(unsigned i) const
+        {
+            ASSERT(i < branchTargetArity());
+            if (blockType() == BlockType::Loop)
+                return m_signature->argument(i);
+            return m_signature->returnType(i);
+        }
+
     private:
         friend class B3IRGenerator;
         BlockType controlBlockType;
-        BlockSignature signature;
+        BlockSignature m_signature;
         BasicBlock* continuation;
         BasicBlock* special;
         ResultList phis;
     };
 
-    using ExpressionType = Value*;
+    using ControlType = ControlData;
     using ExpressionList = Vector<ExpressionType, 1>;
-    using Stack = ExpressionList;
 
-    using ControlType = ControlData;
     using ControlEntry = FunctionParser<B3IRGenerator>::ControlEntry;
+    using ControlStack = FunctionParser<B3IRGenerator>::ControlStack;
+    using Stack = FunctionParser<B3IRGenerator>::Stack;
+    using TypedExpression = FunctionParser<B3IRGenerator>::TypedExpression;
 
-    static constexpr ExpressionType emptyExpression() { return nullptr; }
-    bool isControlTypeIf(const ControlType& control) { return control.blockType() == BlockType::If; }
+    static_assert(std::is_same_v<ResultList, FunctionParser<B3IRGenerator>::ResultList>);
 
     typedef String ErrorType;
     typedef Unexpected<ErrorType> UnexpectedResult;
     typedef Expected<std::unique_ptr<InternalFunction>, ErrorType> Result;
     typedef Expected<void, ErrorType> PartialResult;
+
+    static ExpressionType emptyExpression() { return nullptr; };
+
     template <typename ...Args>
     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
     {
@@ -183,22 +207,22 @@ public:
             return fail(__VA_ARGS__);             \
     } while (0)
 
-    B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, MemoryMode, CompilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount*, ThrowWasmException);
+    B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, MemoryMode, CompilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount*);
 
     PartialResult WARN_UNUSED_RETURN addArguments(const Signature&);
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type, uint64_t);
 
     // References
-    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType value, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
+    PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value);
     PartialResult WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count);
+    PartialResult WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count);
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -229,7 +253,7 @@ public:
     PartialResult WARN_UNUSED_RETURN addElse(ControlData&, const Stack&);
     PartialResult WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
 
-    PartialResult WARN_UNUSED_RETURN addReturn(const ControlData&, const ExpressionList& returnValues);
+    PartialResult WARN_UNUSED_RETURN addReturn(const ControlData&, const Stack& returnValues);
     PartialResult WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const Stack& returnValues);
     PartialResult WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTargets, const Stack& expressionStack);
     PartialResult WARN_UNUSED_RETURN endBlock(ControlEntry&, Stack& expressionStack);
@@ -243,7 +267,7 @@ public:
     PartialResult WARN_UNUSED_RETURN addUnreachable();
     B3::Value* createCallPatchpoint(BasicBlock*, Origin, const Signature&, Vector<ExpressionType>& args, const ScopedLambda<void(PatchpointValue*)>& patchpointFunctor);
 
-    void dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack);
+    void dump(const ControlStack&, const Stack* expressionStack);
     void setParser(FunctionParser<B3IRGenerator>* parser) { m_parser = parser; };
     void didFinishParsingLocals() { }
     void didPopValueFromStack() { }
@@ -362,7 +386,7 @@ void B3IRGenerator::restoreWasmContextInstance(Procedure& proc, BasicBlock* bloc
     });
 }
 
-B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount* tierUp, ThrowWasmException throwWasmException)
+B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, unsigned loopIndexForOSREntry, TierUpCount* tierUp)
     : m_info(info)
     , m_mode(mode)
     , m_compilationMode(compilationMode)
@@ -393,9 +417,6 @@ B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure
         m_proc.pinRegister(m_memorySizeGPR);
     }
 
-    if (throwWasmException)
-        Thunks::singleton().setThrowWasmException(throwWasmException);
-
     if (info.memory) {
         m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -667,13 +688,13 @@ auto B3IRGenerator::addArguments(const Signature& signature) -> PartialResult
     return { };
 }
 
-auto B3IRGenerator::addRefIsNull(ExpressionType& value, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addRefIsNull(ExpressionType value, ExpressionType& result) -> PartialResult
 {
     result = m_currentBlock->appendNew<Value>(m_proc, B3::Equal, origin(), value, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), JSValue::encode(jsNull())));
     return { };
 }
 
-auto B3IRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addTableGet(unsigned tableIndex, ExpressionType index, ExpressionType& result) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(Anyref), origin(),
@@ -692,7 +713,7 @@ auto B3IRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, Expr
     return { };
 }
 
-auto B3IRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
+auto B3IRGenerator::addTableSet(unsigned tableIndex, ExpressionType index, ExpressionType value) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
     auto shouldThrow = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int32, origin(),
@@ -732,7 +753,7 @@ auto B3IRGenerator::addTableSize(unsigned tableIndex, ExpressionType& result) ->
     return { };
 }
 
-auto B3IRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addTableGrow(unsigned tableIndex, ExpressionType fill, ExpressionType delta, ExpressionType& result) -> PartialResult
 {
     result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(),
         m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&operationWasmTableGrow, B3CCallPtrTag)),
@@ -741,7 +762,7 @@ auto B3IRGenerator::addTableGrow(unsigned tableIndex, ExpressionType& fill, Expr
     return { };
 }
 
-auto B3IRGenerator::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> PartialResult
+auto B3IRGenerator::addTableFill(unsigned tableIndex, ExpressionType offset, ExpressionType fill, ExpressionType count) -> PartialResult
 {
     auto result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(I32), origin(),
         m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&operationWasmTableFill, B3CCallPtrTag)),
@@ -1270,12 +1291,12 @@ void B3IRGenerator::emitLoopTierUpCheck(uint32_t loopIndex)
 
     Vector<ExpressionType> stackmap;
     for (auto& local : m_locals) {
-        ExpressionType result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, origin, local);
+        Value* result = m_currentBlock->appendNew<VariableValue>(m_proc, B3::Get, origin, local);
         stackmap.append(result);
     }
     for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
         auto& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
-        for (Value* value : expressionStack)
+        for (TypedExpression value : expressionStack)
             stackmap.append(value);
     }
 
@@ -1333,12 +1354,12 @@ auto B3IRGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Con
     {
         unsigned offset = enclosingStack.size() - signature->argumentCount();
         for (unsigned i = 0; i < signature->argumentCount(); ++i) {
-            Value* value = enclosingStack.at(offset + i);
+            TypedExpression value = enclosingStack.at(offset + i);
             auto* upsilon = m_currentBlock->appendNew<UpsilonValue>(m_proc, origin(), value);
             Value* phi = block.phis[i];
             body->append(phi);
             upsilon->setPhi(phi);
-            newStack.append(phi);
+            newStack.constructAndAppend(value.type(), phi);
         }
         enclosingStack.shrink(offset);
     }
@@ -1369,7 +1390,7 @@ auto B3IRGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Con
             unsigned blockIndex = 0;
             B3::InsertionSet insertionSet(m_proc);
             for (unsigned i = 0; i < expressionStack.size(); i++) {
-                auto* value = expressionStack[i];
+                TypedExpression value = expressionStack[i];
                 if (value->isConstant()) {
                     ++indexInBuffer;
                     continue;
@@ -1388,7 +1409,7 @@ auto B3IRGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Con
                 ASSERT(sourceBlock->at(blockIndex - 1) == value);
 
                 auto* phi = data.continuation->appendNew<Value>(m_proc, Phi,  value->type(), value->origin());
-                expressionStack[i] = phi;
+                expressionStack[i] = TypedExpression { value.type(), phi };
                 m_currentBlock->appendNew<UpsilonValue>(m_proc, value->origin(), loadFromScratchBuffer(value->type()), phi);
 
                 auto* sourceUpsilon = m_proc.add<UpsilonValue>(value->origin(), value, phi);
@@ -1416,7 +1437,7 @@ auto B3IRGenerator::addBlock(BlockSignature signature, Stack& enclosingStack, Co
 {
     BasicBlock* continuation = m_proc.addBlock();
 
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     newBlock = ControlData(m_proc, origin(), signature, BlockType::Block, continuation);
     return { };
 }
@@ -1435,7 +1456,7 @@ auto B3IRGenerator::addIf(ExpressionType condition, BlockSignature signature, St
     notTaken->addPredecessor(m_currentBlock);
 
     m_currentBlock = taken;
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     result = ControlData(m_proc, origin(), signature, BlockType::If, continuation, notTaken);
     return { };
 }
@@ -1455,7 +1476,7 @@ auto B3IRGenerator::addElseToUnreachable(ControlData& data) -> PartialResult
     return { };
 }
 
-auto B3IRGenerator::addReturn(const ControlData&, const ExpressionList& returnValues) -> PartialResult
+auto B3IRGenerator::addReturn(const ControlData&, const Stack& returnValues) -> PartialResult
 {
     CallInformation wasmCallInfo = wasmCallingConvention().callInformationFor(m_parser->signature(), CallRole::Callee);
 
@@ -1526,7 +1547,7 @@ auto B3IRGenerator::endBlock(ControlEntry& entry, Stack& expressionStack) -> Par
 {
     ControlData& data = entry.controlData;
 
-    ASSERT(expressionStack.size() == data.signature->returnCount());
+    ASSERT(expressionStack.size() == data.signature()->returnCount());
     if (data.blockType() != BlockType::Loop)
         unifyValuesWithBlock(expressionStack, data.phis);
 
@@ -1547,17 +1568,20 @@ auto B3IRGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expres
     }
 
     if (data.blockType() != BlockType::Loop) {
-        for (Value* result : data.phis) {
+        for (unsigned i = 0; i < data.signature()->returnCount(); ++i) {
+            Value* result = data.phis[i];
             m_currentBlock->append(result);
-            entry.enclosedExpressionStack.append(result);
+            entry.enclosedExpressionStack.constructAndAppend(data.signature()->returnType(i), result);
         }
     } else {
         m_outerLoops.removeLast();
-        for (unsigned i = 0; i < data.signature->returnCount(); ++i) {
+        for (unsigned i = 0; i < data.signature()->returnCount(); ++i) {
             if (i < expressionStack.size())
                 entry.enclosedExpressionStack.append(expressionStack[i]);
-            else
-                entry.enclosedExpressionStack.append(constant(toB3Type(data.signature->returnType(i)), 0xbbadbeef));
+            else {
+                Type returnType = data.signature()->returnType(i);
+                entry.enclosedExpressionStack.constructAndAppend(returnType, constant(toB3Type(returnType), 0xbbadbeef));
+            }
         }
     }
 
@@ -1895,14 +1919,14 @@ void B3IRGenerator::unifyValuesWithBlock(const Stack& resultStack, const ResultL
         unify(result[result.size() - 1 - i], resultStack.at(resultStack.size() - 1 - i));
 }
 
-static void dumpExpressionStack(const CommaPrinter& comma, const B3IRGenerator::ExpressionList& expressionStack)
+static void dumpExpressionStack(const CommaPrinter& comma, const B3IRGenerator::Stack& expressionStack)
 {
     dataLog(comma, "ExpressionStack:");
     for (const auto& expression : expressionStack)
         dataLog(comma, *expression);
 }
 
-void B3IRGenerator::dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack)
+void B3IRGenerator::dump(const ControlStack& controlStack, const Stack* expressionStack)
 {
     dataLogLn("Constants:");
     for (const auto& constant : m_constantPool)
@@ -1930,7 +1954,7 @@ auto B3IRGenerator::origin() -> Origin
     return bitwise_cast<Origin>(origin);
 }
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* tierUp, ThrowWasmException throwWasmException)
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const FunctionData& function, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, unsigned& osrEntryScratchBufferSize, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* tierUp)
 {
     auto result = makeUnique<InternalFunction>();
 
@@ -1954,7 +1978,7 @@ Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationC
         ? Options::webAssemblyBBQB3OptimizationLevel()
         : Options::webAssemblyOMGOptimizationLevel());
 
-    B3IRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, mode, compilationMode, functionIndex, loopIndexForOSREntry, tierUp, throwWasmException);
+    B3IRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, mode, compilationMode, functionIndex, loopIndexForOSREntry, tierUp);
     FunctionParser<B3IRGenerator> parser(irGenerator, function.data.data(), function.data.size(), signature, info);
     WASM_FAIL_IF_HELPER_FAILS(parser.parse());
 
index ea55024..d2f881e 100644 (file)
@@ -51,7 +51,7 @@ struct CompilationContext {
     std::unique_ptr<B3::OpaqueByproducts> wasmEntrypointByproducts;
 };
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* = nullptr, ThrowWasmException = nullptr);
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const FunctionData&, const Signature&, Vector<UnlinkedWasmToWasmCall>&, unsigned& osrEntryScratchBufferSize, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, uint32_t loopIndexForOSREntry, TierUpCount* = nullptr);
 
 } } // namespace JSC::Wasm
 
index aac5a8c..bc92b6d 100644 (file)
@@ -29,6 +29,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3Compilation.h"
+#include "JSToWasm.h"
 #include "WasmAirIRGenerator.h"
 #include "WasmB3IRGenerator.h"
 #include "WasmBinding.h"
@@ -54,7 +55,7 @@ static constexpr bool verbose = false;
 }
 
 BBQPlan::BBQPlan(Context* context, Ref<ModuleInformation> moduleInformation, uint32_t functionIndex, CodeBlock* codeBlock, CompletionTask&& completionTask)
-    : EntryPlan(context, WTFMove(moduleInformation), WTFMove(completionTask))
+    : EntryPlan(context, WTFMove(moduleInformation), AsyncWork::FullCompile, WTFMove(completionTask))
     , m_codeBlock(codeBlock)
     , m_functionIndex(functionIndex)
 {
@@ -79,7 +80,24 @@ bool BBQPlan::prepareImpl()
 void BBQPlan::work(CompilationEffort effort)
 {
     if (!m_codeBlock) {
-        Base::work(effort);
+        switch (m_state) {
+        case State::Initial:
+            parseAndValidateModule();
+            if (!hasWork()) {
+                ASSERT(m_state == State::Validated);
+                complete(holdLock(m_lock));
+                break;
+            }
+            FALLTHROUGH;
+        case State::Validated:
+            prepare();
+            break;
+        case State::Prepared:
+            compileFunctions(effort);
+            break;
+        default:
+            break;
+        }
         return;
     }
 
@@ -115,7 +133,7 @@ void BBQPlan::work(CompilationEffort effort)
         LockHolder holder(m_codeBlock->m_lock);
         m_codeBlock->m_bbqCallees[m_functionIndex] = callee.copyRef();
         {
-            LLIntCallee& llintCallee = *m_codeBlock->m_llintCallees[m_functionIndex];
+            LLIntCallee& llintCallee = m_codeBlock->m_llintCallees[m_functionIndex].get();
             auto locker = holdLock(llintCallee.tierUpCounter().m_lock);
             llintCallee.setReplacement(callee.copyRef());
             llintCallee.tierUpCounter().m_compilationStatus = LLIntTierUpCounter::CompilationStatus::Compiled;
@@ -153,10 +171,11 @@ void BBQPlan::work(CompilationEffort effort)
 
         for (unsigned i = 0; i < m_codeBlock->m_wasmToWasmCallsites.size(); ++i) {
             repatchCalls(m_codeBlock->m_wasmToWasmCallsites[i]);
-            if (LLIntCallee* llintCallee = m_codeBlock->m_llintCallees[i].get()) {
-                if (JITCallee* replacementCallee = llintCallee->replacement())
+            if (m_codeBlock->m_llintCallees) {
+                LLIntCallee& llintCallee = m_codeBlock->m_llintCallees[i].get();
+                if (JITCallee* replacementCallee = llintCallee.replacement())
                     repatchCalls(replacementCallee->wasmToWasmCallsites());
-                if (OMGForOSREntryCallee* osrEntryCallee = llintCallee->osrEntryCallee())
+                if (OMGForOSREntryCallee* osrEntryCallee = llintCallee.osrEntryCallee())
                     repatchCalls(osrEntryCallee->wasmToWasmCallsites());
             }
             if (BBQCallee* bbqCallee = m_codeBlock->m_bbqCallees[i].get()) {
@@ -191,7 +210,7 @@ void BBQPlan::compileFunction(uint32_t functionIndex)
         auto locker = holdLock(m_lock);
         SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
         const Signature& signature = SignatureInformation::get(signatureIndex);
-        auto result = m_embedderToWasmInternalFunctions.add(functionIndex, m_createEmbedderWrapper(*m_compilationContexts[functionIndex].embedderEntrypointJIT, signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
+        auto result = m_embedderToWasmInternalFunctions.add(functionIndex, createJSToWasmWrapper(*m_compilationContexts[functionIndex].embedderEntrypointJIT, signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
         ASSERT_UNUSED(result, result.isNewEntry);
     }
 }
@@ -215,9 +234,9 @@ std::unique_ptr<InternalFunction> BBQPlan::compileFunction(uint32_t functionInde
         forceUsingB3 = true;
 
     if (!forceUsingB3 && Options::wasmBBQUsesAir())
-        parseAndCompileResult = parseAndCompileAir(context, function, signature, unlinkedWasmToWasmCalls, m_moduleInformation.get(), m_mode, functionIndex, tierUp, m_throwWasmException);
+        parseAndCompileResult = parseAndCompileAir(context, function, signature, unlinkedWasmToWasmCalls, m_moduleInformation.get(), m_mode, functionIndex, tierUp);
     else
-        parseAndCompileResult = parseAndCompile(context, function, signature, unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, UINT32_MAX, tierUp, m_throwWasmException);
+        parseAndCompileResult = parseAndCompile(context, function, signature, unlinkedWasmToWasmCalls, osrEntryScratchBufferSize, m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, UINT32_MAX, tierUp);
 
     if (UNLIKELY(!parseAndCompileResult)) {
         auto locker = holdLock(m_lock);
@@ -283,21 +302,41 @@ void BBQPlan::initializeCallees(const CalleeInitializer& callback)
     ASSERT(!failed());
     for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
 
-        RefPtr<Wasm::Callee> embedderEntrypointCallee;
+        RefPtr<EmbedderEntrypointCallee> embedderEntrypointCallee;
         if (auto embedderToWasmFunction = m_embedderToWasmInternalFunctions.get(internalFunctionIndex)) {
-            embedderEntrypointCallee = Wasm::EmbedderEntrypointCallee::create(WTFMove(embedderToWasmFunction->entrypoint));
+            embedderEntrypointCallee = EmbedderEntrypointCallee::create(WTFMove(embedderToWasmFunction->entrypoint));
             MacroAssembler::repatchPointer(embedderToWasmFunction->calleeMoveLocation, CalleeBits::boxWasm(embedderEntrypointCallee.get()));
         }
 
         InternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
         size_t functionIndexSpace = internalFunctionIndex + m_moduleInformation->importFunctionCount();
-        Ref<Wasm::Callee> wasmEntrypointCallee = Wasm::BBQCallee::create(WTFMove(function->entrypoint), functionIndexSpace, m_moduleInformation->nameSection->get(functionIndexSpace), WTFMove(m_tierUpCounts[internalFunctionIndex]), WTFMove(m_unlinkedWasmToWasmCalls[internalFunctionIndex]));
+        Ref<BBQCallee> wasmEntrypointCallee = BBQCallee::create(WTFMove(function->entrypoint), functionIndexSpace, m_moduleInformation->nameSection->get(functionIndexSpace), WTFMove(m_tierUpCounts[internalFunctionIndex]), WTFMove(m_unlinkedWasmToWasmCalls[internalFunctionIndex]));
         MacroAssembler::repatchPointer(function->calleeMoveLocation, CalleeBits::boxWasm(wasmEntrypointCallee.ptr()));
 
         callback(internalFunctionIndex, WTFMove(embedderEntrypointCallee), WTFMove(wasmEntrypointCallee));
     }
 }
 
+bool BBQPlan::didReceiveFunctionData(unsigned functionIndex, const FunctionData& function)
+{
+    dataLogLnIf(WasmBBQPlanInternal::verbose, "Processing function starting at: ", function.start, " and ending at: ", function.end);
+    size_t functionLength = function.end - function.start;
+    ASSERT(functionLength == function.data.size());
+    SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+    const Signature& signature = SignatureInformation::get(signatureIndex);
+
+    auto validationResult = validateFunction(function, signature, m_moduleInformation.get());
+    if (!validationResult) {
+        if (WasmBBQPlanInternal::verbose) {
+            for (unsigned i = 0; i < functionLength; ++i)
+                dataLog(RawPointer(reinterpret_cast<void*>(function.data[i])), ", ");
+            dataLogLn();
+        }
+        fail(holdLock(m_lock), makeString(validationResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
+    }
+    return !!validationResult;
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)
index f22e189..5e2dfdf 100644 (file)
@@ -44,7 +44,9 @@ class CallLinkInfo;
 
 namespace Wasm {
 
+class BBQCallee;
 class CodeBlock;
+class EmbedderEntrypointCallee;
 
 class BBQPlan final : public EntryPlan {
 public:
@@ -54,8 +56,24 @@ public:
 
     BBQPlan(Context*, Ref<ModuleInformation>, uint32_t functionIndex, CodeBlock*, CompletionTask&&);
 
+    bool hasWork() const override
+    {
+        if (m_asyncWork == AsyncWork::Validation)
+            return m_state < State::Validated;
+        return m_state < State::Compiled;
+    }
+
     void work(CompilationEffort) override;
-    void initializeCallees(const CalleeInitializer&) override;
+
+    using CalleeInitializer = Function<void(uint32_t, RefPtr<EmbedderEntrypointCallee>&&, Ref<BBQCallee>&&)>;
+    void initializeCallees(const CalleeInitializer&);
+
+    bool didReceiveFunctionData(unsigned, const FunctionData&) override;
+
+    bool parseAndValidateModule()
+    {
+        return Base::parseAndValidateModule(m_source.data(), m_source.size());
+    }
 
 protected:
     bool prepareImpl() override;
index 402e70b..134da7d 100644 (file)
 
 namespace JSC { namespace Wasm {
 
-Ref<CodeBlock> CodeBlock::create(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+Ref<CodeBlock> CodeBlock::create(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, const Ref<LLIntCallee>* llintCallees)
 {
-    auto* result = new (NotNull, fastMalloc(sizeof(CodeBlock))) CodeBlock(context, mode, moduleInformation, WTFMove(createEmbedderWrapper), throwWasmException);
+    auto* result = new (NotNull, fastMalloc(sizeof(CodeBlock))) CodeBlock(context, mode, moduleInformation, llintCallees);
     return adoptRef(*result);
 }
 
-CodeBlock::CodeBlock(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+CodeBlock::CodeBlock(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, const Ref<LLIntCallee>* llintCallees)
     : m_calleeCount(moduleInformation.internalFunctionCount())
     , m_mode(mode)
+    , m_llintCallees(llintCallees)
 {
     RefPtr<CodeBlock> protectedThis = this;
 
-    auto task = createSharedTask<Plan::CallbackType>([this, protectedThis = WTFMove(protectedThis)] (Plan&) {
-        auto locker = holdLock(m_lock);
-        if (m_plan->failed()) {
-            m_errorMessage = m_plan->errorMessage();
-            setCompilationFinished();
-            return;
-        }
-
-        // FIXME: we should eventually collect the BBQ code.
-        m_llintCallees.resize(m_calleeCount);
-        m_bbqCallees.resize(m_calleeCount);
-        m_omgCallees.resize(m_calleeCount);
-        m_wasmIndirectCallEntryPoints.resize(m_calleeCount);
-
-        m_plan->initializeCallees([&] (unsigned calleeIndex, RefPtr<Callee>&& embedderEntrypointCallee, RefPtr<Callee>&& wasmEntrypoint) {
-            if (embedderEntrypointCallee) {
-                auto result = m_embedderCallees.set(calleeIndex, WTFMove(embedderEntrypointCallee));
-                ASSERT_UNUSED(result, result.isNewEntry);
+    if (Options::useWasmLLInt()) {
+        m_plan = adoptRef(*new LLIntPlan(context, makeRef(moduleInformation), m_llintCallees, createSharedTask<Plan::CallbackType>([this, protectedThis = WTFMove(protectedThis)] (Plan&) {
+            auto locker = holdLock(m_lock);
+            if (m_plan->failed()) {
+                m_errorMessage = m_plan->errorMessage();
+                setCompilationFinished();
+                return;
             }
-            m_wasmIndirectCallEntryPoints[calleeIndex] = wasmEntrypoint->entrypoint();
 
-            if (Options::useWasmLLInt())
-                m_llintCallees[calleeIndex] = adoptRef(static_cast<LLIntCallee*>(wasmEntrypoint.leakRef()));
-            else
-                m_bbqCallees[calleeIndex] = adoptRef(static_cast<BBQCallee*>(wasmEntrypoint.leakRef()));
-        });
+            // FIXME: we should eventually collect the BBQ code.
+            m_bbqCallees.resize(m_calleeCount);
+            m_omgCallees.resize(m_calleeCount);
+            m_wasmIndirectCallEntryPoints.resize(m_calleeCount);
+
+            for (unsigned i = 0; i < m_calleeCount; ++i)
+                m_wasmIndirectCallEntryPoints[i] = m_llintCallees[i]->entrypoint();
+
+            m_wasmToWasmExitStubs = m_plan->takeWasmToWasmExitStubs();
+            m_wasmToWasmCallsites = m_plan->takeWasmToWasmCallsites();
+            m_embedderCallees = static_cast<LLIntPlan*>(m_plan.get())->takeEmbedderCallees();
 
-        m_wasmToWasmExitStubs = m_plan->takeWasmToWasmExitStubs();
-        m_wasmToWasmCallsites = m_plan->takeWasmToWasmCallsites();
+            setCompilationFinished();
+        })));
+    } else {
+        m_plan = adoptRef(*new BBQPlan(context, makeRef(moduleInformation), EntryPlan::FullCompile, createSharedTask<Plan::CallbackType>([this, protectedThis = WTFMove(protectedThis)] (Plan&) {
+            auto locker = holdLock(m_lock);
+            if (m_plan->failed()) {
+                m_errorMessage = m_plan->errorMessage();
+                setCompilationFinished();
+                return;
+            }
 
-        if (Options::useWasmLLInt())
-            m_llintEntryThunks = bitwise_cast<LLIntPlan*>(m_plan.get())->takeEntryThunks();
+            // FIXME: we should eventually collect the BBQ code.
+            m_bbqCallees.resize(m_calleeCount);
+            m_omgCallees.resize(m_calleeCount);
+            m_wasmIndirectCallEntryPoints.resize(m_calleeCount);
+
+            BBQPlan* bbqPlan = static_cast<BBQPlan*>(m_plan.get());
+            bbqPlan->initializeCallees([&] (unsigned calleeIndex, RefPtr<EmbedderEntrypointCallee>&& embedderEntrypointCallee, RefPtr<BBQCallee>&& wasmEntrypoint) {
+                if (embedderEntrypointCallee) {
+                    auto result = m_embedderCallees.set(calleeIndex, WTFMove(embedderEntrypointCallee));
+                    ASSERT_UNUSED(result, result.isNewEntry);
+                }
+                m_wasmIndirectCallEntryPoints[calleeIndex] = wasmEntrypoint->entrypoint();
+                m_bbqCallees[calleeIndex] = adoptRef(static_cast<BBQCallee*>(wasmEntrypoint.leakRef()));
+            });
 
-        setCompilationFinished();
-    });
+            m_wasmToWasmExitStubs = m_plan->takeWasmToWasmExitStubs();
+            m_wasmToWasmCallsites = m_plan->takeWasmToWasmCallsites();
 
-    if (Options::useWasmLLInt())
-        m_plan = adoptRef(*new LLIntPlan(context, makeRef(moduleInformation), EntryPlan::FullCompile, WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException));
-    else
-        m_plan = adoptRef(*new BBQPlan(context, makeRef(moduleInformation), EntryPlan::FullCompile, WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException));
+            setCompilationFinished();
+        })));
+    }
     m_plan->setMode(mode);
 
     auto& worklist = Wasm::ensureWorklist();
index 2bfc1b2..01547fd 100644 (file)
@@ -53,7 +53,7 @@ class CodeBlock : public ThreadSafeRefCounted<CodeBlock> {
 public:
     typedef void CallbackType(Ref<CodeBlock>&&);
     using AsyncCompilationCallback = RefPtr<WTF::SharedTask<CallbackType>>;
-    static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
+    static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, const Ref<LLIntCallee>*);
 
     void waitUntilFinished();
     void compileAsync(Context*, AsyncCompilationCallback&&);
@@ -95,7 +95,7 @@ public:
             return *m_omgCallees[calleeIndex].get();
         if (m_bbqCallees[calleeIndex])
             return *m_bbqCallees[calleeIndex].get();
-        return *m_llintCallees[calleeIndex].get();
+        return m_llintCallees[calleeIndex].get();
     }
 
     BBQCallee& wasmBBQCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
@@ -128,15 +128,14 @@ private:
     friend class OMGPlan;
     friend class OMGForOSREntryPlan;
 
-    CodeBlock(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
+    CodeBlock(Context*, MemoryMode, ModuleInformation&, const Ref<LLIntCallee>*);
     void setCompilationFinished();
     unsigned m_calleeCount;
     MemoryMode m_mode;
     Vector<RefPtr<OMGCallee>> m_omgCallees;
     Vector<RefPtr<BBQCallee>> m_bbqCallees;
-    Vector<RefPtr<LLIntCallee>> m_llintCallees;
-    MacroAssemblerCodeRef<B3CompilationPtrTag> m_llintEntryThunks;
-    HashMap<uint32_t, RefPtr<Callee>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderCallees;
+    const Ref<LLIntCallee>* m_llintCallees;
+    HashMap<uint32_t, RefPtr<EmbedderEntrypointCallee>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderCallees;
     Vector<MacroAssemblerCodePtr<WasmEntryPtrTag>> m_wasmIndirectCallEntryPoints;
     Vector<Vector<UnlinkedWasmToWasmCall>> m_wasmToWasmCallsites;
     Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>> m_wasmToWasmExitStubs;
index 5d3472b..77d03d3 100644 (file)
@@ -47,33 +47,17 @@ namespace WasmEntryPlanInternal {
 static const bool verbose = false;
 }
 
-EntryPlan::EntryPlan(Context* context, Ref<ModuleInformation> info, AsyncWork work, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
-    : Base(context, WTFMove(info), WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException)
+EntryPlan::EntryPlan(Context* context, Ref<ModuleInformation> info, AsyncWork work, CompletionTask&& task)
+    : Base(context, WTFMove(info), WTFMove(task))
     , m_streamingParser(m_moduleInformation.get(), *this)
     , m_state(State::Validated)
     , m_asyncWork(work)
 {
 }
 
-EntryPlan::EntryPlan(Context* context, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
-    : Base(context, ModuleInformation::create(), WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException)
-    , m_source(WTFMove(source))
-    , m_streamingParser(m_moduleInformation.get(), *this)
-    , m_state(State::Initial)
-    , m_asyncWork(work)
-{
-}
-
-EntryPlan::EntryPlan(Context* context, Ref<ModuleInformation> moduleInformation, CompletionTask&& task)
-    : Base(context, WTFMove(moduleInformation), WTFMove(task))
-    , m_streamingParser(m_moduleInformation.get(), *this)
-    , m_state(State::Initial)
-    , m_asyncWork(AsyncWork::FullCompile)
-{
-}
-
-EntryPlan::EntryPlan(Context* context, AsyncWork work, CompletionTask&& task)
+EntryPlan::EntryPlan(Context* context, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task)
     : Base(context, WTFMove(task))
+    , m_source(WTFMove(source))
     , m_streamingParser(m_moduleInformation.get(), *this)
     , m_state(State::Initial)
     , m_asyncWork(work)
@@ -99,26 +83,6 @@ void EntryPlan::moveToState(State state)
     m_state = state;
 }
 
-bool EntryPlan::didReceiveFunctionData(unsigned functionIndex, const FunctionData& function)
-{
-    dataLogLnIf(WasmEntryPlanInternal::verbose, "Processing function starting at: ", function.start, " and ending at: ", function.end);
-    size_t functionLength = function.end - function.start;
-    ASSERT(functionLength == function.data.size());
-    SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
-    const Signature& signature = SignatureInformation::get(signatureIndex);
-
-    auto validationResult = validateFunction(function, signature, m_moduleInformation.get());
-    if (!validationResult) {
-        if (WasmEntryPlanInternal::verbose) {
-            for (unsigned i = 0; i < functionLength; ++i)
-                dataLog(RawPointer(reinterpret_cast<void*>(function.data[i])), ", ");
-            dataLogLn();
-        }
-        fail(holdLock(m_lock), makeString(validationResult.error(), ", in function at index ", String::number(functionIndex))); // FIXME make this an Expected.
-    }
-    return !!validationResult;
-}
-
 bool EntryPlan::parseAndValidateModule(const uint8_t* source, size_t sourceLength)
 {
     if (m_state != State::Initial)
@@ -145,8 +109,6 @@ bool EntryPlan::parseAndValidateModule(const uint8_t* source, size_t sourceLengt
         dataLogLn("Took ", (MonotonicTime::now() - startTime).microseconds(), " us to validate module");
 
     moveToState(State::Validated);
-    if (m_asyncWork == Validation)
-        complete(holdLock(m_lock));
     return true;
 }
 
@@ -156,6 +118,7 @@ void EntryPlan::prepare()
     dataLogLnIf(WasmEntryPlanInternal::verbose, "Starting preparation");
 
     const auto& functions = m_moduleInformation->functions;
+    m_numberOfFunctions = functions.size();
     if (!tryReserveCapacity(m_wasmToWasmExitStubs, m_moduleInformation->importFunctionSignatureIndices.size(), " WebAssembly to JavaScript stubs")
         || !tryReserveCapacity(m_unlinkedWasmToWasmCalls, functions.size(), " unlinked WebAssembly to WebAssembly calls"))
         return;
@@ -223,20 +186,6 @@ public:
     EntryPlan& m_plan;
 };
 
-void EntryPlan::complete(const AbstractLocker& locker)
-{
-    ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functions.size());
-    dataLogLnIf(WasmEntryPlanInternal::verbose, "Starting Completion");
-
-    if (!failed() && m_state == State::Compiled)
-        didCompleteCompilation(locker);
-
-    if (!isComplete()) {
-        moveToState(State::Completed);
-        runCompletionTasks(locker);
-    }
-}
-
 
 void EntryPlan::compileFunctions(CompilationEffort effort)
 {
@@ -252,7 +201,6 @@ void EntryPlan::compileFunctions(CompilationEffort effort)
     ThreadCountHolder holder(*this);
 
     size_t bytesCompiled = 0;
-    const auto& functions = m_moduleInformation->functions;
     while (true) {
         if (effort == Partial && bytesCompiled >= Options::webAssemblyPartialCompileLimit())
             return;
@@ -260,7 +208,7 @@ void EntryPlan::compileFunctions(CompilationEffort effort)
         uint32_t functionIndex;
         {
             auto locker = holdLock(m_lock);
-            if (m_currentIndex >= functions.size()) {
+            if (m_currentIndex >= m_numberOfFunctions) {
                 if (hasWork())
                     moveToState(State::Compiled);
                 return;
@@ -270,31 +218,25 @@ void EntryPlan::compileFunctions(CompilationEffort effort)
         }
 
         compileFunction(functionIndex);
-        bytesCompiled += functions[functionIndex].data.size();
+        bytesCompiled += m_moduleInformation->functions[functionIndex].data.size();
     }
 }
 
-void EntryPlan::work(CompilationEffort effort)
+void EntryPlan::complete(const AbstractLocker& locker)
 {
-    switch (m_state) {
-    case State::Initial:
-        parseAndValidateModule(m_source.data(), m_source.size());
-        if (!hasWork()) {
-            ASSERT(isComplete());
-            break;
-        }
-        FALLTHROUGH;
-    case State::Validated:
-        prepare();
-        break;
-    case State::Prepared:
-        compileFunctions(effort);
-        break;
-    default:
-        break;
+    ASSERT(m_state != State::Compiled || m_currentIndex >= m_moduleInformation->functions.size());
+    dataLogLnIf(WasmEntryPlanInternal::verbose, "Starting Completion");
+
+    if (!failed() && m_state == State::Compiled)
+        didCompleteCompilation(locker);
+
+    if (!isComplete()) {
+        moveToState(State::Completed);
+        runCompletionTasks(locker);
     }
 }
 
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)
index 2483628..b49dc2b 100644 (file)
@@ -47,36 +47,15 @@ public:
     enum AsyncWork : uint8_t { FullCompile, Validation };
 
     // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
-    EntryPlan(Context*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
-    JS_EXPORT_PRIVATE EntryPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
-    EntryPlan(Context*, Ref<ModuleInformation>, CompletionTask&&);
-    EntryPlan(Context*, AsyncWork, CompletionTask&&);
+    EntryPlan(Context*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&);
+    JS_EXPORT_PRIVATE EntryPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&);
 
     virtual ~EntryPlan() = default;
 
-    using CalleeInitializer = Function<void(uint32_t, RefPtr<Callee>&&, Ref<Callee>&&)>;
-    virtual void initializeCallees(const CalleeInitializer&) = 0;
-
-    bool parseAndValidateModule()
-    {
-        return parseAndValidateModule(m_source.data(), m_source.size());
-    }
-    bool parseAndValidateModule(const uint8_t*, size_t);
+    void prepare();
 
     void compileFunctions(CompilationEffort);
 
-    Vector<Export>& exports() const
-    {
-        RELEASE_ASSERT(!failed() && !hasWork());
-        return m_moduleInformation->exports;
-    }
-
-    size_t internalFunctionCount() const
-    {
-        RELEASE_ASSERT(!failed() && !hasWork());
-        return m_moduleInformation->internalFunctionCount();
-    }
-
     Ref<ModuleInformation>&& takeModuleInformation()
     {
         RELEASE_ASSERT(!failed() && !hasWork());
@@ -103,39 +82,27 @@ public:
         Completed // We should only move to Completed if we are holding the lock.
     };
 
-    bool hasWork() const override
-    {
-        if (m_asyncWork == AsyncWork::Validation)
-            return m_state < State::Validated;
-        return m_state < State::Compiled;
-    }
-
-    void work(CompilationEffort) override;
-    bool hasBeenPrepared() const { return m_state >= State::Prepared; }
-    bool multiThreaded() const override { return hasBeenPrepared(); }
-
-    bool didReceiveFunctionData(unsigned, const FunctionData&) override;
+    bool multiThreaded() const override { return m_state >= State::Prepared; }
 
 private:
     class ThreadCountHolder;
     friend class ThreadCountHolder;
 
-    void prepare();
-    bool isComplete() const override { return m_state == State::Completed; }
-    void complete(const AbstractLocker&) override;
-
-    const char* stateString(State);
-
 protected:
     // For some reason friendship doesn't extend to parent classes...
     using Base::m_lock;
 
+    bool parseAndValidateModule(const uint8_t*, size_t);
+
+    const char* stateString(State);
+    void moveToState(State);
+    bool isComplete() const override { return m_state == State::Completed; }
+    void complete(const AbstractLocker&) override;
+
     virtual bool prepareImpl() = 0;
     virtual void compileFunction(uint32_t functionIndex) = 0;
     virtual void didCompleteCompilation(const AbstractLocker&) = 0;
 
-    void moveToState(State);
-
     template<typename T>
     bool tryReserveCapacity(Vector<T>& vector, size_t size, const char* what)
     {
@@ -157,6 +124,7 @@ protected:
     const AsyncWork m_asyncWork;
     uint8_t m_numberOfActiveThreads { 0 };
     uint32_t m_currentIndex { 0 };
+    uint32_t m_numberOfFunctions { 0 };
 };
 
 
index ccfa185..d12c948 100644 (file)
@@ -40,31 +40,50 @@ enum class BlockType {
     TopLevel
 };
 
-template<typename Stack>
-Stack splitStack(BlockSignature signature, Stack& stack)
+template<typename EnclosingStack, typename NewStack>
+void splitStack(BlockSignature signature, EnclosingStack& enclosingStack, NewStack& newStack)
 {
-    Stack result;
-    result.reserveInitialCapacity(signature->argumentCount());
-    ASSERT(stack.size() >= signature->argumentCount());
-    unsigned offset = stack.size() - signature->argumentCount();
+    newStack.reserveInitialCapacity(signature->argumentCount());
+    ASSERT(enclosingStack.size() >= signature->argumentCount());
+    unsigned offset = enclosingStack.size() - signature->argumentCount();
     for (unsigned i = 0; i < signature->argumentCount(); ++i)
-        result.uncheckedAppend(stack.at(i + offset));
-    stack.shrink(offset);
-    return result;
+        newStack.uncheckedAppend(enclosingStack.at(i + offset));
+    enclosingStack.shrink(offset);
 }
 
 template<typename Context>
 class FunctionParser : public Parser<void> {
 public:
-    using ExpressionType = typename Context::ExpressionType;
+    struct ControlEntry;
+
     using ControlType = typename Context::ControlType;
-    using ExpressionList = typename Context::ExpressionList;
-    using Stack = typename Context::Stack;
-    using ResultList = typename Context::ResultList;
+    using ExpressionType = typename Context::ExpressionType;
 
-    FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature&, const ModuleInformation&);
+    class TypedExpression {
+    public:
+        TypedExpression() = default;
 
-    Result WARN_UNUSED_RETURN parse();
+        TypedExpression(Type type, ExpressionType value)
+            : m_type(type)
+            , m_value(value)
+        {
+        }
+
+        Type type() const { return m_type; }
+
+        ExpressionType value() const { return m_value; }
+        operator ExpressionType() const { return m_value; }
+
+        ExpressionType operator->() const { return m_value; }
+
+    private:
+        Type m_type;
+        ExpressionType m_value;
+    };
+
+    using ControlStack = Vector<ControlEntry, 16>;
+    using ResultList = Vector<ExpressionType, 8>;
+    using Stack = Vector<TypedExpression, 16, UnsafeVectorOverflow>;
 
     struct ControlEntry {
         Stack enclosedExpressionStack;
@@ -72,11 +91,15 @@ public:
         ControlType controlData;
     };
 
+    FunctionParser(Context&, const uint8_t* functionStart, size_t functionLength, const Signature&, const ModuleInformation&);
+
+    Result WARN_UNUSED_RETURN parse();
+
     OpType currentOpcode() const { return m_currentOpcode; }
     size_t currentOpcodeStartingOffset() const { return m_currentOpcodeStartingOffset; }
     const Signature& signature() const { return m_signature; }
 
-    Vector<ControlEntry>& controlStack() { return m_controlStack; }
+    ControlStack& controlStack() { return m_controlStack; }
     Stack& expressionStack() { return m_expressionStack; }
 
 private:
@@ -86,6 +109,8 @@ private:
     PartialResult WARN_UNUSED_RETURN parseExpression();
     PartialResult WARN_UNUSED_RETURN parseUnreachableExpression();
     PartialResult WARN_UNUSED_RETURN unifyControl(Vector<ExpressionType>&, unsigned level);
+    PartialResult WARN_UNUSED_RETURN checkBranchTarget(const ControlType&);
+    PartialResult WARN_UNUSED_RETURN unify(const ControlType&);
 
 #define WASM_TRY_POP_EXPRESSION_STACK_INTO(result, what) do {                               \
         WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't pop empty stack in " what); \
@@ -94,18 +119,39 @@ private:
     } while (0)
 
     template<OpType>
-    PartialResult WARN_UNUSED_RETURN unaryCase();
+    PartialResult WARN_UNUSED_RETURN unaryCase(Type returnType, Type operandType);
 
     template<OpType>
-    PartialResult WARN_UNUSED_RETURN binaryCase();
+    PartialResult WARN_UNUSED_RETURN binaryCase(Type returnType, Type lhsType, Type rhsType);
+
+    PartialResult WARN_UNUSED_RETURN store(Type memoryType);
+    PartialResult WARN_UNUSED_RETURN load(Type memoryType);
 
 #define WASM_TRY_ADD_TO_CONTEXT(add_expression) WASM_FAIL_IF_HELPER_FAILS(m_context.add_expression)
 
+    template <typename ...Args>
+    NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN validationFail(const Args&... args) const
+    {
+        using namespace FailureHelper; // See ADL comment in WasmParser.h.
+        if (UNLIKELY(!ASSERT_DISABLED && Options::crashOnFailedWebAssemblyValidate()))
+            WTFBreakpointTrap();
+
+        StringPrintStream out;
+        out.print("WebAssembly.Module doesn't validate: "_s, args...);
+        return UnexpectedResult(out.toString());
+    }
+
+#define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \
+        if (UNLIKELY(condition)) \
+            return validationFail(__VA_ARGS__); \
+    } while (0) \
+
     // FIXME add a macro as above for WASM_TRY_APPEND_TO_CONTROL_STACK https://bugs.webkit.org/show_bug.cgi?id=165862
 
     Context& m_context;
     Stack m_expressionStack;
-    Vector<ControlEntry> m_controlStack;
+    ControlStack m_controlStack;
+    Vector<Type, 16> m_locals;
     const Signature& m_signature;
     const ModuleInformation& m_info;
 
@@ -136,6 +182,10 @@ auto FunctionParser<Context>::parse() -> Result
     WASM_PARSER_FAIL_IF(!m_context.addArguments(m_signature), "can't add ", m_signature.argumentCount(), " arguments to Function");
     WASM_PARSER_FAIL_IF(!parseVarUInt32(localGroupsCount), "can't get local groups count");
 
+    WASM_PARSER_FAIL_IF(!m_locals.tryReserveCapacity(m_signature.argumentCount()), "can't allocate enough memory for function's ", m_signature.argumentCount(), " arguments");
+    for (uint32_t i = 0; i < m_signature.argumentCount(); ++i)
+        m_locals.uncheckedAppend(m_signature.argument(i));
+
     uint64_t totalNumberOfLocals = m_signature.argumentCount();
     for (uint32_t i = 0; i < localGroupsCount; ++i) {
         uint32_t numberOfLocals;
@@ -145,6 +195,11 @@ auto FunctionParser<Context>::parse() -> Result
         totalNumberOfLocals += numberOfLocals;
         WASM_PARSER_FAIL_IF(totalNumberOfLocals > maxFunctionLocals, "Function's number of locals is too big ", totalNumberOfLocals, " maximum ", maxFunctionLocals);
         WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
+
+        WASM_PARSER_FAIL_IF(!m_locals.tryReserveCapacity(totalNumberOfLocals), "can't allocate enough memory for function's ", totalNumberOfLocals, " locals");
+        for (uint32_t i = 0; i < numberOfLocals; ++i)
+            m_locals.uncheckedAppend(typeOfLocal);
+
         WASM_TRY_ADD_TO_CONTEXT(addLocal(typeOfLocal, numberOfLocals));
     }
 
@@ -186,31 +241,104 @@ auto FunctionParser<Context>::parseBody() -> PartialResult
 
 template<typename Context>
 template<OpType op>
-auto FunctionParser<Context>::binaryCase() -> PartialResult
+auto FunctionParser<Context>::binaryCase(Type returnType, Type lhsType, Type rhsType) -> PartialResult
 {
-    ExpressionType right;
-    ExpressionType left;
-    ExpressionType result;
+    TypedExpression right;
+    TypedExpression left;
 
     WASM_TRY_POP_EXPRESSION_STACK_INTO(right, "binary right");
     WASM_TRY_POP_EXPRESSION_STACK_INTO(left, "binary left");
-    WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result));
 
-    m_expressionStack.append(result);
+    WASM_VALIDATOR_FAIL_IF(left.type() != lhsType, op, " left value type mismatch");
+    WASM_VALIDATOR_FAIL_IF(right.type() != rhsType, op, " right value type mismatch");
+
+    ExpressionType result;
+    WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(left, right, result));
+    m_expressionStack.constructAndAppend(returnType, result);
     return { };
 }
 
 template<typename Context>
 template<OpType op>
-auto FunctionParser<Context>::unaryCase() -> PartialResult
+auto FunctionParser<Context>::unaryCase(Type returnType, Type operandType) -> PartialResult
 {
-    ExpressionType value;
-    ExpressionType result;
-
+    TypedExpression value;
     WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "unary");
+
+    WASM_VALIDATOR_FAIL_IF(value.type() != operandType, op, " value type mismatch");
+
+    ExpressionType result;
     WASM_TRY_ADD_TO_CONTEXT(template addOp<op>(value, result));
+    m_expressionStack.constructAndAppend(returnType, result);
+    return { };
+}
+
+template<typename Context>
+auto FunctionParser<Context>::load(Type memoryType) -> PartialResult
+{
+    WASM_VALIDATOR_FAIL_IF(!m_info.memory, "load instruction without memory");
+
+    uint32_t alignment;
+    uint32_t offset;
+    TypedExpression pointer;
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
+    WASM_PARSER_FAIL_IF(alignment > memoryLog2Alignment(m_currentOpcode), "byte alignment ", 1ull << alignment, " exceeds load's natural alignment ", 1ull << memoryLog2Alignment(m_currentOpcode));
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
+    WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
+
+    WASM_VALIDATOR_FAIL_IF(pointer.type() != I32, m_currentOpcode, " pointer type mismatch");
+
+    ExpressionType result;
+    WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(m_currentOpcode), pointer, result, offset));
+    m_expressionStack.constructAndAppend(memoryType, result);
+    return { };
+}
+
+template<typename Context>
+auto FunctionParser<Context>::store(Type memoryType) -> PartialResult
+{
+    WASM_VALIDATOR_FAIL_IF(!m_info.memory, "store instruction without memory");
+
+    uint32_t alignment;
+    uint32_t offset;
+    TypedExpression value;
+    TypedExpression pointer;
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
+    WASM_PARSER_FAIL_IF(alignment > memoryLog2Alignment(m_currentOpcode), "byte alignment ", 1ull << alignment, " exceeds store's natural alignment ", 1ull << memoryLog2Alignment(m_currentOpcode));
+    WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
+    WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
+    WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
+
+    WASM_VALIDATOR_FAIL_IF(pointer.type() != I32, m_currentOpcode, " pointer type mismatch");
+    WASM_VALIDATOR_FAIL_IF(value.type() != memoryType, m_currentOpcode, " value type mismatch");
+
+    WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(m_currentOpcode), pointer, value, offset));
+    return { };
+}
+
+template<typename Context>
+auto FunctionParser<Context>::checkBranchTarget(const ControlType& target) -> PartialResult
+{
+    if (!target.branchTargetArity())
+        return { };
+
+    WASM_VALIDATOR_FAIL_IF(m_expressionStack.size() < target.branchTargetArity(), ControlType::isTopLevel(target) ? "branch out of function" : "branch to block", " on expression stack of size ", m_expressionStack.size(), ", but block, ", target.signature()->toString() , " expects ", target.branchTargetArity(), " values");
+
+
+    unsigned offset = m_expressionStack.size() - target.branchTargetArity();
+    for (unsigned i = 0; i < target.branchTargetArity(); ++i)
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(target.branchTargetType(i), m_expressionStack[offset + i].type()), "branch's stack type is not a subtype of block's type branch target type. Stack value has type", m_expressionStack[offset + i].type(), " but branch target expects a value with subtype of ", target.branchTargetType(i), " at index ", i);
+
+    return { };
+}
+
+template<typename Context>
+auto FunctionParser<Context>::unify(const ControlType& controlData) -> PartialResult
+{
+    WASM_VALIDATOR_FAIL_IF(controlData.signature()->returnCount() != m_expressionStack.size(), " block with type: ", controlData.signature()->toString(), " returns: ", controlData.signature()->returnCount(), " but stack has: ", m_expressionStack.size(), " values");
+    for (unsigned i = 0; i < controlData.signature()->returnCount(); ++i)
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[i].type(), controlData.signature()->returnType(i)), "control flow returns with unexpected type. ", m_expressionStack[i].type(), " is not a subtype of ", controlData.signature()->returnType(i));
 
-    m_expressionStack.append(result);
     return { };
 }
 
@@ -218,85 +346,66 @@ template<typename Context>
 auto FunctionParser<Context>::parseExpression() -> PartialResult
 {
     switch (m_currentOpcode) {
-#define CREATE_CASE(name, id, b3op, inc) case OpType::name: return binaryCase<OpType::name>();
+#define CREATE_CASE(name, id, b3op, inc, lhsType, rhsType, returnType) case OpType::name: return binaryCase<OpType::name>(returnType, lhsType, rhsType);
     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
 #undef CREATE_CASE
 
-#define CREATE_CASE(name, id, b3op, inc) case OpType::name: return unaryCase<OpType::name>();
+#define CREATE_CASE(name, id, b3op, inc, operandType, returnType) case OpType::name: return unaryCase<OpType::name>(returnType, operandType);
     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
 #undef CREATE_CASE
 
     case Select: {
-        ExpressionType condition;
-        ExpressionType zero;
-        ExpressionType nonZero;
+        TypedExpression condition;
+        TypedExpression zero;
+        TypedExpression nonZero;
 
         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "select condition");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(zero, "select zero");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(nonZero, "select non-zero");
 
+        WASM_VALIDATOR_FAIL_IF(condition.type() != I32, "select condition must be i32, got ", condition.type());
+        WASM_VALIDATOR_FAIL_IF(nonZero.type() != zero.type(), "select result types must match, got ", nonZero.type(), " and ", zero.type());
+
         ExpressionType result;
         WASM_TRY_ADD_TO_CONTEXT(addSelect(condition, nonZero, zero, result));
 
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(zero.type(), result);
         return { };
     }
 
-#define CREATE_CASE(name, id, b3op, inc) case OpType::name:
-    FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE) {
-        uint32_t alignment;
-        uint32_t offset;
-        ExpressionType pointer;
-        ExpressionType result;
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get load alignment");
-        WASM_PARSER_FAIL_IF(alignment > memoryLog2Alignment(m_currentOpcode), "byte alignment ", 1ull << alignment, " exceeds load's natural alignment ", 1ull << memoryLog2Alignment(m_currentOpcode));
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get load offset");
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "load pointer");
-        WASM_TRY_ADD_TO_CONTEXT(load(static_cast<LoadOpType>(m_currentOpcode), pointer, result, offset));
-        m_expressionStack.append(result);
-        return { };
-    }
+#define CREATE_CASE(name, id, b3op, inc, memoryType) case OpType::name: return load(memoryType);
+FOR_EACH_WASM_MEMORY_LOAD_OP(CREATE_CASE)
+#undef CREATE_CASE
 
-    FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE) {
-        uint32_t alignment;
-        uint32_t offset;
-        ExpressionType value;
-        ExpressionType pointer;
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(alignment), "can't get store alignment");
-        WASM_PARSER_FAIL_IF(alignment > memoryLog2Alignment(m_currentOpcode), "byte alignment ", 1ull << alignment, " exceeds store's natural alignment ", 1ull << memoryLog2Alignment(m_currentOpcode));
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(offset), "can't get store offset");
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "store value");
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(pointer, "store pointer");
-        WASM_TRY_ADD_TO_CONTEXT(store(static_cast<StoreOpType>(m_currentOpcode), pointer, value, offset));
-        return { };
-    }
+#define CREATE_CASE(name, id, b3op, inc, memoryType) case OpType::name: return store(memoryType);
+FOR_EACH_WASM_MEMORY_STORE_OP(CREATE_CASE)
 #undef CREATE_CASE
 
     case F32Const: {
         uint32_t constant;
         WASM_PARSER_FAIL_IF(!parseUInt32(constant), "can't parse 32-bit floating-point constant");
-        m_expressionStack.append(m_context.addConstant(F32, constant));
+        m_expressionStack.constructAndAppend(F32, m_context.addConstant(F32, constant));
         return { };
     }
 
     case I32Const: {
         int32_t constant;
         WASM_PARSER_FAIL_IF(!parseVarInt32(constant), "can't parse 32-bit constant");
-        m_expressionStack.append(m_context.addConstant(I32, constant));
+        m_expressionStack.constructAndAppend(I32, m_context.addConstant(I32, constant));
         return { };
     }
 
     case F64Const: {
         uint64_t constant;
         WASM_PARSER_FAIL_IF(!parseUInt64(constant), "can't parse 64-bit floating-point constant");
-        m_expressionStack.append(m_context.addConstant(F64, constant));
+        m_expressionStack.constructAndAppend(F64, m_context.addConstant(F64, constant));
         return { };
     }
 
     case I64Const: {
         int64_t constant;
         WASM_PARSER_FAIL_IF(!parseVarInt64(constant), "can't parse 64-bit constant");
-        m_expressionStack.append(m_context.addConstant(I64, constant));
+        m_expressionStack.constructAndAppend(I64, m_context.addConstant(I64, constant));
         return { };
     }
 
@@ -304,10 +413,16 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         unsigned tableIndex;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
-        ExpressionType result, index;
+        WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount());
+
+        TypedExpression index;
         WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.get");
+        WASM_VALIDATOR_FAIL_IF(I32 != index.type(), "table.get index to type ", index.type(), " expected ", I32);
+
+        ExpressionType result;
         WASM_TRY_ADD_TO_CONTEXT(addTableGet(tableIndex, index, result));
-        m_expressionStack.append(result);
+        Type resultType = m_info.tables[tableIndex].wasmType();
+        m_expressionStack.constructAndAppend(resultType, result);
         return { };
     }
 
@@ -315,10 +430,15 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         unsigned tableIndex;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
-        ExpressionType val, index;
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
+        WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount());
+        TypedExpression value, index;
+        WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "table.set");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.set");
-        WASM_TRY_ADD_TO_CONTEXT(addTableSet(tableIndex, index, val));
+        WASM_VALIDATOR_FAIL_IF(I32 != index.type(), "table.set index to type ", index.type(), " expected ", I32);
+        Type type = m_info.tables[tableIndex].wasmType();
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(value.type(), type), "table.set value to type ", value.type(), " expected ", type);
+        RELEASE_ASSERT(m_info.tables[tableIndex].type() == TableElementType::Anyref || m_info.tables[tableIndex].type() == TableElementType::Funcref);
+        WASM_TRY_ADD_TO_CONTEXT(addTableSet(tableIndex, index, value));
         return { };
     }
 
@@ -328,27 +448,39 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         WASM_PARSER_FAIL_IF(!parseUInt8(extOp), "can't parse table extended opcode");
         unsigned tableIndex;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
+        WASM_VALIDATOR_FAIL_IF(tableIndex >= m_info.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_info.tableCount());
 
         switch (static_cast<ExtTableOpType>(extOp)) {
         case ExtTableOpType::TableSize: {
             ExpressionType result;
             WASM_TRY_ADD_TO_CONTEXT(addTableSize(tableIndex, result));
-            m_expressionStack.append(result);
+            m_expressionStack.constructAndAppend(I32, result);
             break;
         }
         case ExtTableOpType::TableGrow: {
-            ExpressionType fill, delta, result;
+            TypedExpression fill;
+            TypedExpression delta;
             WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "table.grow");
             WASM_TRY_POP_EXPRESSION_STACK_INTO(fill, "table.grow");
+
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(fill.type(), m_info.tables[tableIndex].wasmType()), "table.grow expects fill value of type ", m_info.tables[tableIndex].wasmType(), " got ", fill.type());
+            WASM_VALIDATOR_FAIL_IF(I32 != delta.type(), "table.grow expects an i32 delta value, got ", delta.type());
+
+            ExpressionType result;
             WASM_TRY_ADD_TO_CONTEXT(addTableGrow(tableIndex, fill, delta, result));
-            m_expressionStack.append(result);
+            m_expressionStack.constructAndAppend(I32, result);
             break;
         }
         case ExtTableOpType::TableFill: {
-            ExpressionType offset, fill, count;
+            TypedExpression offset, fill, count;
             WASM_TRY_POP_EXPRESSION_STACK_INTO(count, "table.fill");
             WASM_TRY_POP_EXPRESSION_STACK_INTO(fill, "table.fill");
             WASM_TRY_POP_EXPRESSION_STACK_INTO(offset, "table.fill");
+
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(fill.type(), m_info.tables[tableIndex].wasmType()), "table.fill expects fill value of type ", m_info.tables[tableIndex].wasmType(), " got ", fill.type());
+            WASM_VALIDATOR_FAIL_IF(I32 != offset.type(), "table.fill expects an i32 offset value, got ", offset.type());
+            WASM_VALIDATOR_FAIL_IF(I32 != count.type(), "table.fill expects an i32 count value, got ", count.type());
+
             WASM_TRY_ADD_TO_CONTEXT(addTableFill(tableIndex, offset, fill, count));
             break;
         }
@@ -361,16 +493,18 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
 
     case RefNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        m_expressionStack.append(m_context.addConstant(Funcref, JSValue::encode(jsNull())));
+        m_expressionStack.constructAndAppend(Funcref, m_context.addConstant(Funcref, JSValue::encode(jsNull())));
         return { };
     }
 
     case RefIsNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        ExpressionType result, value;
+        TypedExpression value;
         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "ref.is_null");
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(value.type(), Anyref), "ref.is_null to type ", value.type(), " expected ", Anyref);
+        ExpressionType result;
         WASM_TRY_ADD_TO_CONTEXT(addRefIsNull(value, result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(I32, result);
         return { };
     }
 
@@ -380,8 +514,10 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for ref.func");
 
+        WASM_VALIDATOR_FAIL_IF(index >= m_info.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_info.functionIndexSpaceSize());
+        m_info.addReferencedFunction(index);
         WASM_TRY_ADD_TO_CONTEXT(addRefFunc(index, result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(Funcref, result);
         return { };
     }
 
@@ -389,16 +525,18 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         uint32_t index;
         ExpressionType result;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for get_local");
+        WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
         WASM_TRY_ADD_TO_CONTEXT(getLocal(index, result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(m_locals[index], result);
         return { };
     }
 
     case SetLocal: {
         uint32_t index;
-        ExpressionType value;
+        TypedExpression value;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for set_local");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_local");
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(value.type(), m_locals[index]), "set_local to type ", value.type(), " expected ", m_locals[index]);
         WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
         return { };
     }
@@ -407,7 +545,9 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         uint32_t index;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for tee_local");
         WASM_PARSER_FAIL_IF(m_expressionStack.isEmpty(), "can't tee_local on empty expression stack");
-        WASM_TRY_ADD_TO_CONTEXT(setLocal(index, m_expressionStack.last()));
+        TypedExpression value = m_expressionStack.last();
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(value.type(), m_locals[index]), "set_local to type ", value.type(), " expected ", m_locals[index]);
+        WASM_TRY_ADD_TO_CONTEXT(setLocal(index, value));
         return { };
     }
 
@@ -415,16 +555,27 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         uint32_t index;
         ExpressionType result;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get get_global's index");
+        WASM_VALIDATOR_FAIL_IF(index >= m_info.globals.size(), "get_global ", index, " of unknown global, limit is ", m_info.globals.size());
+        Type resultType = m_info.globals[index].type;
+        ASSERT(isValueType(resultType));
         WASM_TRY_ADD_TO_CONTEXT(getGlobal(index, result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(resultType, result);
         return { };
     }
 
     case SetGlobal: {
         uint32_t index;
-        ExpressionType value;
+        TypedExpression value;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get set_global's index");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "set_global value");
+
+        WASM_VALIDATOR_FAIL_IF(index >= m_info.globals.size(), "set_global ", index, " of unknown global, limit is ", m_info.globals.size());
+        WASM_VALIDATOR_FAIL_IF(m_info.globals[index].mutability == GlobalInformation::Immutable, "set_global ", index, " is immutable");
+
+        Type globalType = m_info.globals[index].type;
+        ASSERT(isValueType(globalType));
+        WASM_VALIDATOR_FAIL_IF(globalType != value.type(), "set_global ", index, " with type ", globalType, " with a variable of type ", value.type());
+
         WASM_TRY_ADD_TO_CONTEXT(setGlobal(index, value));
         return { };
     }
@@ -442,15 +593,22 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         Vector<ExpressionType> args;
         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(calleeSignature.argumentCount()), "can't allocate enough memory for call's ", calleeSignature.argumentCount(), " arguments");
         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) {
-            args.uncheckedAppend(m_expressionStack.at(i));
+            TypedExpression arg = m_expressionStack.at(i);
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(arg.type(), calleeSignature.argument(i - firstArgumentIndex)), "argument type mismatch in call, got ", arg.type(), ", expected ", calleeSignature.argument(i - firstArgumentIndex));
+            args.uncheckedAppend(arg);
             m_context.didPopValueFromStack();
         }
         m_expressionStack.shrink(firstArgumentIndex);
 
+        RELEASE_ASSERT(calleeSignature.argumentCount() == args.size());
+
         ResultList results;
         WASM_TRY_ADD_TO_CONTEXT(addCall(functionIndex, calleeSignature, args, results));
 
-        m_expressionStack.appendVector(results);
+        RELEASE_ASSERT(calleeSignature.returnCount() == results.size());
+
+        for (unsigned i = 0; i < calleeSignature.returnCount(); ++i)
+            m_expressionStack.constructAndAppend(calleeSignature.returnType(i), results[i]);
 
         return { };
     }
@@ -469,18 +627,27 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         size_t argumentCount = calleeSignature.argumentCount() + 1; // Add the callee's index.
         WASM_PARSER_FAIL_IF(argumentCount > m_expressionStack.size(), "call_indirect expects ", argumentCount, " arguments, but the expression stack currently holds ", m_expressionStack.size(), " values");
 
+        WASM_VALIDATOR_FAIL_IF(m_expressionStack.last().type() != I32, "non-i32 call_indirect index ", m_expressionStack.last().type());
+
         Vector<ExpressionType> args;
         WASM_PARSER_FAIL_IF(!args.tryReserveCapacity(argumentCount), "can't allocate enough memory for ", argumentCount, " call_indirect arguments");
         size_t firstArgumentIndex = m_expressionStack.size() - argumentCount;
         for (size_t i = firstArgumentIndex; i < m_expressionStack.size(); ++i) {
-            args.uncheckedAppend(m_expressionStack.at(i));
+            TypedExpression arg = m_expressionStack.at(i);
+            if (i < calleeSignature.argumentCount())
+                WASM_VALIDATOR_FAIL_IF(!isSubtype(arg.type(), calleeSignature.argument(i - firstArgumentIndex)), "argument type mismatch in call_indirect, got ", arg.type(), ", expected ", calleeSignature.argument(i - firstArgumentIndex));
+            args.uncheckedAppend(arg);
             m_context.didPopValueFromStack();
         }
         m_expressionStack.shrink(firstArgumentIndex);
 
+
+
         ResultList results;
         WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(tableIndex, calleeSignature, args, results));
-        m_expressionStack.appendVector(results);
+
+        for (unsigned i = 0; i < calleeSignature.returnCount(); ++i)
+            m_expressionStack.constructAndAppend(calleeSignature.returnType(i), results[i]);
 
         return { };
     }
@@ -489,6 +656,13 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         BlockSignature inlineSignature;
         WASM_PARSER_FAIL_IF(!parseBlockSignature(m_info, inlineSignature), "can't get block's signature");
 
+        WASM_VALIDATOR_FAIL_IF(m_expressionStack.size() < inlineSignature->argumentCount(), "Too few values on stack for block. Block expects ", inlineSignature->argumentCount(), ", but only ", m_expressionStack.size(), " were present. Block has inlineSignature: ", inlineSignature->toString());
+        unsigned offset = m_expressionStack.size() - inlineSignature->argumentCount();
+        for (unsigned i = 0; i < inlineSignature->argumentCount(); ++i) {
+            Type type = m_expressionStack.at(offset + i).type();
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(type, inlineSignature->argument(i)), "Block expects the argument at index", i, " to be a subtype of ", inlineSignature->argument(i), " but argument has type ", type);
+        }
+
         int64_t oldSize = m_expressionStack.size();
         Stack newStack;
         ControlType block;
@@ -505,6 +679,13 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         BlockSignature inlineSignature;
         WASM_PARSER_FAIL_IF(!parseBlockSignature(m_info, inlineSignature), "can't get loop's signature");
 
+        WASM_VALIDATOR_FAIL_IF(m_expressionStack.size() < inlineSignature->argumentCount(), "Too few values on stack for loop block. Loop expects ", inlineSignature->argumentCount(), ", but only ", m_expressionStack.size(), " were present. Loop has inlineSignature: ", inlineSignature->toString());
+        unsigned offset = m_expressionStack.size() - inlineSignature->argumentCount();
+        for (unsigned i = 0; i < inlineSignature->argumentCount(); ++i) {
+            Type type = m_expressionStack.at(offset + i).type();
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(type, inlineSignature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", inlineSignature->argument(i), " but argument has type ", type);
+        }
+
         int64_t oldSize = m_expressionStack.size();
         Stack newStack;
         ControlType loop;
@@ -519,10 +700,16 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
 
     case If: {
         BlockSignature inlineSignature;
-        ExpressionType condition;
+        TypedExpression condition;
         WASM_PARSER_FAIL_IF(!parseBlockSignature(m_info, inlineSignature), "can't get if's signature");
         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "if condition");
 
+        WASM_VALIDATOR_FAIL_IF(condition.type() != I32, "if condition must be i32, got ", condition.type());
+        WASM_VALIDATOR_FAIL_IF(m_expressionStack.size() < inlineSignature->argumentCount(), "Too few arguments on stack for if block. If expects ", inlineSignature->argumentCount(), ", but only ", m_expressionStack.size(), " were present. If block has signature: ", inlineSignature->toString());
+        unsigned offset = m_expressionStack.size() - inlineSignature->argumentCount();
+        for (unsigned i = 0; i < inlineSignature->argumentCount(); ++i)
+            WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[offset + i].type(), inlineSignature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", inlineSignature->argument(i), " but argument has type ", m_expressionStack[i].type());
+
         int64_t oldSize = m_expressionStack.size();
         Stack newStack;
         ControlType control;
@@ -537,32 +724,40 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
 
     case Else: {
         WASM_PARSER_FAIL_IF(m_controlStack.size() == 1, "can't use else block at the top-level of a function");
-        WASM_TRY_ADD_TO_CONTEXT(addElse(m_controlStack.last().controlData, m_expressionStack));
-        m_expressionStack = WTFMove(m_controlStack.last().elseBlockStack);
+
+        ControlEntry& controlEntry = m_controlStack.last();
+
+        WASM_FAIL_IF_HELPER_FAILS(unify(controlEntry.controlData));
+
+        WASM_TRY_ADD_TO_CONTEXT(addElse(controlEntry.controlData, m_expressionStack));
+        m_expressionStack = WTFMove(controlEntry.elseBlockStack);
         return { };
     }
 
     case Br:
     case BrIf: {
         uint32_t target;
-        ExpressionType condition = Context::emptyExpression();
+        TypedExpression condition;
         WASM_PARSER_FAIL_IF(!parseVarUInt32(target), "can't get br / br_if's target");
         WASM_PARSER_FAIL_IF(target >= m_controlStack.size(), "br / br_if's target ", target, " exceeds control stack size ", m_controlStack.size());
-        if (m_currentOpcode == BrIf)
+        if (m_currentOpcode == BrIf) {
             WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br / br_if condition");
-        else
+            WASM_VALIDATOR_FAIL_IF(condition.type() != I32, "conditional branch with non-i32 condition ", condition.type());
+        } else {
             m_unreachableBlocks = 1;
+            condition = TypedExpression { Void, Context::emptyExpression() };
+        }
 
         ControlType& data = m_controlStack[m_controlStack.size() - 1 - target].controlData;
-
+        WASM_FAIL_IF_HELPER_FAILS(checkBranchTarget(data));
         WASM_TRY_ADD_TO_CONTEXT(addBranch(data, condition, m_expressionStack));
         return { };
     }
 
     case BrTable: {
         uint32_t numberOfTargets;
-        uint32_t defaultTarget;
-        ExpressionType condition;
+        uint32_t defaultTargetIndex;
+        TypedExpression condition;
         Vector<ControlType*> targets;
 
         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfTargets), "can't get the number of targets for br_table");
@@ -576,17 +771,29 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
             targets.uncheckedAppend(&m_controlStack[m_controlStack.size() - 1 - target].controlData);
         }
 
-        WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTarget), "can't get default target for br_table");
-        WASM_PARSER_FAIL_IF(defaultTarget >= m_controlStack.size(), "br_table's default target ", defaultTarget, " exceeds control stack size ", m_controlStack.size());
+        WASM_PARSER_FAIL_IF(!parseVarUInt32(defaultTargetIndex), "can't get default target for br_table");
+        WASM_PARSER_FAIL_IF(defaultTargetIndex >= m_controlStack.size(), "br_table's default target ", defaultTargetIndex, " exceeds control stack size ", m_controlStack.size());
+        ControlType& defaultTarget = m_controlStack[m_controlStack.size() - 1 - defaultTargetIndex].controlData;
 
         WASM_TRY_POP_EXPRESSION_STACK_INTO(condition, "br_table condition");
-        WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, m_controlStack[m_controlStack.size() - 1 - defaultTarget].controlData, m_expressionStack));
+        WASM_VALIDATOR_FAIL_IF(condition.type() != I32, "br_table with non-i32 condition ", condition.type());
+
+        for (unsigned i = 0; i < targets.size(); ++i) {
+            ControlType* target = targets[i];
+            WASM_VALIDATOR_FAIL_IF(defaultTarget.branchTargetArity() != target->branchTargetArity(), "br_table target type size mismatch. Default has size: ", defaultTarget.branchTargetArity(), "but target: ", i, " has size: ", target->branchTargetArity());
+            for (unsigned type = 0; type < defaultTarget.branchTargetArity(); ++type)
+                WASM_VALIDATOR_FAIL_IF(!isSubtype(defaultTarget.branchTargetType(type), target->branchTargetType(type)), "br_table target type mismatch at offset ", type, " expected: ", defaultTarget.branchTargetType(type), " but saw: ", target->branchTargetType(type), " when targeting block: ", target->signature()->toString());
+        }
+
+        WASM_FAIL_IF_HELPER_FAILS(checkBranchTarget(defaultTarget));
+        WASM_TRY_ADD_TO_CONTEXT(addSwitch(condition, targets, defaultTarget, m_expressionStack));
 
         m_unreachableBlocks = 1;
         return { };
     }
 
     case Return: {
+        WASM_FAIL_IF_HELPER_FAILS(checkBranchTarget(m_controlStack[0].controlData));
         WASM_TRY_ADD_TO_CONTEXT(addReturn(m_controlStack[0].controlData, m_expressionStack));
         m_unreachableBlocks = 1;
         return { };
@@ -594,13 +801,15 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
 
     case End: {
         ControlEntry data = m_controlStack.takeLast();
-        if (m_context.isControlTypeIf(data.controlData)) {
+        if (ControlType::isIf(data.controlData)) {
+            WASM_FAIL_IF_HELPER_FAILS(unify(data.controlData));
             WASM_TRY_ADD_TO_CONTEXT(addElse(data.controlData, m_expressionStack));
             m_expressionStack = WTFMove(data.elseBlockStack);
         }
         // FIXME: This is a little weird in that it will modify the expressionStack for the result of the block.
         // That's a little too effectful for me but I don't have a better API right now.
         // see: https://bugs.webkit.org/show_bug.cgi?id=164353
+        WASM_FAIL_IF_HELPER_FAILS(unify(data.controlData));
         WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
         m_expressionStack.swap(data.enclosedExpressionStack);
         return { };
@@ -630,12 +839,13 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't parse reserved varUint1 for grow_memory");
         WASM_PARSER_FAIL_IF(reserved != 0, "reserved varUint1 for grow_memory must be zero");
 
-        ExpressionType delta;
+        TypedExpression delta;
         WASM_TRY_POP_EXPRESSION_STACK_INTO(delta, "expect an i32 argument to grow_memory on the stack");
+        WASM_VALIDATOR_FAIL_IF(delta.type() != I32, "grow_memory with non-i32 delta argument has type: ", delta.type());
 
         ExpressionType result;
         WASM_TRY_ADD_TO_CONTEXT(addGrowMemory(delta, result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(I32, result);
 
         return { };
     }
@@ -649,7 +859,7 @@ auto FunctionParser<Context>::parseExpression() -> PartialResult
 
         ExpressionType result;
         WASM_TRY_ADD_TO_CONTEXT(addCurrentMemory(result));
-        m_expressionStack.append(result);
+        m_expressionStack.constructAndAppend(I32, result);
 
         return { };
     }
@@ -664,7 +874,7 @@ template<typename Context>
 auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult
 {
     ASSERT(m_unreachableBlocks);
-#define CREATE_CASE(name, id, b3op, inc) case OpType::name:
+#define CREATE_CASE(name, ...) case OpType::name:
     switch (m_currentOpcode) {
     case Else: {
         if (m_unreachableBlocks > 1)
@@ -680,9 +890,10 @@ auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult
     case End: {
         if (m_unreachableBlocks == 1) {
             ControlEntry data = m_controlStack.takeLast();
-            if (m_context.isControlTypeIf(data.controlData)) {
+            if (ControlType::isIf(data.controlData)) {
                 WASM_TRY_ADD_TO_CONTEXT(addElseToUnreachable(data.controlData));
                 m_expressionStack = WTFMove(data.elseBlockStack);
+                WASM_FAIL_IF_HELPER_FAILS(unify(data.controlData));
                 WASM_TRY_ADD_TO_CONTEXT(endBlock(data, m_expressionStack));
             } else
                 WASM_TRY_ADD_TO_CONTEXT(addEndToUnreachable(data));
@@ -814,4 +1025,8 @@ auto FunctionParser<Context>::parseUnreachableExpression() -> PartialResult
 
 } } // namespace JSC::Wasm
 
+#undef WASM_TRY_POP_EXPRESSION_STACK_INTO
+#undef WASM_TRY_ADD_TO_CONTEXT
+#undef WASM_VALIDATOR_FAIL_IF
+
 #endif // ENABLE(WEBASSEMBLY)
index ad36398..73ff239 100644 (file)
@@ -49,8 +49,6 @@ namespace JSC { namespace Wasm {
 class LLIntGenerator : public BytecodeGeneratorBase<GeneratorTraits> {
 public:
     using ExpressionType = VirtualRegister;
-    using ExpressionList = Vector<ExpressionType, 1>;
-    using Stack = Vector<ExpressionType, 16, UnsafeVectorOverflow>;
 
     struct ControlLoop  {
         Ref<Label> m_body;
@@ -74,14 +72,14 @@ public:
         {
         }
 
-        static ControlType loop(BlockSignature signature, unsigned stackSize, Ref<Label>&& body, RefPtr<Label>&& continuation)
+        static ControlType topLevel(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation)
         {
-            return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlLoop { WTFMove(body) });
+            return ControlType(signature, stackSize, WTFMove(continuation), ControlTopLevel { });
         }
 
-        static ControlType topLevel(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation)
+        static ControlType loop(BlockSignature signature, unsigned stackSize, Ref<Label>&& body, RefPtr<Label>&& continuation)
         {
-            return ControlType(signature, stackSize, WTFMove(continuation), ControlTopLevel { });
+            return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlLoop { WTFMove(body) });
         }
 
         static ControlType block(BlockSignature signature, unsigned stackSize, RefPtr<Label>&& continuation)
@@ -94,6 +92,12 @@ public:
             return ControlType(signature, stackSize - signature->argumentCount(), WTFMove(continuation), ControlIf { WTFMove(alternate) });
         }
 
+        static bool isIf(const ControlType& control) { return WTF::holds_alternative<ControlIf>(control); }
+        static bool isTopLevel(const ControlType& control) { return WTF::holds_alternative<ControlTopLevel>(control); }
+
+        unsigned stackSize() const { return m_stackSize; }
+        BlockSignature signature() const { return m_signature; }
+
         RefPtr<Label> targetLabelForBranch() const
         {
             if (WTF::holds_alternative<ControlLoop>(*this))
@@ -101,14 +105,20 @@ public:
             return m_continuation;
         }
 
-        unsigned targetArity() const
+        SignatureArgCount branchTargetArity() const
         {
             if (WTF::holds_alternative<ControlLoop>(*this))
                 return m_signature->argumentCount();
             return m_signature->returnCount();
         }
 
-        unsigned stackSize() const { return m_stackSize; }
+        Type branchTargetType(unsigned i) const
+        {
+            ASSERT(i < branchTargetArity());
+            if (WTF::holds_alternative<ControlLoop>(*this))
+                return m_signature->argument(i);
+            return m_signature->returnType(i);
+        }
 
         BlockSignature m_signature;
         unsigned m_stackSize;
@@ -127,14 +137,15 @@ public:
 
     using ErrorType = String;
     using PartialResult = Expected<void, ErrorType>;
-    using ResultList = ExpressionList;
     using UnexpectedResult = Unexpected<ErrorType>;
 
     using ControlEntry = FunctionParser<LLIntGenerator>::ControlEntry;
+    using ControlStack = FunctionParser<LLIntGenerator>::ControlStack;
+    using ResultList = FunctionParser<LLIntGenerator>::ResultList;
+    using Stack = FunctionParser<LLIntGenerator>::Stack;
+    using TypedExpression = FunctionParser<LLIntGenerator>::TypedExpression;
 
-    LLIntGenerator(const ModuleInformation&, unsigned functionIndex, ThrowWasmException, const Signature&);
-
-    std::unique_ptr<FunctionCodeBlock> finalize();
+    static ExpressionType emptyExpression() { return { }; };
 
     template <typename ...Args>
     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
@@ -143,6 +154,10 @@ public:
         return UnexpectedResult(makeString("WebAssembly.Module failed compiling: "_s, makeString(args)...));
     }
 
+    LLIntGenerator(const ModuleInformation&, unsigned functionIndex, const Signature&);
+
+    std::unique_ptr<FunctionCodeBlock> finalize();
+
     template<typename ExpressionListA, typename ExpressionListB>
     void unifyValuesWithBlock(const ExpressionListA& destinations, const ExpressionListB& values)
     {
@@ -167,10 +182,6 @@ public:
 
     void didPopValueFromStack() { --m_stackSize; }
 
-    static ExpressionType emptyExpression() { return VirtualRegister { }; };
-    Stack createStack() { return Stack(); }
-    bool isControlTypeIf(const ControlType& control) { return WTF::holds_alternative<ControlIf>(control); }
-
     PartialResult WARN_UNUSED_RETURN addArguments(const Signature&);
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type, int64_t);
@@ -223,15 +234,15 @@ public:
     PartialResult WARN_UNUSED_RETURN endTopLevel(BlockSignature, const Stack&);
 
     // Calls
-    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ExpressionList& results);
-    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ExpressionList& results);
+    PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
+    PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ResultList& results);
     PartialResult WARN_UNUSED_RETURN addUnreachable();
 
     void didFinishParsingLocals();
 
     void setParser(FunctionParser<LLIntGenerator>* parser) { m_parser = parser; };
 
-    void dump(const Vector<ControlEntry>&, const Stack*) { }
+    void dump(const ControlStack&, const Stack*) { }
 
 private:
     friend GenericLabel<Wasm::GeneratorTraits>;
@@ -239,8 +250,8 @@ private:
     struct LLIntCallInformation {
         unsigned stackOffset;
         unsigned numberOfStackArguments;
-        ExpressionList arguments;
-        CompletionHandler<void(ExpressionList&)> commitResults;
+        ResultList arguments;
+        CompletionHandler<void(ResultList&)> commitResults;
     };
 
     LLIntCallInformation callInformationForCaller(const Signature&);
@@ -282,8 +293,8 @@ private:
     void getDropKeepCount(const ControlType& target, unsigned& startOffset, unsigned& drop, unsigned& keep)
     {
         startOffset = target.stackSize() + 1;
-        keep = target.targetArity();
-        drop = m_stackSize - target.stackSize() - target.targetArity();
+        keep = target.branchTargetArity();
+        drop = m_stackSize - target.stackSize() - target.branchTargetArity();
     }
 
     void dropKeep(Stack& values, const ControlType& target, bool dropValues)
@@ -352,32 +363,31 @@ private:
             return;
 
         checkConsistency();
-        walkExpressionStack(expressionStack, [&](VirtualRegister& expression, VirtualRegister slot) {
-            ASSERT(expression == slot || expression.isConstant() || expression.isArgument() || expression.toLocal() < m_codeBlock->m_numVars);
-            if (expression == slot)
+        walkExpressionStack(expressionStack, [&](TypedExpression& expression, VirtualRegister slot) {
+            ASSERT(expression.value() == slot || expression.value().isConstant() || expression.value().isArgument() || expression.value().toLocal() < m_codeBlock->m_numVars);
+            if (expression.value() == slot)
                 return;
             WasmMov::emit(this, slot, expression);
-            expression = slot;
+            expression = TypedExpression { expression.type(), slot };
         });
         checkConsistency();
     }
 
-    Stack splitStack(BlockSignature signature, Stack& stack)
+    void splitStack(BlockSignature signature, Stack& enclosingStack, Stack& newStack)
     {
-        Stack result = JSC::Wasm::splitStack(signature, stack);
+        JSC::Wasm::splitStack(signature, enclosingStack, newStack);
 
-        m_stackSize -= result.size();
+        m_stackSize -= newStack.size();
         checkConsistency();
-        walkExpressionStack(stack, [&](VirtualRegister& expression, VirtualRegister slot) {
-            ASSERT(expression == slot || expression.isConstant() || expression.isArgument() || expression.toLocal() < m_codeBlock->m_numVars);
-            if (expression == slot || expression.isConstant())
+        walkExpressionStack(enclosingStack, [&](TypedExpression& expression, VirtualRegister slot) {
+            ASSERT(expression.value() == slot || expression.value().isConstant() || expression.value().isArgument() || expression.value().toLocal() < m_codeBlock->m_numVars);
+            if (expression.value() == slot || expression.value().isConstant())
                 return;
             WasmMov::emit(this, slot, expression);
-            expression = slot;
+            expression = TypedExpression { expression.type(), slot };
         });
         checkConsistency();
-        m_stackSize += result.size();
-        return result;
+        m_stackSize += newStack.size();
     }
 
     struct SwitchEntry {
@@ -398,23 +408,23 @@ private:
     HashMap<Label*, Vector<SwitchEntry>> m_switches;
     ExpressionType m_jsNullConstant;
     ExpressionType m_zeroConstant;
-    ExpressionList m_unitializedLocals;
+    ResultList m_unitializedLocals;
     HashMap<EncodedJSValue, VirtualRegister, WTF::IntHash<EncodedJSValue>, ConstantMapHashTraits> m_constantMap;
     Vector<VirtualRegister, 2> m_results;
     unsigned m_stackSize { 0 };
     unsigned m_maxStackSize { 0 };
 };
 
-Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileBytecode(const uint8_t* functionStart, size_t functionLength, const Signature& signature, const ModuleInformation& info, uint32_t functionIndex, ThrowWasmException throwWasmException)
+Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileBytecode(const uint8_t* functionStart, size_t functionLength, const Signature& signature, const ModuleInformation& info, uint32_t functionIndex)
 {
-    LLIntGenerator llintGenerator(info, functionIndex, throwWasmException, signature);
+    LLIntGenerator llintGenerator(info, functionIndex, signature);
     FunctionParser<LLIntGenerator> parser(llintGenerator, functionStart, functionLength, signature, info);
     WASM_FAIL_IF_HELPER_FAILS(parser.parse());
 
     return llintGenerator.finalize();
 }
 
-LLIntGenerator::LLIntGenerator(const ModuleInformation& info, unsigned functionIndex, ThrowWasmException throwWasmException, const Signature&)
+LLIntGenerator::LLIntGenerator(const ModuleInformation& info, unsigned functionIndex, const Signature&)
     : BytecodeGeneratorBase(makeUnique<FunctionCodeBlock>(functionIndex), 0)
     , m_info(info)
     , m_functionIndex(functionIndex)
@@ -423,9 +433,6 @@ LLIntGenerator::LLIntGenerator(const ModuleInformation& info, unsigned functionI
     m_stackSize = numberOfLLIntCalleeSaveRegisters;
     m_maxStackSize = numberOfLLIntCalleeSaveRegisters;
 
-    if (throwWasmException)
-        Thunks::singleton().setThrowWasmException(throwWasmException);
-
     WasmEnter::emit(this);
 }
 
@@ -518,8 +525,8 @@ auto LLIntGenerator::callInformationForCaller(const Signature& signature) -> LLI
         m_maxStackSize = m_stackSize;
 
 
-    ExpressionList arguments(signature.argumentCount());
-    ExpressionList temporaryResults(signature.returnCount());
+    ResultList arguments(signature.argumentCount());
+    ResultList temporaryResults(signature.returnCount());
 
     const unsigned stackOffset = m_stackSize;
     const unsigned base = stackOffset - CallFrame::headerSizeInRegisters;
@@ -583,7 +590,7 @@ auto LLIntGenerator::callInformationForCaller(const Signature& signature) -> LLI
 
     m_stackSize = initialStackSize;
 
-    auto commitResults = [this, temporaryResults = WTFMove(temporaryResults)](ExpressionList& results) {
+    auto commitResults = [this, temporaryResults = WTFMove(temporaryResults)](ResultList& results) {
         for (auto temporaryResult : temporaryResults) {
             ExpressionType result = push();
             WasmMov::emit(this, result, temporaryResult);
@@ -689,16 +696,15 @@ auto LLIntGenerator::addArguments(const Signature& signature) -> PartialResult
 auto LLIntGenerator::addLocal(Type type, uint32_t count) -> PartialResult
 {
     m_codeBlock->m_numVars += count;
-    while (count--) {
-        auto local = push();
-        switch (type) {
-        case Type::Anyref:
-        case Type::Funcref:
-            m_unitializedLocals.append(local);
-            break;
-        default:
-            break;
-        }
+    switch (type) {
+    case Type::Anyref:
+    case Type::Funcref:
+        while (count--)
+            m_unitializedLocals.append(push());
+        break;
+    default:
+        m_stackSize += count;
+        break;
     }
     return { };
 }
@@ -750,11 +756,11 @@ auto LLIntGenerator::setLocal(uint32_t index, ExpressionType value) -> PartialRe
     VirtualRegister target = virtualRegisterForWasmLocal(index);
 
     // If this local is currently on the stack we need to materialize it, otherwise it'll see the new value instead of the old one
-    walkExpressionStack(m_parser->expressionStack(), [&](VirtualRegister& expression, VirtualRegister slot) {
-        if (expression != target)
+    walkExpressionStack(m_parser->expressionStack(), [&](TypedExpression& expression, VirtualRegister slot) {
+        if (expression.value() != target)
             return;
         WasmMov::emit(this, slot, expression);
-        expression = slot;
+        expression = TypedExpression { expression.type(), slot };
     });
 
     WasmMov::emit(this, target, value);
@@ -800,7 +806,7 @@ auto LLIntGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialR
 
 auto LLIntGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, ControlType& block, Stack& newStack, uint32_t loopIndex) -> PartialResult
 {
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     materializeConstantsAndLocals(newStack);
 
     Ref<Label> body = newEmittedLabel();
@@ -819,7 +825,7 @@ auto LLIntGenerator::addLoop(BlockSignature signature, Stack& enclosingStack, Co
         osrEntryData.append(virtualRegisterForLocal(i));
     for (unsigned controlIndex = 0; controlIndex < m_parser->controlStack().size(); ++controlIndex) {
         Stack& expressionStack = m_parser->controlStack()[controlIndex].enclosedExpressionStack;
-        for (auto& expression : expressionStack)
+        for (TypedExpression expression : expressionStack)
             osrEntryData.append(expression);
     }
 
@@ -837,7 +843,7 @@ auto LLIntGenerator::addTopLevel(BlockSignature signature) -> ControlType
 
 auto LLIntGenerator::addBlock(BlockSignature signature, Stack& enclosingStack, ControlType& newBlock, Stack& newStack) -> PartialResult
 {
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     newBlock = ControlType::block(signature, m_stackSize, newLabel());
     return { };
 }
@@ -847,7 +853,7 @@ auto LLIntGenerator::addIf(ExpressionType condition, BlockSignature signature, S
     Ref<Label> alternate = newLabel();
     Ref<Label> continuation = newLabel();
 
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
 
     WasmJfalse::emit(this, condition, alternate->bind(this));
 
@@ -967,8 +973,11 @@ auto LLIntGenerator::addEndToUnreachable(ControlEntry& entry, const Stack& expre
         // since they might not have the right number of values in the expression stack.
         // Instead, we do a stricter consistency check below.
         auto tmp = push(NoConsistencyCheck);
-        ASSERT_UNUSED(expressionStack, unreachable || tmp == expressionStack[i]);
-        entry.enclosedExpressionStack.append(tmp);
+        ASSERT(unreachable || tmp == expressionStack[i].value());
+        if (unreachable)
+            entry.enclosedExpressionStack.constructAndAppend(data.m_signature->returnType(i), tmp);
+        else
+            entry.enclosedExpressionStack.append(expressionStack[i]);
     }
 
     if (m_lastOpcodeID == wasm_jmp && data.m_continuation->unresolvedJumps().size() == 1 && data.m_continuation->unresolvedJumps()[0] == static_cast<int>(m_lastInstruction.offset())) {
@@ -996,7 +1005,7 @@ auto LLIntGenerator::endTopLevel(BlockSignature signature, const Stack& expressi
     return { };
 }
 
-auto LLIntGenerator::addCall(uint32_t functionIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionList& results) -> PartialResult
+auto LLIntGenerator::addCall(uint32_t functionIndex, const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
 {
     ASSERT(signature.argumentCount() == args.size());
     LLIntCallInformation info = callInformationForCaller(signature);
@@ -1010,7 +1019,7 @@ auto LLIntGenerator::addCall(uint32_t functionIndex, const Signature& signature,
     return { };
 }
 
-auto LLIntGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionList& results) -> PartialResult
+auto LLIntGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ResultList& results) -> PartialResult
 {
     ExpressionType calleeIndex = args.takeLast();
 
index ed5078b..89cdc71 100644 (file)
@@ -33,7 +33,7 @@ namespace JSC { namespace Wasm {
 
 class FunctionCodeBlock;
 
-Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileBytecode(const uint8_t*, size_t, const Signature&, const ModuleInformation&, uint32_t functionIndex, ThrowWasmException = nullptr);
+Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileBytecode(const uint8_t*, size_t, const Signature&, const ModuleInformation&, uint32_t functionIndex);
 
 } } // namespace JSC::Wasm
 
index bceeb28..cae57ed 100644 (file)
@@ -31,6 +31,7 @@
 #include "B3Compilation.h"
 #include "BytecodeDumper.h"
 #include "CalleeBits.h"
+#include "JSToWasm.h"
 #include "LLIntThunks.h"
 #include "LinkBuffer.h"
 #include "WasmCallee.h"
@@ -44,6 +45,22 @@ namespace WasmLLIntPlanInternal {
 static const bool verbose = false;
 }
 
+LLIntPlan::LLIntPlan(Context* context, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task)
+    : Base(context, WTFMove(source), work, WTFMove(task))
+{
+    if (parseAndValidateModule(m_source.data(), m_source.size()))
+        prepare();
+}
+
+LLIntPlan::LLIntPlan(Context* context, Ref<ModuleInformation> info, const Ref<LLIntCallee>* callees, CompletionTask&& task)
+    : Base(context, WTFMove(info), AsyncWork::FullCompile, WTFMove(task))
+    , m_callees(callees)
+{
+    ASSERT(m_callees);
+    prepare();
+    m_currentIndex = m_moduleInformation->functions.size();
+}
+
 bool LLIntPlan::prepareImpl()
 {
     const auto& functions = m_moduleInformation->functions;
@@ -62,10 +79,9 @@ void LLIntPlan::compileFunction(uint32_t functionIndex)
     const Signature& signature = SignatureInformation::get(signatureIndex);
     unsigned functionIndexSpace = m_wasmToWasmExitStubs.size() + functionIndex;
     ASSERT_UNUSED(functionIndexSpace, m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace) == signatureIndex);
-    ASSERT(validateFunction(function, signature, m_moduleInformation.get()));
 
     m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
-    Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileResult = parseAndCompileBytecode(function.data.data(), function.data.size(), signature, m_moduleInformation.get(), functionIndex, m_throwWasmException);
+    Expected<std::unique_ptr<FunctionCodeBlock>, String> parseAndCompileResult = parseAndCompileBytecode(function.data.data(), function.data.size(), signature, m_moduleInformation.get(), functionIndex);
 
     if (UNLIKELY(!parseAndCompileResult)) {
         auto locker = holdLock(m_lock);
@@ -78,41 +94,15 @@ void LLIntPlan::compileFunction(uint32_t functionIndex)
     }
 
     m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
-
-    if (m_exportedFunctionIndices.contains(functionIndex) || m_moduleInformation->referencedFunctions().contains(functionIndex)) {
-        EmbederToWasmFunction entry;
-        entry.jit = makeUnique<CCallHelpers>();
-        entry.function = m_createEmbedderWrapper(*entry.jit, signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex);
-        auto locker = holdLock(m_lock);
-        auto result = m_embedderToWasmInternalFunctions.add(functionIndex, WTFMove(entry));
-        ASSERT_UNUSED(result, result.isNewEntry);
-    }
 }
 
 void LLIntPlan::didCompleteCompilation(const AbstractLocker& locker)
 {
-    for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functions.size(); functionIndex++) {
-        SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
-        const Signature& signature = SignatureInformation::get(signatureIndex);
-
-        if (auto it = m_embedderToWasmInternalFunctions.find(functionIndex); it != m_embedderToWasmInternalFunctions.end()) {
-            LinkBuffer linkBuffer(*it->value.jit, nullptr, JITCompilationCanFail);
-            if (UNLIKELY(linkBuffer.didFailToAllocate())) {
-                Base::fail(locker, makeString("Out of executable memory in function entrypoint at index ", String::number(functionIndex)));
-                return;
-            }
-
-            it->value.function->entrypoint.compilation = makeUnique<B3::Compilation>(
-                FINALIZE_CODE(linkBuffer, B3CompilationPtrTag, "Embedder->WebAssembly entrypoint[%i] %s", functionIndex, signature.toString().ascii().data()),
-                nullptr);
-        }
-    }
-
     unsigned functionCount = m_wasmInternalFunctions.size();
-    if (functionCount) {
+    if (!m_callees && functionCount) {
         // LLInt entrypoint thunks generation
         CCallHelpers jit;
-        m_callees.resize(functionCount);
+        m_calleesVector.resize(functionCount);
         Vector<CCallHelpers::Label> entrypoints(functionCount);
         Vector<CCallHelpers::Jump> jumps(functionCount);
         for (unsigned i = 0; i < functionCount; ++i) {
@@ -121,7 +111,7 @@ void LLIntPlan::didCompleteCompilation(const AbstractLocker& locker)
             if (UNLIKELY(Options::dumpGeneratedWasmBytecodes()))
                 BytecodeDumper::dumpBlock(m_wasmInternalFunctions[i].get(), m_moduleInformation, WTF::dataFile());
 
-            m_callees[i] = Wasm::LLIntCallee::create(WTFMove(m_wasmInternalFunctions[i]), functionIndexSpace, m_moduleInformation->nameSection->get(functionIndexSpace));
+            m_calleesVector[i] = LLIntCallee::create(WTFMove(m_wasmInternalFunctions[i]), functionIndexSpace, m_moduleInformation->nameSection->get(functionIndexSpace));
             entrypoints[i] = jit.label();
 #if CPU(X86_64)
             CCallHelpers::Address calleeSlot(CCallHelpers::stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) - sizeof(CPURegister));
@@ -130,7 +120,7 @@ void LLIntPlan::didCompleteCompilation(const AbstractLocker& locker)
 #else
 #error Unsupported architecture.
 #endif
-            jit.storePtr(CCallHelpers::TrustedImmPtr(CalleeBits::boxWasm(m_callees[i].ptr())), calleeSlot);
+            jit.storePtr(CCallHelpers::TrustedImmPtr(CalleeBits::boxWasm(m_calleesVector[i].ptr())), calleeSlot);
             jumps[i] = jit.jump();
         }
 
@@ -141,18 +131,51 @@ void LLIntPlan::didCompleteCompilation(const AbstractLocker& locker)
         }
 
         for (unsigned i = 0; i < functionCount; ++i) {
-            m_callees[i]->setEntrypoint(linkBuffer.locationOf<WasmEntryPtrTag>(entrypoints[i]));
+            m_calleesVector[i]->setEntrypoint(linkBuffer.locationOf<WasmEntryPtrTag>(entrypoints[i]));
             linkBuffer.link<JITThunkPtrTag>(jumps[i], CodeLocationLabel<JITThunkPtrTag>(LLInt::wasmFunctionEntryThunk().code()));
         }
 
         m_entryThunks = FINALIZE_CODE(linkBuffer, B3CompilationPtrTag, "Wasm LLInt entry thunks");
+        m_callees = m_calleesVector.data();
+    }
+
+    if (m_asyncWork == AsyncWork::Validation)
+        return;
+
+    for (uint32_t functionIndex = 0; functionIndex < m_moduleInformation->functions.size(); functionIndex++) {
+        if (m_exportedFunctionIndices.contains(functionIndex) || m_moduleInformation->referencedFunctions().contains(functionIndex)) {
+            SignatureIndex signatureIndex = m_moduleInformation->internalFunctionSignatureIndices[functionIndex];
+            const Signature& signature = SignatureInformation::get(signatureIndex);
+            CCallHelpers jit;
+            std::unique_ptr<InternalFunction> function = createJSToWasmWrapper(jit, signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex);
+
+            LinkBuffer linkBuffer(jit, nullptr, JITCompilationCanFail);
+            if (UNLIKELY(linkBuffer.didFailToAllocate())) {
+                Base::fail(locker, makeString("Out of executable memory in function entrypoint at index ", String::number(functionIndex)));
+                return;
+            }
+
+            function->entrypoint.compilation = makeUnique<B3::Compilation>(
+                FINALIZE_CODE(linkBuffer, B3CompilationPtrTag, "Embedder->WebAssembly entrypoint[%i] %s", functionIndex, signature.toString().ascii().data()),
+                nullptr);
+
+            Ref<EmbedderEntrypointCallee> callee = EmbedderEntrypointCallee::create(WTFMove(function->entrypoint));
+            // FIXME: remove this repatchPointer - just pass in the callee directly
+            // https://bugs.webkit.org/show_bug.cgi?id=166462
+            if (function->calleeMoveLocation)
+                MacroAssembler::repatchPointer(function->calleeMoveLocation, CalleeBits::boxWasm(callee.ptr()));
+
+            auto result = m_embedderCallees.add(functionIndex, WTFMove(callee));
+            ASSERT_UNUSED(result, result.isNewEntry);
+        }
     }
 
     for (auto& unlinked : m_unlinkedWasmToWasmCalls) {
         for (auto& call : unlinked) {
             MacroAssemblerCodePtr<WasmEntryPtrTag> executableAddress;
             if (m_moduleInformation->isImportedFunctionFromFunctionIndexSpace(call.functionIndexSpace)) {
-                // FIXME imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT. https://bugs.webkit.org/show_bug.cgi?id=166462
+                // FIXME: imports could have been linked in B3, instead of generating a patchpoint. This condition should be replaced by a RELEASE_ASSERT.
+                // https://bugs.webkit.org/show_bug.cgi?id=166462
                 executableAddress = m_wasmToWasmExitStubs.at(call.functionIndexSpace).code();
             } else
                 executableAddress = m_callees[call.functionIndexSpace - m_moduleInformation->importFunctionCount()]->entrypoint();
@@ -161,21 +184,25 @@ void LLIntPlan::didCompleteCompilation(const AbstractLocker& locker)
     }
 }
 
-void LLIntPlan::initializeCallees(const CalleeInitializer& callback)
+void LLIntPlan::work(CompilationEffort effort)
 {
-    ASSERT(!failed());
-    for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
-        RefPtr<Wasm::Callee> embedderEntrypointCallee;
-        if (auto it = m_embedderToWasmInternalFunctions.find(internalFunctionIndex); it != m_embedderToWasmInternalFunctions.end()) {
-            embedderEntrypointCallee = Wasm::EmbedderEntrypointCallee::create(WTFMove(it->value.function->entrypoint));
-            if (it->value.function->calleeMoveLocation)
-                MacroAssembler::repatchPointer(it->value.function->calleeMoveLocation, CalleeBits::boxWasm(embedderEntrypointCallee.get()));
-        }
-
-        callback(internalFunctionIndex, WTFMove(embedderEntrypointCallee), WTFMove(m_callees[internalFunctionIndex]));
+    switch (m_state) {
+    case State::Prepared:
+        compileFunctions(effort);
+        break;
+    case State::Compiled:
+        break;
+    default:
+        break;
     }
 }
 
+bool LLIntPlan::didReceiveFunctionData(unsigned, const FunctionData&)
+{
+    // Validation is done inline by the parser
+    return true;
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)
index 6c91d27..42de813 100644 (file)
@@ -37,14 +37,16 @@ class CallLinkInfo;
 namespace Wasm {
 
 class LLIntCallee;
+class EmbedderEntrypointCallee;
+
+using EmbedderEntrypointCalleeMap = HashMap<uint32_t, RefPtr<EmbedderEntrypointCallee>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>>;
 
 class LLIntPlan final : public EntryPlan {
-public:
     using Base = EntryPlan;
 
-    using Base::Base;
-
-    void initializeCallees(const CalleeInitializer&) override;
+public:
+    JS_EXPORT_PRIVATE LLIntPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&);
+    LLIntPlan(Context*, Ref<ModuleInformation>, const Ref<LLIntCallee>*, CompletionTask&&);
 
     MacroAssemblerCodeRef<B3CompilationPtrTag>&& takeEntryThunks()
     {
@@ -52,20 +54,37 @@ public:
         return WTFMove(m_entryThunks);
     }
 
+    Vector<Ref<LLIntCallee>>&& takeCallees()
+    {
+        RELEASE_ASSERT(!failed() && !hasWork());
+        return WTFMove(m_calleesVector);
+    }
+
+    EmbedderEntrypointCalleeMap&& takeEmbedderCallees()
+    {
+        RELEASE_ASSERT(!failed() && !hasWork());
+        return WTFMove(m_embedderCallees);
+    }
+
+    bool hasWork() const override
+    {
+        return m_state < State::Compiled;
+    }
+
+    void work(CompilationEffort) override;
+
+    bool didReceiveFunctionData(unsigned, const FunctionData&) override;
+
 protected:
     bool prepareImpl() override;
     void compileFunction(uint32_t functionIndex) override;
     void didCompleteCompilation(const AbstractLocker&) override;
 
 private:
-    struct EmbederToWasmFunction {
-        std::unique_ptr<CCallHelpers> jit;
-        std::unique_ptr<InternalFunction> function;
-    };
-
     Vector<std::unique_ptr<FunctionCodeBlock>> m_wasmInternalFunctions;
-    Vector<Ref<LLIntCallee>> m_callees;
-    HashMap<uint32_t, EmbederToWasmFunction, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderToWasmInternalFunctions;
+    const Ref<LLIntCallee>* m_callees { nullptr };
+    Vector<Ref<LLIntCallee>> m_calleesVector;
+    EmbedderEntrypointCalleeMap m_embedderCallees;
     MacroAssemblerCodeRef<B3CompilationPtrTag> m_entryThunks;
 };
 
index 44a2743..3c8432e 100644 (file)
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "WasmBBQPlan.h"
 #include "WasmLLIntPlan.h"
 #include "WasmModuleInformation.h"
 #include "WasmWorklist.h"
 
 namespace JSC { namespace Wasm {
 
-Module::Module(Ref<ModuleInformation>&& moduleInformation)
-    : m_moduleInformation(WTFMove(moduleInformation))
+Module::Module(LLIntPlan& plan)
+    : m_moduleInformation(plan.takeModuleInformation())
+    , m_llintCallees(plan.takeCallees())
+    , m_llintEntryThunks(plan.takeEntryThunks())
+{
+}
+
+Module::Module(BBQPlan& plan)
+    : m_moduleInformation(plan.takeModuleInformation())
 {
 }
 
@@ -46,36 +54,50 @@ Wasm::SignatureIndex Module::signatureIndexFromFunctionIndexSpace(unsigned funct
     return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
 }
 
-static Module::ValidationResult makeValidationResult(EntryPlan& plan)
+template<typename Plan>
+static Module::ValidationResult makeValidationResult(Plan& plan)
 {
     ASSERT(!plan.hasWork());
     if (plan.failed())
         return Unexpected<String>(plan.errorMessage());
-    return Module::ValidationResult(Module::create(plan.takeModuleInformation()));
+    return Module::ValidationResult(Module::create(plan));
 }
 
+template<typename PlanT>
 static Plan::CompletionTask makeValidationCallback(Module::AsyncValidationCallback&& callback)
 {
     return createSharedTask<Plan::CallbackType>([callback = WTFMove(callback)] (Plan& plan) {
         ASSERT(!plan.hasWork());
-        callback->run(makeValidationResult(static_cast<LLIntPlan&>(plan)));
+        callback->run(makeValidationResult(static_cast<PlanT&>(plan)));
     });
 }
 
 Module::ValidationResult Module::validateSync(Context* context, Vector<uint8_t>&& source)
 {
-    Ref<LLIntPlan> plan = adoptRef(*new LLIntPlan(context, WTFMove(source), EntryPlan::Validation, Plan::dontFinalize(), nullptr, nullptr));
+    if (Options::useWasmLLInt()) {
+        Ref<LLIntPlan> plan = adoptRef(*new LLIntPlan(context, WTFMove(source), EntryPlan::Validation, Plan::dontFinalize()));
+        Wasm::ensureWorklist().enqueue(plan.get());
+        plan->waitForCompletion();
+        return makeValidationResult(plan.get());
+    }
+
+    Ref<BBQPlan> plan = adoptRef(*new BBQPlan(context, WTFMove(source), EntryPlan::Validation, Plan::dontFinalize()));
     plan->parseAndValidateModule();
     return makeValidationResult(plan.get());
 }
 
 void Module::validateAsync(Context* context, Vector<uint8_t>&& source, Module::AsyncValidationCallback&& callback)
 {
-    Ref<Plan> plan = adoptRef(*new LLIntPlan(context, WTFMove(source), EntryPlan::Validation, makeValidationCallback(WTFMove(callback)), nullptr, nullptr));
-    Wasm::ensureWorklist().enqueue(WTFMove(plan));
+    if (Options::useWasmLLInt()) {
+        Ref<Plan> plan = adoptRef(*new LLIntPlan(context, WTFMove(source), EntryPlan::Validation, makeValidationCallback<LLIntPlan>(WTFMove(callback))));
+        Wasm::ensureWorklist().enqueue(WTFMove(plan));
+    } else {
+        Ref<Plan> plan = adoptRef(*new BBQPlan(context, WTFMove(source), EntryPlan::Validation, makeValidationCallback<BBQPlan>(WTFMove(callback))));
+        Wasm::ensureWorklist().enqueue(WTFMove(plan));
+    }
 }
 
-Ref<CodeBlock> Module::getOrCreateCodeBlock(Context* context, MemoryMode mode, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+Ref<CodeBlock> Module::getOrCreateCodeBlock(Context* context, MemoryMode mode)
 {
     RefPtr<CodeBlock> codeBlock;
     auto locker = holdLock(m_lock);
@@ -86,22 +108,25 @@ Ref<CodeBlock> Module::getOrCreateCodeBlock(Context* context, MemoryMode mode, C
     // FIXME: We might want to back off retrying at some point:
     // https://bugs.webkit.org/show_bug.cgi?id=170607
     if (!codeBlock || (codeBlock->compilationFinished() && !codeBlock->runnable())) {
-        codeBlock = CodeBlock::create(context, mode, const_cast<ModuleInformation&>(moduleInformation()), WTFMove(createEmbedderWrapper), throwWasmException);
+        const Ref<LLIntCallee>* llintCallees = nullptr;
+        if (Options::useWasmLLInt())
+            llintCallees = m_llintCallees.data();
+        codeBlock = CodeBlock::create(context, mode, const_cast<ModuleInformation&>(moduleInformation()), llintCallees);
         m_codeBlocks[static_cast<uint8_t>(mode)] = codeBlock;
     }
     return codeBlock.releaseNonNull();
 }
 
-Ref<CodeBlock> Module::compileSync(Context* context, MemoryMode mode, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+Ref<CodeBlock> Module::compileSync(Context* context, MemoryMode mode)
 {
-    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode, WTFMove(createEmbedderWrapper), throwWasmException);
+    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode);
     codeBlock->waitUntilFinished();
     return codeBlock;
 }
 
-void Module::compileAsync(Context* context, MemoryMode mode, CodeBlock::AsyncCompilationCallback&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+void Module::compileAsync(Context* context, MemoryMode mode, CodeBlock::AsyncCompilationCallback&& task)
 {
-    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode, WTFMove(createEmbedderWrapper), throwWasmException);
+    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode);
     codeBlock->compileAsync(context, WTFMove(task));
 }
 
index 652ddd3..2dadb6a 100644 (file)
 
 namespace JSC { namespace Wasm {
 
+class BBQPlan;
+class LLIntPlan;
 struct Context;
 struct ModuleInformation;
-class Plan;
 
 using SignatureIndex = uint64_t;
 
@@ -52,26 +53,34 @@ public:
     static ValidationResult validateSync(Context*, Vector<uint8_t>&& source);
     static void validateAsync(Context*, Vector<uint8_t>&& source, Module::AsyncValidationCallback&&);
 
-    static Ref<Module> create(Ref<ModuleInformation>&& moduleInformation)
+    static Ref<Module> create(BBQPlan& plan)
     {
-        return adoptRef(*new Module(WTFMove(moduleInformation)));
+        return adoptRef(*new Module(plan));
+    }
+
+    static Ref<Module> create(LLIntPlan& plan)
+    {
+        return adoptRef(*new Module(plan));
     }
 
     Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const;
     const Wasm::ModuleInformation& moduleInformation() const { return m_moduleInformation.get(); }
 
-    Ref<CodeBlock> compileSync(Context*, MemoryMode, CreateEmbedderWrapper&&, ThrowWasmException);
-    void compileAsync(Context*, MemoryMode, CodeBlock::AsyncCompilationCallback&&, CreateEmbedderWrapper&&, ThrowWasmException);
+    Ref<CodeBlock> compileSync(Context*, MemoryMode);
+    void compileAsync(Context*, MemoryMode, CodeBlock::AsyncCompilationCallback&&);
 
     JS_EXPORT_PRIVATE ~Module();
 
     CodeBlock* codeBlockFor(MemoryMode mode) { return m_codeBlocks[static_cast<uint8_t>(mode)].get(); }
 private:
-    Ref<CodeBlock> getOrCreateCodeBlock(Context*, MemoryMode, CreateEmbedderWrapper&&, ThrowWasmException);
+    Ref<CodeBlock> getOrCreateCodeBlock(Context*, MemoryMode);
 
-    Module(Ref<ModuleInformation>&&);
+    Module(BBQPlan&);
+    Module(LLIntPlan&);
     Ref<ModuleInformation> m_moduleInformation;
     RefPtr<CodeBlock> m_codeBlocks[Wasm::NumberOfMemoryModes];
+    Vector<Ref<LLIntCallee>> m_llintCallees;
+    MacroAssemblerCodeRef<B3CompilationPtrTag> m_llintEntryThunks;
     Lock m_lock;
 };
 
index 6f4ddca..5d49c3e 100644 (file)
@@ -122,10 +122,11 @@ void OMGPlan::work(CompilationEffort)
                 bbqCallee->setReplacement(callee.copyRef());
                 bbqCallee->tierUpCount()->m_compilationStatusForOMG = TierUpCount::CompilationStatus::Compiled;
             }
-            if (LLIntCallee* llintCallee = m_codeBlock->m_llintCallees[m_functionIndex].get()) {
-                auto locker = holdLock(llintCallee->tierUpCounter().m_lock);
-                llintCallee->setReplacement(callee.copyRef());
-                llintCallee->tierUpCounter().m_compilationStatus = LLIntTierUpCounter::CompilationStatus::Compiled;
+            if (m_codeBlock->m_llintCallees) {
+                LLIntCallee& llintCallee = m_codeBlock->m_llintCallees[m_functionIndex].get();
+                auto locker = holdLock(llintCallee.tierUpCounter().m_lock);
+                llintCallee.setReplacement(callee.copyRef());
+                llintCallee.tierUpCounter().m_compilationStatus = LLIntTierUpCounter::CompilationStatus::Compiled;
             }
         }
         for (auto& call : callee->wasmToWasmCallsites()) {
@@ -161,10 +162,11 @@ void OMGPlan::work(CompilationEffort)
 
         for (unsigned i = 0; i < m_codeBlock->m_wasmToWasmCallsites.size(); ++i) {
             repatchCalls(m_codeBlock->m_wasmToWasmCallsites[i]);
-            if (LLIntCallee* llintCallee = m_codeBlock->m_llintCallees[i].get()) {
-                if (JITCallee* replacementCallee = llintCallee->replacement())
+            if (m_codeBlock->m_llintCallees) {
+                LLIntCallee& llintCallee = m_codeBlock->m_llintCallees[i].get();
+                if (JITCallee* replacementCallee = llintCallee.replacement())
                     repatchCalls(replacementCallee->wasmToWasmCallsites());
-                if (OMGForOSREntryCallee* osrEntryCallee = llintCallee->osrEntryCallee())
+                if (OMGForOSREntryCallee* osrEntryCallee = llintCallee.osrEntryCallee())
                     repatchCalls(osrEntryCallee->wasmToWasmCallsites());
             }
             if (BBQCallee* bbqCallee = m_codeBlock->m_bbqCallees[i].get()) {
index 1ed6cff..5a53b95 100644 (file)
@@ -48,19 +48,11 @@ namespace WasmPlanInternal {
 static constexpr bool verbose = false;
 }
 
-Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task)
     : m_moduleInformation(WTFMove(info))
-    , m_createEmbedderWrapper(WTFMove(createEmbedderWrapper))
-    , m_throwWasmException(throwWasmException)
 {
     m_completionTasks.append(std::make_pair(context, WTFMove(task)));
 }
-
-Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task)
-    : Plan(context, WTFMove(info), WTFMove(task), nullptr, nullptr)
-{
-}
-
 Plan::Plan(Context* context, CompletionTask&& task)
     : m_moduleInformation(ModuleInformation::create())
 {
index 111234f..9be6ce2 100644 (file)
@@ -51,7 +51,6 @@ public:
     using CompletionTask = RefPtr<SharedTask<CallbackType>>;
 
     static CompletionTask dontFinalize() { return createSharedTask<CallbackType>([](Plan&) { }); }
-    Plan(Context*, Ref<ModuleInformation>, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
     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
@@ -88,9 +87,6 @@ protected:
 
     Vector<std::pair<Context*, CompletionTask>, 1> m_completionTasks;
 
-    CreateEmbedderWrapper m_createEmbedderWrapper;
-    ThrowWasmException m_throwWasmException { nullptr };
-
     String m_errorMessage;
     MemoryMode m_mode { MemoryMode::BoundsChecking };
     Lock m_lock;
index a5248fd..5a8ebb8 100644 (file)
@@ -411,7 +411,7 @@ WASM_SLOW_PATH_DECL(set_global_ref_portable_binding)
 extern "C" SlowPathReturnType slow_path_wasm_throw_exception(CallFrame* callFrame, const Instruction* pc, Wasm::Instance* instance, Wasm::ExceptionType exceptionType)
 {
     UNUSED_PARAM(pc);
-    WASM_RETURN_TWO(Wasm::Thunks::singleton().throwWasmException()(callFrame, exceptionType, instance), 0);
+    WASM_RETURN_TWO(operationWasmToJSException(callFrame, exceptionType, instance), 0);
 }
 
 extern "C" SlowPathReturnType slow_path_wasm_popcount(const Instruction* pc, uint32_t x)
index f2b3ee1..f934f1a 100644 (file)
@@ -56,10 +56,8 @@ MacroAssemblerCodeRef<JITThunkPtrTag> throwExceptionFromWasmThunkGenerator(const
     jit.farJump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
     jit.breakpoint(); // We should not reach this.
 
-    ThrowWasmException throwWasmException = Thunks::singleton().throwWasmException();
-    RELEASE_ASSERT(throwWasmException);
     LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
-    linkBuffer.link(call, FunctionPtr<OperationPtrTag>(throwWasmException));
+    linkBuffer.link(call, FunctionPtr<OperationPtrTag>(operationWasmToJSException));
     return FINALIZE_WASM_CODE(linkBuffer, JITThunkPtrTag, "Throw exception from Wasm");
 }
 
@@ -113,19 +111,6 @@ Thunks& Thunks::singleton()
     return *thunks;
 }
 
-void Thunks::setThrowWasmException(ThrowWasmException throwWasmException)
-{
-    auto locker = holdLock(m_lock);
-    // The thunks are unique for the entire process, therefore changing the throwing function changes it for all uses of WebAssembly.
-    RELEASE_ASSERT(!m_throwWasmException || m_throwWasmException == throwWasmException);
-    m_throwWasmException = throwWasmException;
-}
-
-ThrowWasmException Thunks::throwWasmException()
-{
-    return m_throwWasmException;
-}
-
 MacroAssemblerCodeRef<JITThunkPtrTag> Thunks::stub(ThunkGenerator generator)
 {
     auto locker = holdLock(m_lock);
index 81cc669..a28aba9 100644 (file)
@@ -45,9 +45,6 @@ public:
     static void initialize();
     static Thunks& singleton();
 
-    void setThrowWasmException(ThrowWasmException);
-    ThrowWasmException throwWasmException();
-
     MacroAssemblerCodeRef<JITThunkPtrTag> stub(ThunkGenerator);
     MacroAssemblerCodeRef<JITThunkPtrTag> stub(const AbstractLocker&, ThunkGenerator);
     MacroAssemblerCodeRef<JITThunkPtrTag> existingStub(ThunkGenerator);
@@ -56,7 +53,6 @@ private:
     Thunks() = default;
 
     HashMap<ThunkGenerator, MacroAssemblerCodeRef<JITThunkPtrTag>> m_stubs;
-    ThrowWasmException m_throwWasmException { nullptr };
     Lock m_lock;
 };
 
index 1b218e6..f9c0a3a 100644 (file)
@@ -46,6 +46,19 @@ public:
         {
         }
 
+        static bool isIf(const ControlData& control) { return control.blockType() == BlockType::If; }
+        static bool isTopLevel(const ControlData& control) { return control.blockType() == BlockType::TopLevel; }
+
+        BlockType blockType() const { return m_blockType; }
+        BlockSignature signature() const { return m_signature; }
+
+        unsigned branchTargetArity() const { return blockType() == BlockType::Loop ? signature()->argumentCount() : signature()->returnCount(); }
+        Type branchTargetType(unsigned i) const
+        {
+            ASSERT(i < branchTargetArity());
+            return blockType() == BlockType::Loop ? signature()->argument(i) : signature()->returnType(i);
+        }
+
         void dump(PrintStream& out) const
         {
             switch (blockType()) {
@@ -66,34 +79,24 @@ public:
             out.print(sig);
         }
 
-        BlockType blockType() const { return m_blockType; }
-        BlockSignature signature() const { return m_signature; }
-
-        unsigned branchTargetArity() const { return blockType() == BlockType::Loop ? signature()->argumentCount() : signature()->returnCount(); }
-        Type branchTargetType(unsigned i) const
-        {
-            ASSERT(i < branchTargetArity());
-            return blockType() == BlockType::Loop ? signature()->argument(i) : signature()->returnType(i);
-        }
-
     private:
         BlockType m_blockType;
         BlockSignature m_signature;
     };
 
-    typedef String ErrorType;
-    typedef Unexpected<ErrorType> UnexpectedResult;
-    typedef Expected<void, ErrorType> Result;
-    using ExpressionType = Type;
-    using ExpressionList = Vector<ExpressionType, 1>;
-    using Stack = ExpressionList;
-    typedef ControlData ControlType;
-    typedef ExpressionList ResultList;
-    typedef FunctionParser<Validate>::ControlEntry ControlEntry;
+    enum ExpressionType { EmptyExpression };
+
+    using ErrorType = String;
+    using UnexpectedResult = Unexpected<ErrorType>;
+    using Result = Expected<void, ErrorType>;
+    using ControlType = ControlData;
 
-    static constexpr ExpressionType emptyExpression() { return Void; }
-    Stack createStack() { return Stack(); }
-    bool isControlTypeIf(const ControlType& control) { return control.blockType() == BlockType::If; }
+    using ControlEntry = FunctionParser<Validate>::ControlEntry;
+    using ControlStack = FunctionParser<Validate>::ControlStack;
+    using ResultList = FunctionParser<Validate>::ResultList;
+    using Stack = FunctionParser<Validate>::Stack;
+
+    static ExpressionType emptyExpression() { return EmptyExpression; };
 
     template <typename ...Args>
     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(const Args&... args) const
@@ -113,18 +116,18 @@ public:
 
     Result WARN_UNUSED_RETURN addArguments(const Signature&);
     Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
-    ExpressionType addConstant(Type type, uint64_t) { return type; }
+    ExpressionType addConstant(Type, uint64_t) { return EmptyExpression; }
 
     // References
-    Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType value, ExpressionType& result);
     Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
-    Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
+    Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType index, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType index, ExpressionType value);
     Result WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result);
-    Result WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result);
-    Result WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count);
+    Result WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType fill, ExpressionType delta, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType offset, ExpressionType fill, ExpressionType count);
     // Locals
     Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -167,142 +170,81 @@ public:
     Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature&, const Vector<ExpressionType>& args, ResultList&);
     Result WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, const Vector<ExpressionType>& args, ResultList&);
 
-    bool hasMemory() const { return !!m_module.memory; }
-
-    Validate(const ModuleInformation& module)
-        : m_module(module)
+    Validate()
     {
     }
 
-    void dump(const Vector<ControlEntry>&, const Stack*);
+    void dump(const ControlStack&, const Stack*);
     void setParser(FunctionParser<Validate>*) { }
     void didFinishParsingLocals() { }
     void didPopValueFromStack() { }
 
 private:
     Result WARN_UNUSED_RETURN unify(const Stack&, const ControlData&);
-
-    Result WARN_UNUSED_RETURN checkBranchTarget(ControlData& target, const Stack& expressionStack);
-
-    Vector<Type> m_locals;
-    const ModuleInformation& m_module;
 };
 
-auto Validate::addArguments(const Signature& signature) -> Result
+auto Validate::addArguments(const Signature&) -> Result
 {
-    for (size_t i = 0; i < signature.argumentCount(); ++i)
-        WASM_FAIL_IF_HELPER_FAILS(addLocal(signature.argument(i), 1));
     return { };
 }
 
-auto Validate::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> Result
+auto Validate::addTableGet(unsigned, ExpressionType, ExpressionType&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
-    result = m_module.tables[tableIndex].wasmType();
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", makeString(index), " expected ", makeString(Type::I32));
-
     return { };
 }
 
-auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> Result
+auto Validate::addTableSet(unsigned, ExpressionType, ExpressionType) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
-    auto type = m_module.tables[tableIndex].wasmType();
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
-    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
-    RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Anyref || m_module.tables[tableIndex].type() == TableElementType::Funcref);
-
     return { };
 }
 
-auto Validate::addTableSize(unsigned tableIndex, ExpressionType& result) -> Result
+auto Validate::addTableSize(unsigned, ExpressionType&) -> Result
 {
-    result = Type::I32;
-    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
-
     return { };
 }
 
-auto Validate::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> Result
+auto Validate::addTableGrow(unsigned, ExpressionType, ExpressionType, ExpressionType&) -> Result
 {
-    result = Type::I32;
-    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
-    WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.grow expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill);
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != delta, "table.grow expects an i32 delta value, got ", makeString(delta));
-
     return { };
 }
 
-auto Validate::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> Result
+auto Validate::addTableFill(unsigned, ExpressionType, ExpressionType, ExpressionType) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
-    WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.fill expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill);
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != offset, "table.fill expects an i32 offset value, got ", makeString(offset));
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != count, "table.fill expects an i32 count value, got ", makeString(count));
-
     return { };
 }
 
-auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
+auto Validate::addRefIsNull(ExpressionType, ExpressionType&) -> Result
 {
-    result = Type::I32;
-    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, Type::Anyref), "ref.is_null to type ", makeString(value), " expected ", makeString(Type::Anyref));
-
     return { };
 }
 
-auto Validate::addRefFunc(uint32_t index, ExpressionType& result) -> Result
+auto Validate::addRefFunc(uint32_t, ExpressionType&) -> Result
 {
-    result = Type::Funcref;
-    WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_module.functionIndexSpaceSize());
-    m_module.addReferencedFunction(index);
-
     return { };
 }
 
-auto Validate::addLocal(Type type, uint32_t count) -> Result
+auto Validate::addLocal(Type, uint32_t) -> Result
 {
-    size_t newSize = m_locals.size() + count;
-    ASSERT(!(CheckedUint32(count) + m_locals.size()).hasOverflowed());
-    ASSERT(newSize <= maxFunctionLocals);
-    WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(newSize), "can't allocate memory for ", newSize, " locals");
-
-    for (uint32_t i = 0; i < count; ++i)
-        m_locals.uncheckedAppend(type);
     return { };
 }
 
-auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result
+auto Validate::getLocal(uint32_t, ExpressionType&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
-    result = m_locals[index];
     return { };
 }
 
-auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result
+auto Validate::setLocal(uint32_t, ExpressionType) -> Result
 {
-    ExpressionType localType;
-    WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
-    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, localType), "set_local to type ", value, " expected ", localType);
     return { };
 }
 
-auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result
+auto Validate::getGlobal(uint32_t, ExpressionType&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size());
-    result = m_module.globals[index].type;
-    ASSERT(isValueType(result));
     return { };
 }
 
-auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result
+auto Validate::setGlobal(uint32_t, ExpressionType) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size());
-    WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == GlobalInformation::Immutable, "set_global ", index, " is immutable");
-
-    ExpressionType globalType = m_module.globals[index].type;
-    ASSERT(isValueType(globalType));
-    WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value);
     return { };
 }
 
@@ -311,178 +253,114 @@ Validate::ControlType Validate::addTopLevel(BlockSignature signature)
     return ControlData(BlockType::TopLevel, signature);
 }
 
-static Validate::Stack splitStack(BlockSignature signature, Validate::Stack& stack)
-{
-    Validate::Stack result;
-    result.reserveInitialCapacity(signature->argumentCount());
-    ASSERT(stack.size() >= signature->argumentCount());
-    unsigned offset = stack.size() - signature->argumentCount();
-    for (unsigned i = 0; i < signature->argumentCount(); ++i)
-        result.uncheckedAppend(stack[i + offset]);
-    stack.shrink(offset);
-    return result;
-}
-
 auto Validate::addBlock(BlockSignature signature, Stack& enclosingStack, ControlType& newBlock, Stack& newStack) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few values on stack for block. Block expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. Block has signature: ", *signature);
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     newBlock = ControlData(BlockType::Block, signature);
-    for (unsigned i = 0; i < signature->argumentCount(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
     return { };
 }
 
 auto Validate::addLoop(BlockSignature signature, Stack& enclosingStack, ControlType& loop, Stack& newStack, uint32_t) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few values on stack for loop block. Loop expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. Loop has signature: ", *signature);
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     loop = ControlData(BlockType::Loop, signature);
-    for (unsigned i = 0; i < signature->argumentCount(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
     return { };
 }
 
-auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result
+auto Validate::addSelect(ExpressionType, ExpressionType, ExpressionType, ExpressionType&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition);
-    WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero);
-    result = zero;
     return { };
 }
 
-auto Validate::addIf(ExpressionType condition, BlockSignature signature, Stack& enclosingStack, ControlType& result, Stack& newStack) -> Result
+auto Validate::addIf(ExpressionType, BlockSignature signature, Stack& enclosingStack, ControlType& result, Stack& newStack) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", makeString(condition));
-    WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few arguments on stack for if block. If expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. If block has signature: ", *signature);
-    newStack = splitStack(signature, enclosingStack);
+    splitStack(signature, enclosingStack, newStack);
     result = ControlData(BlockType::If, signature);
-    for (unsigned i = 0; i < signature->argumentCount(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
     return { };
 }
 
-auto Validate::addElse(ControlType& current, const Stack& values) -> Result
+auto Validate::addElse(ControlType& current, const Stack&) -> Result
 {
-    WASM_FAIL_IF_HELPER_FAILS(unify(values, current));
     return addElseToUnreachable(current);
 }
 
 auto Validate::addElseToUnreachable(ControlType& current) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(current.blockType() != BlockType::If, "else block isn't associated to an if");
     current = ControlData(BlockType::Block, current.signature());
     return { };
 }
 
-auto Validate::addReturn(ControlType& topLevel, const ExpressionList& returnValues) -> Result
+auto Validate::addReturn(ControlType&, const Stack&) -> Result
 {
-    ASSERT(topLevel.blockType() == BlockType::TopLevel);
-    return checkBranchTarget(topLevel, returnValues);
-}
-
-auto Validate::checkBranchTarget(ControlType& target, const Stack& expressionStack) -> Result
-{
-    if (!target.branchTargetArity())
-        return { };
-
-    WASM_VALIDATOR_FAIL_IF(expressionStack.size() < target.branchTargetArity(), target.blockType() == BlockType::TopLevel ? "branch out of function" : "branch to block", " on expression stack of size ", expressionStack.size(), ", but block, ", target , " expects ", target.branchTargetArity(), " values");
-
-
-    unsigned expressionStackOffset = expressionStack.size() - target.branchTargetArity();
-    for (unsigned i = 0; i < target.branchTargetArity(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(target.branchTargetType(i), expressionStack[expressionStackOffset + i]), "branch's stack type is not a subtype of block's type branch target type. Stack value has type", expressionStack[expressionStackOffset + i], " but branch target expects a value with subtype of ", target.branchTargetType(i), " at index ", i);
-
     return { };
 }
 
-auto Validate::addBranch(ControlType& target, ExpressionType condition, const Stack& stack) -> Result
+auto Validate::addBranch(ControlType&, ExpressionType, const Stack&) -> Result
 {
-    // Void means this is an unconditional branch.
-    WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition);
-    return checkBranchTarget(target, stack);
+    return { };
 }
 
-auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const Stack& expressionStack) -> Result
+auto Validate::addSwitch(ExpressionType, const Vector<ControlData*>&, ControlData&, const Stack&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition);
-
-    for (unsigned i = 0; i < targets.size(); ++i) {
-        auto* target = targets[i];
-        WASM_VALIDATOR_FAIL_IF(defaultTarget.branchTargetArity() != target->branchTargetArity(), "br_table target type size mismatch. Default has size: ", defaultTarget.branchTargetArity(), "but target: ", i, " has size: ", target->branchTargetArity());
-        for (unsigned type = 0; type < defaultTarget.branchTargetArity(); ++type)
-            WASM_VALIDATOR_FAIL_IF(!isSubtype(defaultTarget.branchTargetType(type), target->branchTargetType(type)), "br_table target type mismatch at offset ", type, " expected: ", defaultTarget.branchTargetType(type), " but saw: ", target->branchTargetType(type), " when targeting block", *target);
-    }
-
-    return checkBranchTarget(defaultTarget, expressionStack);
+    return { };
 }
 
-auto Validate::addGrowMemory(ExpressionType delta, ExpressionType& result) -> Result
+auto Validate::addGrowMemory(ExpressionType, ExpressionType&) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(delta != I32, "grow_memory with non-i32 delta argument has type: ", delta);
-    result = I32;
     return { };
 }
 
-auto Validate::addCurrentMemory(ExpressionType& result) -> Result
+auto Validate::addCurrentMemory(ExpressionType&) -> Result
 {
-    result = I32;
     return { };
 }
 
-auto Validate::endBlock(ControlEntry& entry, Stack& stack) -> Result
+auto Validate::endBlock(ControlEntry& entry, Stack&) -> Result
 {
-    WASM_FAIL_IF_HELPER_FAILS(unify(stack, entry.controlData));
     return addEndToUnreachable(entry);
 }
 
 auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
 {
     auto block = entry.controlData;
-    RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(block.blockType() != BlockType::If);
-
     for (unsigned i = 0; i < block.signature()->returnCount(); ++i)
-        entry.enclosedExpressionStack.append(block.signature()->returnType(i));
+        entry.enclosedExpressionStack.constructAndAppend(block.signature()->returnType(i), EmptyExpression);
     return { };
 }
 
-auto Validate::addCall(unsigned, const Signature& signature, const Vector<ExpressionType>& args, ResultList& results) -> Result
+auto Validate::addCall(unsigned, const Signature& signature, const Vector<ExpressionType>&, ResultList& results) -> Result
 {
-    RELEASE_ASSERT(signature.argumentCount() == args.size());
-
-    for (unsigned i = 0; i < args.size(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
-
     for (unsigned i = 0; i < signature.returnCount(); ++i)
-        results.append(signature.returnType(i));
+        results.append(EmptyExpression);
     return { };
 }
 
-auto Validate::addCallIndirect(unsigned tableIndex, const Signature& signature, const Vector<ExpressionType>& args, ResultList& results) -> Result
+auto Validate::addCallIndirect(unsigned, const Signature& signature, const Vector<ExpressionType>&, ResultList& results) -> Result
 {
-    RELEASE_ASSERT(tableIndex < m_module.tableCount());
-    RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Funcref);
-    const auto argumentCount = signature.argumentCount();
-    RELEASE_ASSERT(argumentCount == args.size() - 1);
-
-    for (unsigned i = 0; i < argumentCount; ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
-
-    WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
-
     for (unsigned i = 0; i < signature.returnCount(); ++i)
-        results.append(signature.returnType(i));
+        results.append(EmptyExpression);
     return { };
 }
 
-auto Validate::unify(const Stack& values, const ControlType& block) -> Result
+auto Validate::load(LoadOpType, ExpressionType, ExpressionType&, uint32_t) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(block.signature()->returnCount() != values.size(), " block with type: ", *block.signature(), " returns: ", block.signature()->returnCount(), " but stack has: ", values.size(), " values");
+    return { };
+}
 
-    for (unsigned i = 0; i < block.signature()->returnCount(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(values[i], block.signature()->returnType(i)), "control flow returns with unexpected type. ", values[i], " is not a subtype of ", block.signature()->returnType(i));
+auto Validate::store(StoreOpType, ExpressionType, ExpressionType, uint32_t) -> Result
+{
+    return { };
+}
+
+template<OpType>
+auto Validate::addOp(ExpressionType, ExpressionType&) -> Result
+{
+    return { };
+}
 
-    // WASM_VALIDATOR_FAIL_IF(values.size() != 1, "block with type: ", makeString(*block.signature()), " ends with a stack containing more than one value");
+template<OpType>
+auto Validate::addOp(ExpressionType, ExpressionType, ExpressionType&) -> Result
+{
     return { };
 }
 
@@ -490,10 +368,10 @@ static void dumpExpressionStack(const CommaPrinter& comma, const Validate::Stack
 {
     dataLog(comma, " ExpressionStack:");
     for (const auto& expression : expressionStack)
-        dataLog(comma, makeString(expression));
+        dataLog(comma, makeString(expression.type()));
 }
 
-void Validate::dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack)
+void Validate::dump(const ControlStack& controlStack, const Stack* expressionStack)
 {
     for (size_t i = controlStack.size(); i--;) {
         dataLog("  ", controlStack[i].controlData);
@@ -507,7 +385,7 @@ void Validate::dump(const Vector<ControlEntry>& controlStack, const Stack* expre
 
 Expected<void, String> validateFunction(const FunctionData& function, const Signature& signature, const ModuleInformation& module)
 {
-    Validate context(module);
+    Validate context;
     FunctionParser<Validate> validator(context, function.data.data(), function.data.size(), signature, module);
     WASM_FAIL_IF_HELPER_FAILS(validator.parse());
     return { };
@@ -515,6 +393,4 @@ Expected<void, String> validateFunction(const FunctionData& function, const Sign
 
 } } // namespace JSC::Wasm
 
-#include "WasmValidateInlines.h"
-
 #endif // ENABLE(WEBASSEMBLY)
index df8b3e8..fa716e2 100644 (file)
@@ -152,8 +152,12 @@ void Worklist::enqueue(Ref<Plan> plan)
     }
 
     dataLogLnIf(WasmWorklistInternal::verbose, "Enqueuing plan");
-    m_queue.enqueue({ Priority::Preparation, nextTicket(),  WTFMove(plan) });
-    m_planEnqueued->notifyOne(locker);
+    bool multiThreaded = plan->multiThreaded();
+    m_queue.enqueue({ multiThreaded ? Priority::Compilation : Priority::Preparation, nextTicket(),  WTFMove(plan) });
+    if (multiThreaded)
+        m_planEnqueued->notifyAll(locker);
+    else
+        m_planEnqueued->notifyOne(locker);
 }
 
 void Worklist::completePlanSynchronously(Plan& plan)
index b13a5e2..cb0281b 100755 (executable)
@@ -40,10 +40,16 @@ opcodes = wasm.opcodes
 wasmOpsHFile = open(args[2], "w")
 
 
-def cppMacro(wasmOpcode, value, b3, inc):
-    return " \\\n    macro(" + wasm.toCpp(wasmOpcode) + ", " + hex(int(value)) + ", " + b3 + ", " + str(inc) + ")"
+def cppType(type):
+    if type == "bool":
+        return "I32"
+    return type.capitalize()
 
 
+def cppMacro(wasmOpcode, value, b3, inc, *extraArgs):
+    extraArgsStr = ", " + ", ".join(extraArgs) if len(extraArgs) else ""
+    return " \\\n    macro(" + wasm.toCpp(wasmOpcode) + ", " + hex(int(value)) + ", " + b3 + ", " + str(inc) + extraArgsStr + ")"
+
 def typeMacroizer():
     inc = 0
     for ty in wasm.types:
@@ -55,33 +61,55 @@ type_definitions.extend([t for t in typeMacroizer()])
 type_definitions = "".join(type_definitions)
 
 
-def opcodeMacroizer(filter, opcodeField="value"):
+def opcodeMacroizer(filter, opcodeField="value", modifier=None):
     inc = 0
     for op in wasm.opcodeIterator(filter):
         b3op = "Oops"
         if isSimple(op["opcode"]):
             b3op = op["opcode"]["b3op"]
-        yield cppMacro(op["name"], op["opcode"][opcodeField], b3op, inc)
+        extraArgs = []
+        if modifier:
+            extraArgs = modifier(op["opcode"])
+        yield cppMacro(op["name"], op["opcode"][opcodeField], b3op, inc, *extraArgs)
         inc += 1
 
+
+def opcodeWithTypesMacroizer(filter):
+    def modifier(op):
+        return [cppType(type) for type in op["parameter"] + op["return"]]
+    return opcodeMacroizer(filter, modifier=modifier)
+
+
+def memoryLoadMacroizer():
+    def modifier(op):
+        return [cppType(op["return"][0])]
+    return opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 1), modifier=modifier)
+
+
+def memoryStoreMacroizer():
+    def modifier(op):
+        return [cppType(op["parameter"][1])]
+    return opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 0), modifier=modifier)
+
+
 defines = ["#define FOR_EACH_WASM_SPECIAL_OP(macro)"]
 defines.extend([op for op in opcodeMacroizer(lambda op: not (isUnary(op) or isBinary(op) or op["category"] == "control" or op["category"] == "memory" or op["category"] == "exttable"))])
 defines.append("\n\n#define FOR_EACH_WASM_CONTROL_FLOW_OP(macro)")
 defines.extend([op for op in opcodeMacroizer(lambda op: op["category"] == "control")])
 defines.append("\n\n#define FOR_EACH_WASM_SIMPLE_UNARY_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: isUnary(op) and isSimple(op))])
+defines.extend([op for op in opcodeWithTypesMacroizer(lambda op: isUnary(op) and isSimple(op))])
 defines.append("\n\n#define FOR_EACH_WASM_UNARY_OP(macro) \\\n    FOR_EACH_WASM_SIMPLE_UNARY_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: isUnary(op) and not (isSimple(op)))])
+defines.extend([op for op in opcodeWithTypesMacroizer(lambda op: isUnary(op) and not (isSimple(op)))])
 defines.append("\n\n#define FOR_EACH_WASM_SIMPLE_BINARY_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: isBinary(op) and isSimple(op))])
+defines.extend([op for op in opcodeWithTypesMacroizer(lambda op: isBinary(op) and isSimple(op))])
 defines.append("\n\n#define FOR_EACH_WASM_BINARY_OP(macro) \\\n    FOR_EACH_WASM_SIMPLE_BINARY_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: isBinary(op) and not (isSimple(op)))])
+defines.extend([op for op in opcodeWithTypesMacroizer(lambda op: isBinary(op) and not (isSimple(op)))])
 defines.append("\n\n#define FOR_EACH_WASM_MEMORY_LOAD_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 1))])
+defines.extend([op for op in memoryLoadMacroizer()])
 defines.append("\n\n#define FOR_EACH_WASM_MEMORY_STORE_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "memory" and len(op["return"]) == 0))])
+defines.extend([op for op in memoryStoreMacroizer()])
 defines.append("\n\n#define FOR_EACH_WASM_EXT_TABLE_OP(macro)")
-defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "exttable"), "extendedOp")])
+defines.extend([op for op in opcodeMacroizer(lambda op: (op["category"] == "exttable"), opcodeField="extendedOp")])
 defines.append("\n\n")
 
 defines = "".join(defines)
@@ -133,13 +161,13 @@ static constexpr unsigned expectedVersionNumber = """ + wasm.expectedVersionNumb
 static constexpr unsigned numTypes = """ + str(len(types)) + """;
 
 """ + type_definitions + """
-#define CREATE_ENUM_VALUE(name, id, b3type, inc) name = id,
+#define CREATE_ENUM_VALUE(name, id, ...) name = id,
 enum Type : int8_t {
     FOR_EACH_WASM_TYPE(CREATE_ENUM_VALUE)
 };
 #undef CREATE_ENUM_VALUE
 
-#define CREATE_CASE(name, id, b3type, inc) case id: return true;
+#define CREATE_CASE(name, id, ...) case id: return true;
 template <typename Int>
 inline bool isValidType(Int i)
 {
@@ -152,7 +180,7 @@ inline bool isValidType(Int i)
 }
 #undef CREATE_CASE
 
-#define CREATE_CASE(name, id, b3type, inc) case name: return b3type;
+#define CREATE_CASE(name, id, b3type, ...) case name: return b3type;
 inline B3::Type toB3Type(Type type)
 {
     switch (type) {
@@ -163,7 +191,7 @@ inline B3::Type toB3Type(Type type)
 }
 #undef CREATE_CASE
 
-#define CREATE_CASE(name, id, b3type, inc) case name: return #name;
+#define CREATE_CASE(name, ...) case name: return #name;
 inline const char* makeString(Type type)
 {
     switch (type) {
@@ -174,7 +202,7 @@ inline const char* makeString(Type type)
 }
 #undef CREATE_CASE
 
-#define CREATE_CASE(name, id, b3type, inc) case id: return inc;
+#define CREATE_CASE(name, id, b3type, inc, ...) case id: return inc;
 inline int linearizeType(Type type)
 {
     switch (type) {
@@ -185,7 +213,7 @@ inline int linearizeType(Type type)
 }
 #undef CREATE_CASE
 
-#define CREATE_CASE(name, id, b3type, inc) case inc: return name;
+#define CREATE_CASE(name, id, b3type, inc, ...) case inc: return name;
 inline Type linearizedToType(int i)
 {
     switch (i) {
@@ -207,7 +235,7 @@ inline Type linearizedToType(int i)
     FOR_EACH_WASM_MEMORY_STORE_OP(macro) \\
     macro(ExtTable, 0xFC, Oops, 0)
 
-#define CREATE_ENUM_VALUE(name, id, b3op, inc) name = id,
+#define CREATE_ENUM_VALUE(name, id, ...) name = id,
 
 enum OpType : uint8_t {
     FOR_EACH_WASM_OP(CREATE_ENUM_VALUE)
@@ -246,7 +274,7 @@ enum class ExtTableOpType : uint8_t {
 inline bool isControlOp(OpType op)
 {
     switch (op) {
-#define CREATE_CASE(name, id, b3op, inc) case OpType::name:
+#define CREATE_CASE(name, ...) case OpType::name:
     FOR_EACH_WASM_CONTROL_FLOW_OP(CREATE_CASE)
         return true;
 #undef CREATE_CASE
@@ -259,7 +287,7 @@ inline bool isControlOp(OpType op)
 inline bool isSimple(UnaryOpType op)
 {
     switch (op) {
-#define CREATE_CASE(name, id, b3op, inc) case UnaryOpType::name:
+#define CREATE_CASE(name, ...) case UnaryOpType::name:
     FOR_EACH_WASM_SIMPLE_UNARY_OP(CREATE_CASE)
         return true;
 #undef CREATE_CASE
@@ -272,7 +300,7 @@ inline bool isSimple(UnaryOpType op)
 inline bool isSimple(BinaryOpType op)
 {
     switch (op) {
-#define CREATE_CASE(name, id, b3op, inc) case BinaryOpType::name:
+#define CREATE_CASE(name, ...) case BinaryOpType::name:
     FOR_EACH_WASM_SIMPLE_BINARY_OP(CREATE_CASE)
         return true;
 #undef CREATE_CASE
@@ -294,7 +322,7 @@ inline uint32_t memoryLog2Alignment(OpType op)
     return 0;
 }
 
-#define CREATE_CASE(name, id, b3type, inc) case name: return #name;
+#define CREATE_CASE(name, ...) case name: return #name;
 inline const char* makeString(OpType op)
 {
     switch (op) {
diff --git a/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py b/Source/JavaScriptCore/wasm/generateWasmValidateInlinesHeader.py
deleted file mode 100755 (executable)
index 786d096..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2016-2017 Apple Inc. All rights reserved.
-#
-# 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 AND ITS CONTRIBUTORS "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 OR ITS 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.
-
-# This tool has a couple of helpful macros to process Wasm files from the wasm.json.
-
-from generateWasm import *
-import optparse
-import sys
-
-parser = optparse.OptionParser(usage="usage: %prog <wasm.json> <WasmOps.h>")
-(options, args) = parser.parse_args(sys.argv[0:])
-if len(args) != 3:
-    parser.error(parser.usage)
-
-wasm = Wasm(args[0], args[1])
-opcodes = wasm.opcodes
-wasmValidateInlinesHFile = open(args[2], "w")
-
-
-def cppType(name):
-    result = {
-        "bool": "I32",
-        "addr": "I32",
-        "i32": "I32",
-        "i64": "I64",
-        "f32": "F32",
-        "f64": "F64",
-    }.get(name, None)
-    if result == None:
-        raise ValueError("Unknown type name: " + name)
-    return result
-
-
-def toCpp(name):
-    return wasm.toCpp(name)
-
-
-def unaryMacro(name):
-    op = opcodes[name]
-    return """
-template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType value, ExpressionType& result) -> Result
-{
-    if (UNLIKELY(value != """ + cppType(op["parameter"][0]) + """))
-        return Unexpected<Result::error_type>("validation failed: """ + name + """ value type mismatch");
-
-    result = """ + cppType(op["return"][0]) + """;
-    return { };
-}
-"""
-
-
-def binaryMacro(name):
-    op = opcodes[name]
-    return """
-template<> auto Validate::addOp<OpType::""" + toCpp(name) + """>(ExpressionType left, ExpressionType right, ExpressionType& result) -> Result
-{
-    if (UNLIKELY(left != """ + cppType(op["parameter"][0]) + """))
-        return Unexpected<Result::error_type>("validation failed: """ + name + """ left value type mismatch");
-
-    if (UNLIKELY(right != """ + cppType(op["parameter"][1]) + """))
-        return Unexpected<Result::error_type>("validation failed: """ + name + """ right value type mismatch");
-
-    result = """ + cppType(op["return"][0]) + """;
-    return { };
-}
-"""
-
-def loadMacro(name):
-    op = opcodes[name]
-    return """
-    case LoadOpType::""" + toCpp(name) + """: {
-        if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
-            return Unexpected<Result::error_type>("validation failed: """ + name + """ pointer type mismatch");
-
-        result = """ + cppType(op["return"][0]) + """;
-        return { };
-    }"""
-
-
-def storeMacro(name):
-    op = opcodes[name]
-    return """
-    case StoreOpType::""" + toCpp(name) + """: {
-        if (UNLIKELY(pointer != """ + cppType(op["parameter"][0]) + """))
-            return Unexpected<Result::error_type>("validation failed: """ + name + """ pointer type mismatch");
-
-        if (UNLIKELY(value != """ + cppType(op["parameter"][1]) + """))
-            return Unexpected<Result::error_type>("validation failed: """ + name + """ value type mismatch");
-
-        return { };
-    }"""
-
-
-unarySpecializations = "".join([op for op in wasm.opcodeIterator(isUnary, unaryMacro)])
-binarySpecializations = "".join([op for op in wasm.opcodeIterator(isBinary, binaryMacro)])
-loadCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 1, loadMacro)])
-storeCases = "".join([op for op in wasm.opcodeIterator(lambda op: op["category"] == "memory" and len(op["return"]) == 0, storeMacro)])
-
-contents = wasm.header + """
-// This file is intended to be inlined by WasmValidate.cpp only! It should not be included elsewhere.
-
-#pragma once
-
-#if ENABLE(WEBASSEMBLY)
-
-#include <wtf/StdLibExtras.h>
-
-#if ASSERT_DISABLED
-IGNORE_RETURN_TYPE_WARNINGS_BEGIN
-#endif
-
-namespace JSC { namespace Wasm {
-
-""" + unarySpecializations + binarySpecializations + """
-
-auto Validate::load(LoadOpType op, ExpressionType pointer, ExpressionType& result, uint32_t) -> Result
-{
-    if (UNLIKELY(!hasMemory()))
-        return Unexpected<Result::error_type>("validation failed: load instruction without memory");
-
-    switch (op) {
-""" + loadCases + """
-    }
-    ASSERT_NOT_REACHED();
-}
-
-auto Validate::store(StoreOpType op, ExpressionType pointer, ExpressionType value, uint32_t) -> Result
-{
-    if (UNLIKELY(!hasMemory()))
-        return Unexpected<Result::error_type>("validation failed: store instruction without memory");
-
-    switch (op) {
-""" + storeCases + """
-    }
-    ASSERT_NOT_REACHED();
-}
-
-} } // namespace JSC::Wasm
-
-#if ASSERT_DISABLED
-IGNORE_RETURN_TYPE_WARNINGS_END
-#endif
-
-#endif // ENABLE(WEBASSEMBLY)
-
-"""
-
-wasmValidateInlinesHFile.write(contents)
-wasmValidateInlinesHFile.close()
index fc4158f..3649e57 100644 (file)
@@ -229,7 +229,7 @@ static void instantiate(VM& vm, JSGlobalObject* globalObject, JSPromise* promise
             JSGlobalObject* globalObject = instance->globalObject();
             resolve(vm, globalObject, promise, instance, module, importObject, codeBlock.releaseNonNull(), resolveKind, creationMode);
         });
-    }), &Wasm::createJSToWasmWrapper, &Wasm::operationWasmToJSException);
+    }));
 }
 
 static void compileAndInstantiate(VM& vm, JSGlobalObject* globalObject, JSPromise* promise, const Identifier& moduleKey, JSValue buffer, JSObject* importObject, Resolve resolveKind, Wasm::CreationMode creationMode)
@@ -329,12 +329,12 @@ static EncodedJSValue JSC_HOST_CALL webAssemblyValidateFunc(JSGlobalObject* glob
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    auto [base, byteSize] = getWasmBufferFromValue(globalObject, callFrame->argument(0));
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    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(base, byteSize)));
+    Vector<uint8_t> source = createSourceBufferFromValue(vm, globalObject, callFrame->argument(0));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    auto validationResult = Wasm::Module::validateSync(&vm.wasmContext, WTFMove(source));
+    return JSValue::encode(jsBoolean(validationResult.has_value()));
 }
 
 EncodedJSValue JSC_HOST_CALL webAssemblyCompileStreamingInternal(JSGlobalObject* globalObject, CallFrame* callFrame)
index 3ba6243..8419c3a 100644 (file)
@@ -81,7 +81,7 @@ static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(JSGlobalObjec
     JSWebAssemblyInstance* instance = JSWebAssemblyInstance::tryCreate(vm, globalObject, JSWebAssemblyInstance::createPrivateModuleKey(), module, importObject, instanceStructure, Ref<Wasm::Module>(module->module()), Wasm::CreationMode::FromJS);
     RETURN_IF_EXCEPTION(scope, { });
 
-    instance->finalizeCreation(vm, globalObject, module->module().compileSync(&vm.wasmContext, instance->memoryMode(), &Wasm::createJSToWasmWrapper, &Wasm::operationWasmToJSException), importObject, Wasm::CreationMode::FromJS);
+    instance->finalizeCreation(vm, globalObject, module->module().compileSync(&vm.wasmContext, instance->memoryMode()), importObject, Wasm::CreationMode::FromJS);
     RETURN_IF_EXCEPTION(scope, { });
     return JSValue::encode(instance);
 }