WebAssembly: no VM / JS version of everything but Instance
https://bugs.webkit.org/show_bug.cgi?id=177473

Reviewed by Filip Pizlo, Saam Barati.

JSTests:

- Exceeding max on memory growth now returns a range error as per
spec. This is a (very minor) breaking change: it used to throw OOM
error. Update the corresponding test.

* wasm/js-api/memory-grow.js:
(assertEq):
* wasm/js-api/table.js:
(assert.throws):

Source/JavaScriptCore:

This change entails cleaning up and splitting a bunch of code which we had
intertwined between C++ classes which represent JS objects, and pure C++
implementation objects. This specific change goes most of the way towards
allowing JSC's WebAssembly to work without VM / JS, up to but excluding
JSWebAssemblyInstance (there's Wasm::Instance, but it's not *the* thing
yet). Because of this we still have a few FIXME identifying places that need to
change. A follow-up change will go the rest of the way.

I went about this change in the simplest way possible: grep the
JavaScriptCore/wasm directory for "JS[^C_]" as well as "VM" and exclude the /js/
sub-directory (which contains the JS implementation of WebAssembly).

None of this change removes the need for a JIT entitlement to be able to use
WebAssembly. We don't have an interpreter, the process therefore still needs to
be allowed to JIT to use these pure-C++ APIs.

Interesting things to note:

  - Remove VM from Plan and associated places. It can just live as a capture in
    the callback lambda if it's needed.
  - Wasm::Memory shouldn't require a VM. It was only used to ask the GC to
    collect. We now instead pass two lambdas at construction time for this
    purpose: one to notify of memory pressure, and the other to ask for
    syncrhonous memory reclamation. This allows whoever creates the memory to
    dictate how to react to both these cases, and for a JS embedding that's to
    call the GC (async or sync, respectively).
  - Move grow logic from JSWebAssemblyMemory to Wasm::Memory::grow. Use Expected
    there, with an enum class for failure types.
  - Exceeding max on memory growth now returns a range error as per spec. This
    is a (very minor) breaking change: it used to throw OOM error. Update the
    corresponding test.
  - When generating the grow_memory opcode, no need to get the VM. Instead,
    reach directly for Wasm::Memory and grow it.
  - JSWebAssemblyMemory::grow can now always throw on failure, because it's only
    ever called from JS (not from grow_memory as before).
  - Wasm::Memory now takes a callback for successful growth. This allows JS
    wrappers to register themselves when growth succeeds without Wasm::Memory
    knowning anything about JS. It'll also allow creating a list of callbacks
    for when we add thread support (we'll want to notify many wrappers, all
    under a lock).
  - Wasm::Memory is now back to being the source of truth about address / size,
    used directly by generated code instead of JSWebAssemblyMemory.
  - Move wasmToJS from the general WasmBinding header to its own header under
    wasm/js. It's only used by wasm/js/JSWebAssemblyCodeBlock.cpp, and uses VM,
    and therefore isn't general WebAssembly.
  - Make Wasm::Context an actual type (just a struct holding a
    JSWebAssemlyInstance for now) instead of an alias for that. Notably this
    doesn't add anything to the Context and doesn't change what actually gets
    passed around in JIT code (fast TLS or registers) because these changes
    potentially impact performance. The entire purpose of this change is to
    allow passing Wasm::Context around without having to know about VM. Since VM
    contains a Wasm::Context the JS embedding is effectively the same, but with
    this setup a non-JS embedding is much better off.
  - Move JSWebAssembly into the JS folder.
  - OMGPlan: use Wasm::CodeBlock directly instead of JSWebAssemblyCodeBlock.
  - wasm->JS stubs are now on the instance's tail as raw pointers, instead of
    being on JSWebAssemblyCodeBlock, and are now called wasm->Embedder
    stubs. The owned reference is still on JSWebAssemblyCodeBlock, and is still
    called wasm->JS stub. This move means that the embedder must, after creating
    a Wasm::CodeBlock, somehow create the stubs to call back into the
    embedder. This removes an indirection in the generated code because
    the B3 IR generator now reaches into the instance instead of
    JSWebAssemblyCodeBlock.
  - Move more CodeBlock things. Compilation completion is now marked by its own
    atomic<bool> flag instead of a nullptr plan: that required using a lock, and
    was causing a deadlock in stack-trace.js because before my changes
    JSWebAssemblyCodeBlock did its own completion checking separately from
    Wasm::CodeBlock, without getting the lock. Now that everything points to
    Wasm::CodeBlock and there's no cached completion marker, the lock was being
    acquired in a sanity-check assertion.
  - Embedder -> Wasm wrappers are now generated through a function that's passed
    in at compilation time, instead of being hard-coded as a JS -> Wasm wrapper.
  - WasmMemory doens't need to know about fault handling thunks. Only the IR
    generator should know, and should make sure that the exception throwing
    thunk is generated if any memory is present (note: with signal handling not
    all of them generate an exception check).
  - Make exception throwing pluggable: instead of having a hard-coded
    JS-specific lambda we now have a regular C++ function being called from JIT
    code when a WebAssembly exception is thrown. This allows any embedder to get
    called as they wish. For now a process can only have a single of these
    functions (i.e. only one embedder per process) because the trap handler is a
    singleton. That can be fixed in in #177475.
  - Create WasmEmbedder.h where all embedder plugging will live.
  - Split up JSWebAssemblyTable into Wasm::Table which is
    refcounted. JSWebAssemblyTable now only contains the JS functions in the
    table, and Wasm::Table is what's used by the JIT code to lookup where to
    call and do the instance check (for context switch). Note that this creates
    an extra allocation for all the instances in Wasm::Table, and in exchange
    removes an indirection in JIT code because the instance used to be obtained
    off of the JS function. Also note that it's the embedder than keeps the
    instances alive, not Wasm::Table (which holds a dumb pointer to the
    instance), because doing otherwise would cause reference cycles.
   - Add WasmInstance. It doesn't do much for now, owns globals.
   - JSWebAssembly instance now doesn't just contain the imported functions as
     JSObjects, it also has the corresponding import's instance and wasm
     entrypoint. This triples the space allocated per instance's imported
     function, but there shouldn't be that many imports. This has two upsides: it
     creates smaller and faster code, and makes is easier to disassociate
     embedder-specific things from embedder-neutral things. The small / faster
     win is in two places: B3 IR generator only needs offsetOfImportFunction for
     the call opcode (when the called index is an import) to know whether the
     import is wasm->wasm or wasm->embedder (this isn't known at compile-time
     because it's dependent on the import object), this is now done by seeing if
     that import function has an associated target instance (only wasm->wasm
     does); the other place is wasmBinding which uses offsetOfImportFunction to
     figure out the wasm->wasm target instance, and then gets
     WebAssemblyFunction::offsetOfWasmEntrypointLoadLocation to do a tail
     call. The disassociation comes because the target instance can be
     Wasm::Instance once we change what the Context is, and
     WasmEntrypointLoadLocation is already embedder-independent. As a next step I
     can move this tail allocation from JSWebAssemblyInstance to Wasm::Instance,
     and leave importFunction in as an opaque pointer which is embedder-specific,
     and in JS will remain WriteBarrier<JSObject>.
   - Rename VMEntryFrame to EntryFrame, and in many places pass a pointer to it
     around instead of VM. This is a first step in allowing entry frames which
     aren't stored on VM, but which are instead stored in an embedder-specific
     location. That change won't really affect JS except through code churn, but
     will allow WebAssembly to use some machinery in a generic manner without
     having a VM.

* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecode/PolymorphicAccess.cpp:
(JSC::AccessGenerationState::emitExplicitExceptionHandler):
* debugger/Debugger.cpp:
(JSC::Debugger::stepOutOfFunction):
(JSC::Debugger::returnEvent):
(JSC::Debugger::unwindEvent):
(JSC::Debugger::didExecuteProgram):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileExceptionHandlers):
* dfg/DFGOSREntry.cpp:
(JSC::DFG::prepareOSREntry):
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::compileOSRExit):
(JSC::DFG::OSRExit::compileExit):
* dfg/DFGThunks.cpp:
(JSC::DFG::osrEntryThunkGenerator):
* ftl/FTLCompile.cpp:
(JSC::FTL::compile):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::lower):
* ftl/FTLOSRExitCompiler.cpp:
(JSC::FTL::compileStub):
* interpreter/CallFrame.cpp:
(JSC::CallFrame::wasmAwareLexicalGlobalObject):
(JSC::CallFrame::callerFrame):
(JSC::CallFrame::unsafeCallerFrame):
* interpreter/CallFrame.h:
(JSC::ExecState::callerFrame const):
(JSC::ExecState::callerFrameOrEntryFrame const):
(JSC::ExecState::unsafeCallerFrameOrEntryFrame const):
* interpreter/FrameTracers.h:
(JSC::NativeCallFrameTracer::NativeCallFrameTracer):
(JSC::NativeCallFrameTracerWithRestore::NativeCallFrameTracerWithRestore):
(JSC::NativeCallFrameTracerWithRestore::~NativeCallFrameTracerWithRestore):
* interpreter/Interpreter.cpp:
(JSC::UnwindFunctor::operator() const):
(JSC::UnwindFunctor::copyCalleeSavesToEntryFrameCalleeSavesBuffer const):
(JSC::Interpreter::unwind):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::StackVisitor):
(JSC::StackVisitor::gotoNextFrame):
(JSC::StackVisitor::readNonInlinedFrame):
(JSC::StackVisitor::Frame::dump const):
* interpreter/StackVisitor.h:
(JSC::StackVisitor::Frame::callerIsEntryFrame const):
* interpreter/VMEntryRecord.h:
(JSC::VMEntryRecord::prevTopEntryFrame):
(JSC::VMEntryRecord::unsafePrevTopEntryFrame):
(JSC::EntryFrame::vmEntryRecordOffset):
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::restoreCalleeSavesFromEntryFrameCalleeSavesBuffer):
(JSC::AssemblyHelpers::loadWasmContextInstance):
(JSC::AssemblyHelpers::storeWasmContextInstance):
(JSC::AssemblyHelpers::loadWasmContextInstanceNeedsMacroScratchRegister):
(JSC::AssemblyHelpers::storeWasmContextInstanceNeedsMacroScratchRegister):
(JSC::AssemblyHelpers::copyCalleeSavesToEntryFrameCalleeSavesBufferImpl):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::copyCalleeSavesToVMEntryFrameCalleeSavesBuffer):
(JSC::AssemblyHelpers::copyCalleeSavesToEntryFrameCalleeSavesBuffer):
(JSC::AssemblyHelpers::copyCalleeSavesFromFrameOrRegisterToEntryFrameCalleeSavesBuffer):
* jit/JIT.cpp:
(JSC::JIT::emitEnterOptimizationCheck):
(JSC::JIT::privateCompileExceptionHandlers):
* jit/JITExceptions.cpp:
(JSC::genericUnwind):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_throw):
(JSC::JIT::emit_op_catch):
(JSC::JIT::emitSlow_op_loop_hint):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_throw):
(JSC::JIT::emit_op_catch):
* jit/JITOperations.cpp:
* jit/ThunkGenerators.cpp:
(JSC::throwExceptionFromCallSlowPathGenerator):
(JSC::nativeForGenerator):
* jsc.cpp:
(functionDumpCallFrame):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntThunks.cpp:
(JSC::vmEntryRecord):
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/Options.cpp:
(JSC::recomputeDependentOptions):
* runtime/Options.h:
* runtime/SamplingProfiler.cpp:
(JSC::FrameWalker::FrameWalker):
(JSC::FrameWalker::advanceToParentFrame):
(JSC::SamplingProfiler::processUnverifiedStackTraces):
* runtime/ThrowScope.cpp:
(JSC::ThrowScope::~ThrowScope):
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::~VM):
* runtime/VM.h:
(JSC::VM::topEntryFrameOffset):
* runtime/VMTraps.cpp:
(JSC::isSaneFrame):
(JSC::VMTraps::tryInstallTrapBreakpoints):
(JSC::VMTraps::invalidateCodeBlocksOnStack):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::restoreWasmContextInstance):
(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::B3IRGenerator::restoreWebAssemblyGlobalState):
(JSC::Wasm::B3IRGenerator::addGrowMemory):
(JSC::Wasm::B3IRGenerator::addCurrentMemory):
(JSC::Wasm::B3IRGenerator::addCall):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
(JSC::Wasm::parseAndCompile):
* wasm/WasmB3IRGenerator.h:
* wasm/WasmBBQPlan.cpp:
(JSC::Wasm::BBQPlan::BBQPlan):
(JSC::Wasm::BBQPlan::compileFunctions):
(JSC::Wasm::BBQPlan::complete):
* wasm/WasmBBQPlan.h:
* wasm/WasmBBQPlanInlines.h:
(JSC::Wasm::BBQPlan::initializeCallees):
* wasm/WasmBinding.cpp:
(JSC::Wasm::wasmToWasm):
* wasm/WasmBinding.h:
* wasm/WasmCodeBlock.cpp:
(JSC::Wasm::CodeBlock::create):
(JSC::Wasm::CodeBlock::CodeBlock):
(JSC::Wasm::CodeBlock::compileAsync):
(JSC::Wasm::CodeBlock::setCompilationFinished):
* wasm/WasmCodeBlock.h:
(JSC::Wasm::CodeBlock::offsetOfImportStubs):
(JSC::Wasm::CodeBlock::allocationSize):
(JSC::Wasm::CodeBlock::importWasmToEmbedderStub):
(JSC::Wasm::CodeBlock::offsetOfImportWasmToEmbedderStub):
(JSC::Wasm::CodeBlock::wasmToJSCallStubForImport):
(JSC::Wasm::CodeBlock::compilationFinished):
(JSC::Wasm::CodeBlock::jsEntrypointCalleeFromFunctionIndexSpace):
(JSC::Wasm::CodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
* wasm/WasmContext.cpp:
(JSC::Wasm::Context::useFastTLS):
(JSC::Wasm::Context::load const):
(JSC::Wasm::Context::store):
* wasm/WasmContext.h:
* wasm/WasmEmbedder.h: Copied from Source/JavaScriptCore/wasm/WasmContext.h.
* wasm/WasmFaultSignalHandler.cpp:
* wasm/WasmFaultSignalHandler.h:
* wasm/WasmFormat.h:
* wasm/WasmInstance.cpp: Copied from Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h.
(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::~Instance):
(JSC::Wasm::Instance::extraMemoryAllocated const):
* wasm/WasmInstance.h: Added.
(JSC::Wasm::Instance::create):
(JSC::Wasm::Instance::finalizeCreation):
(JSC::Wasm::Instance::module):
(JSC::Wasm::Instance::codeBlock):
(JSC::Wasm::Instance::memory):
(JSC::Wasm::Instance::table):
(JSC::Wasm::Instance::loadI32Global const):
(JSC::Wasm::Instance::loadI64Global const):
(JSC::Wasm::Instance::loadF32Global const):
(JSC::Wasm::Instance::loadF64Global const):
(JSC::Wasm::Instance::setGlobal):
(JSC::Wasm::Instance::offsetOfCachedStackLimit):
(JSC::Wasm::Instance::cachedStackLimit const):
(JSC::Wasm::Instance::setCachedStackLimit):
* wasm/WasmMemory.cpp:
(JSC::Wasm::Memory::Memory):
(JSC::Wasm::Memory::create):
(JSC::Wasm::Memory::~Memory):
(JSC::Wasm::Memory::grow):
* wasm/WasmMemory.h:
(JSC::Wasm::Memory::offsetOfMemory):
(JSC::Wasm::Memory::offsetOfSize):
* wasm/WasmMemoryInformation.cpp:
(JSC::Wasm::PinnedRegisterInfo::get):
(JSC::Wasm::PinnedRegisterInfo::PinnedRegisterInfo):
* wasm/WasmMemoryInformation.h:
(JSC::Wasm::PinnedRegisterInfo::toSave const):
* wasm/WasmMemoryMode.cpp: Copied from Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h.
(JSC::Wasm::makeString):
* wasm/WasmMemoryMode.h: Copied from Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h.
* wasm/WasmModule.cpp:
(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:
* wasm/WasmModuleParser.cpp:
(JSC::Wasm::ModuleParser::parseTableHelper):
* wasm/WasmOMGPlan.cpp:
(JSC::Wasm::OMGPlan::OMGPlan):
(JSC::Wasm::OMGPlan::runForIndex):
* wasm/WasmOMGPlan.h:
* wasm/WasmPageCount.h:
(JSC::Wasm::PageCount::isValid const):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::Plan):
(JSC::Wasm::Plan::runCompletionTasks):
(JSC::Wasm::Plan::addCompletionTask):
(JSC::Wasm::Plan::tryRemoveContextAndCancelIfLast):
* wasm/WasmPlan.h:
(JSC::Wasm::Plan::dontFinalize):
* wasm/WasmSignature.cpp:
* wasm/WasmSignature.h:
* wasm/WasmTable.cpp: Added.
(JSC::Wasm::Table::create):
(JSC::Wasm::Table::~Table):
(JSC::Wasm::Table::Table):
(JSC::Wasm::Table::grow):
(JSC::Wasm::Table::clearFunction):
(JSC::Wasm::Table::setFunction):
* wasm/WasmTable.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h.
(JSC::Wasm::Table::maximum const):
(JSC::Wasm::Table::size const):
(JSC::Wasm::Table::offsetOfSize):
(JSC::Wasm::Table::offsetOfFunctions):
(JSC::Wasm::Table::offsetOfInstances):
(JSC::Wasm::Table::isValidSize):
* wasm/WasmThunks.cpp:
(JSC::Wasm::throwExceptionFromWasmThunkGenerator):
(JSC::Wasm::triggerOMGTierUpThunkGenerator):
(JSC::Wasm::Thunks::setThrowWasmException):
(JSC::Wasm::Thunks::throwWasmException):
* wasm/WasmThunks.h:
* wasm/WasmWorklist.cpp:
(JSC::Wasm::Worklist::stopAllPlansForContext):
* wasm/WasmWorklist.h:
* wasm/js/JSToWasm.cpp: Added.
(JSC::Wasm::createJSToWasmWrapper):
* wasm/js/JSToWasm.h: Copied from Source/JavaScriptCore/wasm/WasmBinding.h.
* wasm/js/JSWebAssembly.cpp: Renamed from Source/JavaScriptCore/wasm/JSWebAssembly.cpp.
* wasm/js/JSWebAssembly.h: Renamed from Source/JavaScriptCore/wasm/JSWebAssembly.h.
* wasm/js/JSWebAssemblyCodeBlock.cpp:
(JSC::JSWebAssemblyCodeBlock::create):
(JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
* wasm/js/JSWebAssemblyCodeBlock.h:
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::JSWebAssemblyInstance):
(JSC::JSWebAssemblyInstance::finishCreation):
(JSC::JSWebAssemblyInstance::visitChildren):
(JSC::JSWebAssemblyInstance::finalizeCreation):
(JSC::JSWebAssemblyInstance::create):
* wasm/js/JSWebAssemblyInstance.h:
(JSC::JSWebAssemblyInstance::instance):
(JSC::JSWebAssemblyInstance::context const):
(JSC::JSWebAssemblyInstance::table):
(JSC::JSWebAssemblyInstance::webAssemblyToJSCallee):
(JSC::JSWebAssemblyInstance::setMemory):
(JSC::JSWebAssemblyInstance::offsetOfTail):
(JSC::JSWebAssemblyInstance::importFunctionInfo):
(JSC::JSWebAssemblyInstance::offsetOfTargetInstance):
(JSC::JSWebAssemblyInstance::offsetOfWasmEntrypoint):
(JSC::JSWebAssemblyInstance::offsetOfImportFunction):
(JSC::JSWebAssemblyInstance::importFunction):
(JSC::JSWebAssemblyInstance::internalMemory):
(JSC::JSWebAssemblyInstance::wasmCodeBlock const):
(JSC::JSWebAssemblyInstance::offsetOfWasmTable):
(JSC::JSWebAssemblyInstance::offsetOfCallee):
(JSC::JSWebAssemblyInstance::offsetOfGlobals):
(JSC::JSWebAssemblyInstance::offsetOfWasmCodeBlock):
(JSC::JSWebAssemblyInstance::offsetOfWasmMemory):
(JSC::JSWebAssemblyInstance::cachedStackLimit const):
(JSC::JSWebAssemblyInstance::setCachedStackLimit):
(JSC::JSWebAssemblyInstance::wasmMemory):
(JSC::JSWebAssemblyInstance::wasmModule):
(JSC::JSWebAssemblyInstance::allocationSize):
(JSC::JSWebAssemblyInstance::module const):
* wasm/js/JSWebAssemblyMemory.cpp:
(JSC::JSWebAssemblyMemory::create):
(JSC::JSWebAssemblyMemory::adopt):
(JSC::JSWebAssemblyMemory::JSWebAssemblyMemory):
(JSC::JSWebAssemblyMemory::grow):
(JSC::JSWebAssemblyMemory::growSuccessCallback):
* wasm/js/JSWebAssemblyMemory.h:
* wasm/js/JSWebAssemblyModule.cpp:
(JSC::JSWebAssemblyModule::moduleInformation const):
(JSC::JSWebAssemblyModule::exportSymbolTable const):
(JSC::JSWebAssemblyModule::signatureIndexFromFunctionIndexSpace const):
(JSC::JSWebAssemblyModule::callee const):
(JSC::JSWebAssemblyModule::codeBlock):
(JSC::JSWebAssemblyModule::module):
* wasm/js/JSWebAssemblyModule.h:
* wasm/js/JSWebAssemblyTable.cpp:
(JSC::JSWebAssemblyTable::create):
(JSC::JSWebAssemblyTable::JSWebAssemblyTable):
(JSC::JSWebAssemblyTable::visitChildren):
(JSC::JSWebAssemblyTable::grow):
(JSC::JSWebAssemblyTable::getFunction):
(JSC::JSWebAssemblyTable::clearFunction):
(JSC::JSWebAssemblyTable::setFunction):
* wasm/js/JSWebAssemblyTable.h:
(JSC::JSWebAssemblyTable::isValidSize):
(JSC::JSWebAssemblyTable::maximum const):
(JSC::JSWebAssemblyTable::size const):
(JSC::JSWebAssemblyTable::table):
* wasm/js/WasmToJS.cpp: Copied from Source/JavaScriptCore/wasm/WasmBinding.cpp.
(JSC::Wasm::materializeImportJSCell):
(JSC::Wasm::wasmToJS):
(JSC::Wasm::wasmToJSException):
* wasm/js/WasmToJS.h: Copied from Source/JavaScriptCore/wasm/WasmBinding.h.
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyMemoryConstructor.cpp:
(JSC::constructJSWebAssemblyMemory):
* wasm/js/WebAssemblyMemoryPrototype.cpp:
(JSC::webAssemblyMemoryProtoFuncGrow):
* wasm/js/WebAssemblyModuleConstructor.cpp:
(JSC::constructJSWebAssemblyModule):
(JSC::WebAssemblyModuleConstructor::createModule):
* wasm/js/WebAssemblyModuleConstructor.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):
* wasm/js/WebAssemblyPrototype.cpp:
(JSC::webAssemblyCompileFunc):
(JSC::instantiate):
(JSC::compileAndInstantiate):
(JSC::webAssemblyValidateFunc):
* wasm/js/WebAssemblyTableConstructor.cpp:
(JSC::constructJSWebAssemblyTable):
* wasm/js/WebAssemblyWrapperFunction.cpp:
(JSC::WebAssemblyWrapperFunction::create):

Source/WebCore:

* ForwardingHeaders/wasm/WasmModule.h: Added. This used to be
included in JSWebAssemblyModule.h.
* bindings/js/SerializedScriptValue.cpp: Update postMessage code
according to C++ API changes.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@223738 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/wasm/WasmBinding.cpp b/Source/JavaScriptCore/wasm/WasmBinding.cpp
index 67ccf5e..4910c83 100644
--- a/Source/JavaScriptCore/wasm/WasmBinding.cpp
+++ b/Source/JavaScriptCore/wasm/WasmBinding.cpp
@@ -29,596 +29,14 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "CCallHelpers.h"
-#include "FrameTracers.h"
-#include "JITExceptions.h"
 #include "JSCInlines.h"
 #include "JSWebAssemblyInstance.h"
 #include "LinkBuffer.h"
-#include "NativeErrorConstructor.h"
-#include "ThunkGenerators.h"
-#include "WasmCallingConvention.h"
-#include "WasmContext.h"
-#include "WasmExceptionType.h"
 
 namespace JSC { namespace Wasm {
 
 using JIT = CCallHelpers;
 
-static void materializeImportJSCell(JIT& jit, unsigned importIndex, GPRReg result)
-{
-    // We're calling out of the current WebAssembly.Instance. That Instance has a list of all its import functions.
-    jit.loadWasmContext(result);
-    jit.loadPtr(JIT::Address(result, JSWebAssemblyInstance::offsetOfImportFunction(importIndex)), result);
-}
-
-Expected<MacroAssemblerCodeRef, BindingFailure> wasmToJs(VM* vm, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex signatureIndex, unsigned importIndex)
-{
-    // FIXME: This function doesn't properly abstract away the calling convention.
-    // It'd be super easy to do so: https://bugs.webkit.org/show_bug.cgi?id=169401
-    const WasmCallingConvention& wasmCC = wasmCallingConvention();
-    const JSCCallingConvention& jsCC = jscCallingConvention();
-    const Signature& signature = SignatureInformation::get(signatureIndex);
-    unsigned argCount = signature.argumentCount();
-    JIT jit;
-
-    // Note: WasmB3IRGenerator assumes that this stub treats SP as a callee save.
-    // If we ever change this, we will also need to change WasmB3IRGenerator.
-
-    // Below, we assume that the JS calling convention is always on the stack.
-    ASSERT(!jsCC.m_gprArgs.size());
-    ASSERT(!jsCC.m_fprArgs.size());
-
-    jit.emitFunctionPrologue();
-    jit.store64(JIT::TrustedImm32(0), JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register)))); // FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321
-
-    {
-        bool hasBadI64Use = false;
-        hasBadI64Use |= signature.returnType() == I64;
-        for (unsigned argNum = 0; argNum < argCount && !hasBadI64Use; ++argNum) {
-            Type argType = signature.argument(argNum);
-            switch (argType) {
-            case Void:
-            case Func:
-            case Anyfunc:
-                RELEASE_ASSERT_NOT_REACHED();
-
-            case I64: {
-                hasBadI64Use = true;
-                break;
-            }
-
-            default:
-                break;
-            }
-        }
-
-        if (hasBadI64Use) {
-            jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(*vm);
-            jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-            jit.loadWasmContext(GPRInfo::argumentGPR1);
-
-            // Store Callee.
-            jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR1, JSWebAssemblyInstance::offsetOfCallee()), GPRInfo::argumentGPR2);
-            jit.storePtr(GPRInfo::argumentGPR2, JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-
-            auto call = jit.call();
-            jit.jumpToExceptionHandler(*vm);
-
-            void (*throwBadI64)(ExecState*, JSWebAssemblyInstance*) = [] (ExecState* exec, JSWebAssemblyInstance* wasmContext) -> void {
-                VM* vm = &exec->vm();
-                NativeCallFrameTracer tracer(vm, exec);
-
-                {
-                    auto throwScope = DECLARE_THROW_SCOPE(*vm);
-                    JSGlobalObject* globalObject = wasmContext->globalObject();
-                    auto* error = ErrorInstance::create(exec, *vm, globalObject->typeErrorConstructor()->errorStructure(), ASCIILiteral("i64 not allowed as return type or argument to an imported function"));
-                    throwException(exec, throwScope, error);
-                }
-
-                genericUnwind(vm, exec);
-                ASSERT(!!vm->callFrameForCatch);
-            };
-
-            LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
-            if (UNLIKELY(linkBuffer.didFailToAllocate()))
-                return makeUnexpected(BindingFailure::OutOfMemory);
-
-            linkBuffer.link(call, throwBadI64);
-            return FINALIZE_CODE(linkBuffer, ("WebAssembly->JavaScript invalid i64 use in import[%i]", importIndex));
-        }
-    }
-
-    // Here we assume that the JS calling convention saves at least all the wasm callee saved. We therefore don't need to save and restore more registers since the wasm callee already took care of this.
-    RegisterSet missingCalleeSaves = wasmCC.m_calleeSaveRegisters;
-    missingCalleeSaves.exclude(jsCC.m_calleeSaveRegisters);
-    ASSERT(missingCalleeSaves.isEmpty());
-
-    if (!Options::useCallICsForWebAssemblyToJSCalls()) {
-        ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(argCount * sizeof(uint64_t));
-        char* buffer = argCount ? static_cast<char*>(scratchBuffer->dataBuffer()) : nullptr;
-        unsigned marshalledGPRs = 0;
-        unsigned marshalledFPRs = 0;
-        unsigned bufferOffset = 0;
-        unsigned frOffset = CallFrame::headerSizeInRegisters * static_cast<int>(sizeof(Register));
-        const GPRReg scratchGPR = GPRInfo::regCS0;
-        jit.subPtr(MacroAssembler::TrustedImm32(WTF::roundUpToMultipleOf(stackAlignmentBytes(), sizeof(Register))), MacroAssembler::stackPointerRegister);
-        jit.storePtr(scratchGPR, MacroAssembler::Address(MacroAssembler::stackPointerRegister));
-
-        for (unsigned argNum = 0; argNum < argCount; ++argNum) {
-            Type argType = signature.argument(argNum);
-            switch (argType) {
-            case Void:
-            case Func:
-            case Anyfunc:
-            case I64:
-                RELEASE_ASSERT_NOT_REACHED();
-            case I32: {
-                GPRReg gprReg;
-                if (marshalledGPRs < wasmCC.m_gprArgs.size())
-                    gprReg = wasmCC.m_gprArgs[marshalledGPRs].gpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    gprReg = GPRInfo::argumentGPR0;
-                    jit.load64(JIT::Address(GPRInfo::callFrameRegister, frOffset), gprReg);
-                    frOffset += sizeof(Register);
-                }
-                jit.zeroExtend32ToPtr(gprReg, gprReg);
-                jit.store64(gprReg, buffer + bufferOffset);
-                ++marshalledGPRs;
-                break;
-            }
-            case F32: {
-                FPRReg fprReg;
-                if (marshalledFPRs < wasmCC.m_fprArgs.size())
-                    fprReg = wasmCC.m_fprArgs[marshalledFPRs].fpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    fprReg = FPRInfo::argumentFPR0;
-                    jit.loadFloat(JIT::Address(GPRInfo::callFrameRegister, frOffset), fprReg);
-                    frOffset += sizeof(Register);
-                }
-                jit.convertFloatToDouble(fprReg, fprReg);
-                jit.moveDoubleTo64(fprReg, scratchGPR);
-                jit.store64(scratchGPR, buffer + bufferOffset);
-                ++marshalledFPRs;
-                break;
-            }
-            case F64: {
-                FPRReg fprReg;
-                if (marshalledFPRs < wasmCC.m_fprArgs.size())
-                    fprReg = wasmCC.m_fprArgs[marshalledFPRs].fpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    fprReg = FPRInfo::argumentFPR0;
-                    jit.loadDouble(JIT::Address(GPRInfo::callFrameRegister, frOffset), fprReg);
-                    frOffset += sizeof(Register);
-                }
-                jit.moveDoubleTo64(fprReg, scratchGPR);
-                jit.store64(scratchGPR, buffer + bufferOffset);
-                ++marshalledFPRs;
-                break;
-            }
-            }
-
-            bufferOffset += sizeof(Register);
-        }
-        jit.loadPtr(MacroAssembler::Address(MacroAssembler::stackPointerRegister), scratchGPR);
-        if (argCount) {
-            // The GC should not look at this buffer at all, these aren't JSValues.
-            jit.move(CCallHelpers::TrustedImmPtr(scratchBuffer->addressOfActiveLength()), GPRInfo::argumentGPR0);
-            jit.storePtr(CCallHelpers::TrustedImmPtr(0), GPRInfo::argumentGPR0);
-        }
-
-        uint64_t (*callFunc)(ExecState*, JSObject*, SignatureIndex, uint64_t*) =
-            [] (ExecState* exec, JSObject* callee, SignatureIndex signatureIndex, uint64_t* buffer) -> uint64_t { 
-                VM* vm = &exec->vm();
-                NativeCallFrameTracer tracer(vm, exec);
-                auto throwScope = DECLARE_THROW_SCOPE(*vm);
-                const Signature& signature = SignatureInformation::get(signatureIndex);
-                MarkedArgumentBuffer args;
-                for (unsigned argNum = 0; argNum < signature.argumentCount(); ++argNum) {
-                    Type argType = signature.argument(argNum);
-                    JSValue arg;
-                    switch (argType) {
-                    case Void:
-                    case Func:
-                    case Anyfunc:
-                    case I64:
-                        RELEASE_ASSERT_NOT_REACHED();
-                    case I32:
-                        arg = jsNumber(static_cast<int32_t>(buffer[argNum]));
-                        break;
-                    case F32:
-                    case F64:
-                        arg = jsNumber(bitwise_cast<double>(buffer[argNum]));
-                        break;
-                    }
-                    args.append(arg);
-                }
-
-                CallData callData;
-                CallType callType = callee->methodTable(*vm)->getCallData(callee, callData);
-                RELEASE_ASSERT(callType != CallType::None);
-                JSValue result = call(exec, callee, callType, callData, jsUndefined(), args);
-                RETURN_IF_EXCEPTION(throwScope, 0);
-
-                uint64_t realResult;
-                switch (signature.returnType()) {
-                case Func:
-                case Anyfunc:
-                case I64:
-                    RELEASE_ASSERT_NOT_REACHED();
-                    break;
-                case Void:
-                    break;
-                case I32: {
-                    realResult = static_cast<uint64_t>(static_cast<uint32_t>(result.toInt32(exec)));
-                    break;
-                }
-                case F64:
-                case F32: {
-                    realResult = bitwise_cast<uint64_t>(result.toNumber(exec));
-                    break;
-                }
-                }
-
-                RETURN_IF_EXCEPTION(throwScope, 0);
-                return realResult;
-            };
-        
-        jit.loadWasmContext(GPRInfo::argumentGPR0);
-        jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0, JSWebAssemblyInstance::offsetOfCallee()), GPRInfo::argumentGPR0);
-        jit.storePtr(GPRInfo::argumentGPR0, JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-        
-        materializeImportJSCell(jit, importIndex, GPRInfo::argumentGPR1);
-        static_assert(GPRInfo::numberOfArgumentRegisters >= 4, "We rely on this with the call below.");
-        jit.setupArgumentsWithExecState(GPRInfo::argumentGPR1, CCallHelpers::TrustedImm32(signatureIndex), CCallHelpers::TrustedImmPtr(buffer));
-        auto call = jit.call();
-        auto noException = jit.emitExceptionCheck(*vm, AssemblyHelpers::InvertedExceptionCheck);
-
-        // exception here.
-        jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(*vm);
-        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-        void (*doUnwinding)(ExecState*) = [] (ExecState* exec) -> void {
-            VM* vm = &exec->vm();
-            NativeCallFrameTracer tracer(vm, exec);
-            genericUnwind(vm, exec);
-            ASSERT(!!vm->callFrameForCatch);
-        };
-        auto exceptionCall = jit.call();
-        jit.jumpToExceptionHandler(*vm);
-
-        noException.link(&jit);
-        switch (signature.returnType()) {
-        case F64: {
-            jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-            break;
-        }
-        case F32: {
-            jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-            jit.convertDoubleToFloat(FPRInfo::returnValueFPR, FPRInfo::returnValueFPR);
-            break;
-        }
-        default:
-            break;
-        }
-
-        jit.emitFunctionEpilogue();
-        jit.ret();
-
-        LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
-        if (UNLIKELY(linkBuffer.didFailToAllocate()))
-            return makeUnexpected(BindingFailure::OutOfMemory);
-
-        linkBuffer.link(call, callFunc);
-        linkBuffer.link(exceptionCall, doUnwinding);
-
-        return FINALIZE_CODE(linkBuffer, ("WebAssembly->JavaScript import[%i] %s", importIndex, signature.toString().ascii().data()));
-    }
-
-    // Note: We don't need to perform a stack check here since WasmB3IRGenerator
-    // will do the stack check for us. Whenever it detects that it might make
-    // a call to this thunk, it'll make sure its stack check includes space
-    // for us here.
-
-    const unsigned numberOfParameters = argCount + 1; // There is a "this" argument.
-    const unsigned numberOfRegsForCall = CallFrame::headerSizeInRegisters + numberOfParameters;
-    const unsigned numberOfBytesForCall = numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC);
-    const unsigned stackOffset = WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall);
-    jit.subPtr(MacroAssembler::TrustedImm32(stackOffset), MacroAssembler::stackPointerRegister);
-    JIT::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC)));
-
-    // FIXME make these loops which switch on Signature if there are many arguments on the stack. It'll otherwise be huge for huge signatures. https://bugs.webkit.org/show_bug.cgi?id=165547
-    
-    // First go through the integer parameters, freeing up their register for use afterwards.
-    {
-        unsigned marshalledGPRs = 0;
-        unsigned marshalledFPRs = 0;
-        unsigned calleeFrameOffset = CallFrameSlot::firstArgument * static_cast<int>(sizeof(Register));
-        unsigned frOffset = CallFrame::headerSizeInRegisters * static_cast<int>(sizeof(Register));
-        for (unsigned argNum = 0; argNum < argCount; ++argNum) {
-            Type argType = signature.argument(argNum);
-            switch (argType) {
-            case Void:
-            case Func:
-            case Anyfunc:
-            case I64:
-                RELEASE_ASSERT_NOT_REACHED(); // Handled above.
-            case I32: {
-                GPRReg gprReg;
-                if (marshalledGPRs < wasmCC.m_gprArgs.size())
-                    gprReg = wasmCC.m_gprArgs[marshalledGPRs].gpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    gprReg = GPRInfo::argumentGPR0;
-                    jit.load64(JIT::Address(GPRInfo::callFrameRegister, frOffset), gprReg);
-                    frOffset += sizeof(Register);
-                }
-                ++marshalledGPRs;
-                jit.zeroExtend32ToPtr(gprReg, gprReg); // Clear non-int32 and non-tag bits.
-                jit.boxInt32(gprReg, JSValueRegs(gprReg), DoNotHaveTagRegisters);
-                jit.store64(gprReg, calleeFrame.withOffset(calleeFrameOffset));
-                calleeFrameOffset += sizeof(Register);
-                break;
-            }
-            case F32:
-            case F64:
-                // Skipped: handled below.
-                if (marshalledFPRs >= wasmCC.m_fprArgs.size())
-                    frOffset += sizeof(Register);
-                ++marshalledFPRs;
-                calleeFrameOffset += sizeof(Register);
-                break;
-            }
-        }
-    }
-    
-    {
-        // Integer registers have already been spilled, these are now available.
-        GPRReg doubleEncodeOffsetGPRReg = GPRInfo::argumentGPR0;
-        GPRReg scratch = GPRInfo::argumentGPR1;
-        bool hasMaterializedDoubleEncodeOffset = false;
-        auto materializeDoubleEncodeOffset = [&hasMaterializedDoubleEncodeOffset, &jit] (GPRReg dest) {
-            if (!hasMaterializedDoubleEncodeOffset) {
-                static_assert(DoubleEncodeOffset == 1ll << 48, "codegen assumes this below");
-                jit.move(JIT::TrustedImm32(1), dest);
-                jit.lshift64(JIT::TrustedImm32(48), dest);
-                hasMaterializedDoubleEncodeOffset = true;
-            }
-        };
-
-        unsigned marshalledGPRs = 0;
-        unsigned marshalledFPRs = 0;
-        unsigned calleeFrameOffset = CallFrameSlot::firstArgument * static_cast<int>(sizeof(Register));
-        unsigned frOffset = CallFrame::headerSizeInRegisters * static_cast<int>(sizeof(Register));
-        for (unsigned argNum = 0; argNum < argCount; ++argNum) {
-            Type argType = signature.argument(argNum);
-            switch (argType) {
-            case Void:
-            case Func:
-            case Anyfunc:
-            case I64:
-                RELEASE_ASSERT_NOT_REACHED(); // Handled above.
-            case I32:
-                // Skipped: handled above.
-                if (marshalledGPRs >= wasmCC.m_gprArgs.size())
-                    frOffset += sizeof(Register);
-                ++marshalledGPRs;
-                calleeFrameOffset += sizeof(Register);
-                break;
-            case F32: {
-                FPRReg fprReg;
-                if (marshalledFPRs < wasmCC.m_fprArgs.size())
-                    fprReg = wasmCC.m_fprArgs[marshalledFPRs].fpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    fprReg = FPRInfo::argumentFPR0;
-                    jit.loadFloat(JIT::Address(GPRInfo::callFrameRegister, frOffset), fprReg);
-                    frOffset += sizeof(Register);
-                }
-                jit.convertFloatToDouble(fprReg, fprReg);
-                jit.purifyNaN(fprReg);
-                jit.moveDoubleTo64(fprReg, scratch);
-                materializeDoubleEncodeOffset(doubleEncodeOffsetGPRReg);
-                jit.add64(doubleEncodeOffsetGPRReg, scratch);
-                jit.store64(scratch, calleeFrame.withOffset(calleeFrameOffset));
-                calleeFrameOffset += sizeof(Register);
-                ++marshalledFPRs;
-                break;
-            }
-            case F64: {
-                FPRReg fprReg;
-                if (marshalledFPRs < wasmCC.m_fprArgs.size())
-                    fprReg = wasmCC.m_fprArgs[marshalledFPRs].fpr();
-                else {
-                    // We've already spilled all arguments, these registers are available as scratch.
-                    fprReg = FPRInfo::argumentFPR0;
-                    jit.loadDouble(JIT::Address(GPRInfo::callFrameRegister, frOffset), fprReg);
-                    frOffset += sizeof(Register);
-                }
-                jit.purifyNaN(fprReg);
-                jit.moveDoubleTo64(fprReg, scratch);
-                materializeDoubleEncodeOffset(doubleEncodeOffsetGPRReg);
-                jit.add64(doubleEncodeOffsetGPRReg, scratch);
-                jit.store64(scratch, calleeFrame.withOffset(calleeFrameOffset));
-                calleeFrameOffset += sizeof(Register);
-                ++marshalledFPRs;
-                break;
-            }
-            }
-        }
-    }
-
-    jit.loadWasmContext(GPRInfo::argumentGPR0);
-    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0, JSWebAssemblyInstance::offsetOfCallee()), GPRInfo::argumentGPR0);
-    jit.storePtr(GPRInfo::argumentGPR0, JIT::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-
-    GPRReg importJSCellGPRReg = GPRInfo::regT0; // Callee needs to be in regT0 for slow path below.
-    ASSERT(!wasmCC.m_calleeSaveRegisters.get(importJSCellGPRReg));
-
-    materializeImportJSCell(jit, importIndex, importJSCellGPRReg);
-
-    jit.store64(importJSCellGPRReg, calleeFrame.withOffset(CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-    jit.store32(JIT::TrustedImm32(numberOfParameters), calleeFrame.withOffset(CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset));
-    jit.store64(JIT::TrustedImm64(ValueUndefined), calleeFrame.withOffset(CallFrameSlot::thisArgument * static_cast<int>(sizeof(Register))));
-
-    // FIXME Tail call if the wasm return type is void and no registers were spilled. https://bugs.webkit.org/show_bug.cgi?id=165488
-
-    CallLinkInfo* callLinkInfo = callLinkInfos.add();
-    callLinkInfo->setUpCall(CallLinkInfo::Call, CodeOrigin(), importJSCellGPRReg);
-    JIT::DataLabelPtr targetToCheck;
-    JIT::TrustedImmPtr initialRightValue(0);
-    JIT::Jump slowPath = jit.branchPtrWithPatch(MacroAssembler::NotEqual, importJSCellGPRReg, targetToCheck, initialRightValue);
-    JIT::Call fastCall = jit.nearCall();
-    JIT::Jump done = jit.jump();
-    slowPath.link(&jit);
-    // Callee needs to be in regT0 here.
-    jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2.
-    JIT::Call slowCall = jit.nearCall();
-    done.link(&jit);
-
-    CCallHelpers::JumpList exceptionChecks;
-
-    switch (signature.returnType()) {
-    case Void:
-        // Discard.
-        break;
-    case Func:
-    case Anyfunc:
-        // For the JavaScript embedding, imports with these types in their signature return are a WebAssembly.Module validation error.
-        RELEASE_ASSERT_NOT_REACHED();
-        break;
-    case I64: {
-        RELEASE_ASSERT_NOT_REACHED(); // Handled above.
-    }
-    case I32: {
-        CCallHelpers::JumpList done;
-        CCallHelpers::JumpList slowPath;
-
-        slowPath.append(jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters));
-        slowPath.append(jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters));
-        jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR);
-        done.append(jit.jump());
-
-        slowPath.link(&jit);
-        jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR);
-        auto call = jit.call();
-        exceptionChecks.append(jit.emitJumpIfException(*vm));
-
-        int32_t (*convertToI32)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> int32_t { 
-            VM* vm = &exec->vm();
-            NativeCallFrameTracer tracer(vm, exec);
-            return v.toInt32(exec);
-        };
-        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-            linkBuffer.link(call, convertToI32);
-        });
-
-        done.link(&jit);
-        break;
-    }
-    case F32: {
-        CCallHelpers::JumpList done;
-        auto notANumber = jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters);
-        auto isDouble = jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters);
-        // We're an int32
-        jit.signExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR);
-        jit.convertInt64ToFloat(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-        done.append(jit.jump());
-
-        isDouble.link(&jit);
-        jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2);
-        jit.add64(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
-        jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-        jit.convertDoubleToFloat(FPRInfo::returnValueFPR, FPRInfo::returnValueFPR);
-        done.append(jit.jump());
-
-        notANumber.link(&jit);
-        jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR);
-        auto call = jit.call();
-        exceptionChecks.append(jit.emitJumpIfException(*vm));
-
-        float (*convertToF32)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> float { 
-            VM* vm = &exec->vm();
-            NativeCallFrameTracer tracer(vm, exec);
-            return static_cast<float>(v.toNumber(exec));
-        };
-        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-            linkBuffer.link(call, convertToF32);
-        });
-
-        done.link(&jit);
-        break;
-    }
-    case F64: {
-        CCallHelpers::JumpList done;
-        auto notANumber = jit.branchIfNotNumber(GPRInfo::returnValueGPR, DoNotHaveTagRegisters);
-        auto isDouble = jit.branchIfNotInt32(JSValueRegs(GPRInfo::returnValueGPR), DoNotHaveTagRegisters);
-        // We're an int32
-        jit.signExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR);
-        jit.convertInt64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-        done.append(jit.jump());
-
-        isDouble.link(&jit);
-        jit.move(JIT::TrustedImm64(TagTypeNumber), GPRInfo::returnValueGPR2);
-        jit.add64(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
-        jit.move64ToDouble(GPRInfo::returnValueGPR, FPRInfo::returnValueFPR);
-        done.append(jit.jump());
-
-        notANumber.link(&jit);
-        jit.setupArgumentsWithExecState(GPRInfo::returnValueGPR);
-        auto call = jit.call();
-        exceptionChecks.append(jit.emitJumpIfException(*vm));
-
-        double (*convertToF64)(ExecState*, JSValue) = [] (ExecState* exec, JSValue v) -> double { 
-            VM* vm = &exec->vm();
-            NativeCallFrameTracer tracer(vm, exec);
-            return v.toNumber(exec);
-        };
-        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-            linkBuffer.link(call, convertToF64);
-        });
-
-        done.link(&jit);
-        break;
-    }
-    }
-
-    jit.emitFunctionEpilogue();
-    jit.ret();
-
-    if (!exceptionChecks.empty()) {
-        exceptionChecks.link(&jit);
-        jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(*vm);
-        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-        auto call = jit.call();
-        jit.jumpToExceptionHandler(*vm);
-
-        void (*doUnwinding)(ExecState*) = [] (ExecState* exec) -> void {
-            VM* vm = &exec->vm();
-            NativeCallFrameTracer tracer(vm, exec);
-            genericUnwind(vm, exec);
-            ASSERT(!!vm->callFrameForCatch);
-        };
-
-        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-            linkBuffer.link(call, doUnwinding);
-        });
-    }
-
-    LinkBuffer patchBuffer(jit, GLOBAL_THUNK_ID, JITCompilationCanFail);
-    if (UNLIKELY(patchBuffer.didFailToAllocate()))
-        return makeUnexpected(BindingFailure::OutOfMemory);
-
-    patchBuffer.link(slowCall, FunctionPtr(vm->getCTIStub(linkCallThunkGenerator).code().executableAddress()));
-    CodeLocationLabel callReturnLocation(patchBuffer.locationOfNearCall(slowCall));
-    CodeLocationLabel hotPathBegin(patchBuffer.locationOf(targetToCheck));
-    CodeLocationNearCall hotPathOther = patchBuffer.locationOfNearCall(fastCall);
-    callLinkInfo->setCallLocations(callReturnLocation, hotPathBegin, hotPathOther);
-
-    return FINALIZE_CODE(patchBuffer, ("WebAssembly->JavaScript import[%i] %s", importIndex, signature.toString().ascii().data()));
-}
-
 Expected<MacroAssemblerCodeRef, BindingFailure> wasmToWasm(unsigned importIndex)
 {
     const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
@@ -633,24 +51,23 @@
     ASSERT(sizeRegs[0].sizeRegister != scratch);
     GPRReg sizeRegAsScratch = sizeRegs[0].sizeRegister;
 
-    static_assert(std::is_same<Context, JSWebAssemblyInstance>::value, "This is assumed in the code below.");
     // B3's call codegen ensures that the JSCell is a WebAssemblyFunction.
-    jit.loadWasmContext(sizeRegAsScratch); // Old Instance*
-    jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfImportFunction(importIndex)), scratch);
-
-    // Get the callee's WebAssembly.Instance and set it as WasmContext. The caller will take care of restoring its own Instance.
-    jit.loadPtr(JIT::Address(scratch, WebAssemblyFunction::offsetOfInstance()), baseMemory); // Instance*.
-    jit.storeWasmContext(baseMemory);
+    jit.loadWasmContextInstance(sizeRegAsScratch); // Old Instance*
+    // Get the callee's WebAssembly.Instance and set it as WasmContext's instance. The caller will take care of restoring its own Instance.
+    jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfTargetInstance(importIndex)), baseMemory); // JSWebAssemblyInstance*.
+    // While we're accessing that cacheline, also get the wasm entrypoint so we can tail call to it below.
+    jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfWasmEntrypoint(importIndex)), scratch); // Wasm::WasmEntrypointLoadLocation.
+    jit.storeWasmContextInstance(baseMemory);
 
     jit.loadPtr(JIT::Address(sizeRegAsScratch, JSWebAssemblyInstance::offsetOfCachedStackLimit()), sizeRegAsScratch);
     jit.storePtr(sizeRegAsScratch, JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfCachedStackLimit()));
 
     // FIXME the following code assumes that all WebAssembly.Instance have the same pinned registers. https://bugs.webkit.org/show_bug.cgi?id=162952
     // Set up the callee's baseMemory register as well as the memory size registers.
-    jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory); // JSWebAssemblyMemory*.
+    jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyInstance::offsetOfWasmMemory()), baseMemory); // Wasm::Memory*.
     ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
-    jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
-    jit.loadPtr(JIT::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); // WasmMemory::void*.
+    jit.loadPtr(JIT::Address(baseMemory, Wasm::Memory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
+    jit.loadPtr(JIT::Address(baseMemory, Wasm::Memory::offsetOfMemory()), baseMemory); // Wasm::Memory::void*.
     for (unsigned i = 1; i < sizeRegs.size(); ++i) {
         ASSERT(sizeRegs[i].sizeRegister != baseMemory);
         ASSERT(sizeRegs[i].sizeRegister != scratch);
@@ -658,7 +75,6 @@
     }
 
     // Tail call into the callee WebAssembly function.
-    jit.loadPtr(JIT::Address(scratch, WebAssemblyFunction::offsetOfWasmEntrypointLoadLocation()), scratch);
     jit.loadPtr(scratch, scratch);
     jit.jump(scratch);