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/WasmB3IRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
index bac8dc1..4503cda 100644
--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
@@ -49,8 +49,6 @@
 #include "B3WasmBoundsCheckValue.h"
 #include "JSCInlines.h"
 #include "JSWebAssemblyInstance.h"
-#include "JSWebAssemblyModule.h"
-#include "JSWebAssemblyRuntimeError.h"
 #include "ScratchRegisterAllocator.h"
 #include "VirtualRegister.h"
 #include "WasmCallingConvention.h"
@@ -178,7 +176,7 @@
             return fail(__VA_ARGS__);             \
     } while (0)
 
-    B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, CompilationMode, unsigned functionIndex, TierUpCount*);
+    B3IRGenerator(const ModuleInformation&, Procedure&, InternalFunction*, Vector<UnlinkedWasmToWasmCall>&, MemoryMode, CompilationMode, unsigned functionIndex, TierUpCount*, ThrowWasmException);
 
     PartialResult WARN_UNUSED_RETURN addArguments(const Signature&);
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
@@ -247,7 +245,7 @@
 
     int32_t WARN_UNUSED_RETURN fixupPointerPlusOffset(ExpressionType&, uint32_t);
 
-    void restoreWasmContext(Procedure&, BasicBlock*, Value*);
+    void restoreWasmContextInstance(Procedure&, BasicBlock*, Value*);
     void restoreWebAssemblyGlobalState(const MemoryInformation&, Value* instance, Procedure&, BasicBlock*);
 
     Origin origin();
@@ -267,7 +265,7 @@
     InsertionSet m_constantInsertionValues;
     GPRReg m_memoryBaseGPR { InvalidGPRReg };
     GPRReg m_memorySizeGPR { InvalidGPRReg };
-    GPRReg m_wasmContextGPR { InvalidGPRReg };
+    GPRReg m_wasmContextInstanceGPR { InvalidGPRReg };
     bool m_makesCalls { false };
 
     Value* m_instanceValue { nullptr }; // Always use the accessor below to ensure the instance value is materialized when used.
@@ -291,37 +289,37 @@
     return offset;
 }
 
-void B3IRGenerator::restoreWasmContext(Procedure& proc, BasicBlock* block, Value* arg)
+void B3IRGenerator::restoreWasmContextInstance(Procedure& proc, BasicBlock* block, Value* arg)
 {
-    if (useFastTLSForContext()) {
+    if (Context::useFastTLS()) {
         PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, B3::Void, Origin());
-        if (CCallHelpers::storeWasmContextNeedsMacroScratchRegister())
+        if (CCallHelpers::storeWasmContextInstanceNeedsMacroScratchRegister())
             patchpoint->clobber(RegisterSet::macroScratchRegisters());
         patchpoint->append(ConstrainedValue(arg, ValueRep::SomeRegister));
         patchpoint->setGenerator(
             [=] (CCallHelpers& jit, const StackmapGenerationParams& params) {
-                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::storeWasmContextNeedsMacroScratchRegister());
-                jit.storeWasmContext(params[0].gpr());
+                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::storeWasmContextInstanceNeedsMacroScratchRegister());
+                jit.storeWasmContextInstance(params[0].gpr());
             });
         return;
     }
 
-    // FIXME: Because WasmToWasm call clobbers wasmContext register and does not restore it, we need to restore it in the caller side.
+    // FIXME: Because WasmToWasm call clobbers wasmContextInstance register and does not restore it, we need to restore it in the caller side.
     // This prevents us from using ArgumentReg to this (logically) immutable pinned register.
     PatchpointValue* patchpoint = block->appendNew<PatchpointValue>(proc, B3::Void, Origin());
     Effects effects = Effects::none();
     effects.writesPinned = true;
     effects.reads = B3::HeapRange::top();
     patchpoint->effects = effects;
-    patchpoint->clobberLate(RegisterSet(m_wasmContextGPR));
+    patchpoint->clobberLate(RegisterSet(m_wasmContextInstanceGPR));
     patchpoint->append(instanceValue(), ValueRep::SomeRegister);
-    GPRReg wasmContextGPR = m_wasmContextGPR;
+    GPRReg wasmContextInstanceGPR = m_wasmContextInstanceGPR;
     patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& param) {
-        jit.move(param[0].gpr(), wasmContextGPR);
+        jit.move(param[0].gpr(), wasmContextInstanceGPR);
     });
 }
 
-B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, TierUpCount* tierUp)
+B3IRGenerator::B3IRGenerator(const ModuleInformation& info, Procedure& procedure, InternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, MemoryMode mode, CompilationMode compilationMode, unsigned functionIndex, TierUpCount* tierUp, ThrowWasmException throwWasmException)
     : m_info(info)
     , m_mode(mode)
     , m_compilationMode(compilationMode)
@@ -339,9 +337,9 @@
     m_memoryBaseGPR = pinnedRegs.baseMemoryPointer;
     m_proc.pinRegister(m_memoryBaseGPR);
 
-    m_wasmContextGPR = pinnedRegs.wasmContextPointer;
-    if (!useFastTLSForContext())
-        m_proc.pinRegister(m_wasmContextGPR);
+    m_wasmContextInstanceGPR = pinnedRegs.wasmContextInstancePointer;
+    if (!Context::useFastTLS())
+        m_proc.pinRegister(m_wasmContextInstanceGPR);
 
     if (mode != MemoryMode::Signaling) {
         ASSERT(!pinnedRegs.sizeRegisters[0].sizeOffset);
@@ -350,6 +348,9 @@
             m_proc.pinRegister(regInfo.sizeRegister);
     }
 
+    if (throwWasmException)
+        Thunks::singleton().setThrowWasmException(throwWasmException);
+
     if (info.memory) {
         m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
@@ -363,6 +364,19 @@
             }
             this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsMemoryAccess);
         });
+
+        switch (m_mode) {
+        case MemoryMode::BoundsChecking:
+            break;
+        case MemoryMode::Signaling:
+            // Most memory accesses in signaling mode don't do an explicit
+            // exception check because they can rely on fault handling to detect
+            // out-of-bounds accesses. FaultSignalHandler nonetheless needs the
+            // thunk to exist so that it can jump to that thunk.
+            if (UNLIKELY(!Thunks::singleton().stub(throwExceptionFromWasmThunkGenerator)))
+                CRASH();
+            break;
+        }
     }
 
     wasmCallingConvention().setupFrameInPrologue(&compilation->calleeMoveLocation, m_proc, Origin(), m_currentBlock);
@@ -373,12 +387,12 @@
         m_instanceValue = stackOverflowCheck;
         stackOverflowCheck->appendSomeRegister(framePointer);
         stackOverflowCheck->clobber(RegisterSet::macroScratchRegisters());
-        if (!useFastTLSForContext()) {
-            // FIXME: Because WasmToWasm call clobbers wasmContext register and does not restore it, we need to restore it in the caller side.
+        if (!Context::useFastTLS()) {
+            // FIXME: Because WasmToWasm call clobbers wasmContextInstance register and does not restore it, we need to restore it in the caller side.
             // This prevents us from using ArgumentReg to this (logically) immutable pinned register.
             stackOverflowCheck->effects.writesPinned = false;
             stackOverflowCheck->effects.readsPinned = true;
-            stackOverflowCheck->resultConstraint = ValueRep::reg(m_wasmContextGPR);
+            stackOverflowCheck->resultConstraint = ValueRep::reg(m_wasmContextInstanceGPR);
         }
         stackOverflowCheck->numGPScratchRegisters = 2;
         stackOverflowCheck->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
@@ -401,7 +415,7 @@
             bool needUnderflowCheck = static_cast<unsigned>(checkSize) > Options::reservedZoneSize();
             bool needsOverflowCheck = m_makesCalls || wasmFrameSize >= minimumParentCheckSize || needUnderflowCheck;
 
-            GPRReg context = useFastTLSForContext() ? params[0].gpr() : m_wasmContextGPR;
+            GPRReg contextInstance = Context::useFastTLS() ? params[0].gpr() : m_wasmContextInstanceGPR;
 
             // This allows leaf functions to not do stack checks if their frame size is within
             // certain limits since their caller would have already done the check.
@@ -411,10 +425,10 @@
                 GPRReg scratch1 = params.gpScratch(0);
                 GPRReg scratch2 = params.gpScratch(1);
 
-                if (useFastTLSForContext())
-                    jit.loadWasmContext(context);
+                if (Context::useFastTLS())
+                    jit.loadWasmContextInstance(contextInstance);
 
-                jit.loadPtr(CCallHelpers::Address(context, Context::offsetOfCachedStackLimit()), scratch2);
+                jit.loadPtr(CCallHelpers::Address(contextInstance, JSWebAssemblyInstance::offsetOfCachedStackLimit()), scratch2);
                 jit.addPtr(CCallHelpers::TrustedImm32(-checkSize), fp, scratch1);
                 MacroAssembler::JumpList overflow;
                 if (UNLIKELY(needUnderflowCheck))
@@ -423,10 +437,10 @@
                 jit.addLinkTask([overflow] (LinkBuffer& linkBuffer) {
                     linkBuffer.link(overflow, CodeLocationLabel(Thunks::singleton().stub(throwStackOverflowFromWasmThunkGenerator).code()));
                 });
-            } else if (m_usesInstanceValue && useFastTLSForContext()) {
+            } else if (m_usesInstanceValue && Context::useFastTLS()) {
                 // No overflow check is needed, but the instance values still needs to be correct.
-                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::loadWasmContextNeedsMacroScratchRegister());
-                jit.loadWasmContext(context);
+                AllowMacroScratchRegisterUsageIf allowScratch(jit, CCallHelpers::loadWasmContextInstanceNeedsMacroScratchRegister());
+                jit.loadWasmContextInstance(contextInstance);
             } else {
                 // We said we'd return a pointer. We don't actually need to because it isn't used, but the patchpoint conservatively said it had effects (potential stack check) which prevent it from getting removed.
             }
@@ -438,7 +452,7 @@
 
 void B3IRGenerator::restoreWebAssemblyGlobalState(const MemoryInformation& memory, Value* instance, Procedure& proc, BasicBlock* block)
 {
-    restoreWasmContext(proc, block, instance);
+    restoreWasmContextInstance(proc, block, instance);
 
     if (!!memory) {
         const PinnedRegisterInfo* pinnedRegs = &PinnedRegisterInfo::get();
@@ -458,12 +472,12 @@
 
         patchpoint->setGenerator([pinnedRegs] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
             GPRReg baseMemory = pinnedRegs->baseMemoryPointer;
-            jit.loadPtr(CCallHelpers::Address(params[0].gpr(), JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
+            jit.loadPtr(CCallHelpers::Address(params[0].gpr(), JSWebAssemblyInstance::offsetOfWasmMemory()), baseMemory);
             const auto& sizeRegs = pinnedRegs->sizeRegisters;
             ASSERT(sizeRegs.size() >= 1);
             ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister);
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, Memory::offsetOfSize()), sizeRegs[0].sizeRegister);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, Memory::offsetOfMemory()), baseMemory);
             for (unsigned i = 1; i < sizeRegs.size(); ++i)
                 jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
         });
@@ -541,24 +555,22 @@
 
 auto B3IRGenerator::addGrowMemory(ExpressionType delta, ExpressionType& result) -> PartialResult
 {
-    int32_t (*growMemory) (Context*, int32_t) = [] (Context* wasmContext, int32_t delta) -> int32_t {
-        VM& vm = *wasmContext->vm();
-        auto scope = DECLARE_THROW_SCOPE(vm);
-
-        JSWebAssemblyMemory* wasmMemory = wasmContext->memory();
-
+    int32_t (*growMemory)(JSWebAssemblyInstance*, int32_t) = [] (JSWebAssemblyInstance* instance, int32_t delta) -> int32_t {
         if (delta < 0)
             return -1;
 
-        bool shouldThrowExceptionsOnFailure = false;
-        // grow() does not require ExecState* if it doesn't throw exceptions.
-        ExecState* exec = nullptr;
-        PageCount result = wasmMemory->grow(vm, exec, static_cast<uint32_t>(delta), shouldThrowExceptionsOnFailure);
-        scope.releaseAssertNoException();
-        if (!result)
-            return -1;
+        auto grown = instance->internalMemory().grow(PageCount(delta));
+        if (!grown) {
+            switch (grown.error()) {
+            case Memory::GrowFailReason::InvalidDelta:
+            case Memory::GrowFailReason::InvalidGrowSize:
+            case Memory::GrowFailReason::WouldExceedMaximum:
+            case Memory::GrowFailReason::OutOfMemory:
+                return -1;
+            }
+        }
 
-        return result.pageCount();
+        return grown.value().pageCount();
     };
 
     result = m_currentBlock->appendNew<CCallValue>(m_proc, Int32, origin(),
@@ -572,13 +584,13 @@
 
 auto B3IRGenerator::addCurrentMemory(ExpressionType& result) -> PartialResult
 {
-    Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfMemory()));
+    Value* memoryObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfWasmMemory()));
 
-    static_assert(sizeof(decltype(static_cast<JSWebAssemblyInstance*>(nullptr)->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
-    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, safeCast<int32_t>(JSWebAssemblyMemory::offsetOfSize()));
+    static_assert(sizeof(decltype(static_cast<Memory*>(nullptr)->size())) == sizeof(uint64_t), "codegen relies on this size");
+    Value* size = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin(), memoryObject, safeCast<int32_t>(Memory::offsetOfSize()));
     
     constexpr uint32_t shiftValue = 16;
-    static_assert(PageCount::pageSize == 1 << shiftValue, "This must hold for the code below to be correct.");
+    static_assert(PageCount::pageSize == 1ull << shiftValue, "This must hold for the code below to be correct.");
     Value* numPages = m_currentBlock->appendNew<Value>(m_proc, ZShr, origin(),
         size, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), shiftValue));
 
@@ -1069,14 +1081,13 @@
         m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
 
         // FIXME imports can be linked here, instead of generating a patchpoint, because all import stubs are generated before B3 compilation starts. https://bugs.webkit.org/show_bug.cgi?id=166462
-        Value* functionImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfImportFunction(functionIndex)));
-        Value* jsTypeOfImport = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin(), functionImport, safeCast<int32_t>(JSCell::typeInfoTypeOffset()));
-        Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), jsTypeOfImport, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), WebAssemblyFunctionType));
+        Value* targetInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfTargetInstance(functionIndex)));
+        Value* isWasmCall = m_currentBlock->appendNew<Value>(m_proc, NotEqual, origin(), targetInstance, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), 0));
 
         BasicBlock* isWasmBlock = m_proc.addBlock();
-        BasicBlock* isJSBlock = m_proc.addBlock();
+        BasicBlock* isEmbedderBlock = m_proc.addBlock();
         BasicBlock* continuation = m_proc.addBlock();
-        m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(), isWasmCall, FrequentedBlock(isWasmBlock), FrequentedBlock(isJSBlock));
+        m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(), isWasmCall, FrequentedBlock(isWasmBlock), FrequentedBlock(isEmbedderBlock));
 
         Value* wasmCallResult = wasmCallingConvention().setupCall(m_proc, isWasmBlock, origin(), args, toB3Type(returnType),
             [=] (PatchpointValue* patchpoint) {
@@ -1097,15 +1108,13 @@
         UpsilonValue* wasmCallResultUpsilon = returnType == Void ? nullptr : isWasmBlock->appendNew<UpsilonValue>(m_proc, origin(), wasmCallResult);
         isWasmBlock->appendNewControlValue(m_proc, Jump, origin(), continuation);
 
-        // FIXME: Lets remove this indirection by creating a PIC friendly IC
+        // FIXME: Let's remove this indirection by creating a PIC friendly IC
         // for calls out to JS. This shouldn't be that hard to do. We could probably
-        // implement the IC to be over Wasm::Context*.
+        // implement the IC to be over Context*.
         // https://bugs.webkit.org/show_bug.cgi?id=170375
-        Value* codeBlock = isJSBlock->appendNew<MemoryValue>(m_proc,
-            Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfCodeBlock()));
-        Value* jumpDestination = isJSBlock->appendNew<MemoryValue>(m_proc,
-            Load, pointerType(), origin(), codeBlock, safeCast<int32_t>(JSWebAssemblyCodeBlock::offsetOfImportWasmToJSStub(functionIndex)));
-        Value* jsCallResult = wasmCallingConvention().setupCall(m_proc, isJSBlock, origin(), args, toB3Type(returnType),
+        Value* jumpDestination = isEmbedderBlock->appendNew<MemoryValue>(m_proc,
+            Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfWasmToEmbedderStubExecutableAddress(functionIndex)));
+        Value* embedderCallResult = wasmCallingConvention().setupCall(m_proc, isEmbedderBlock, origin(), args, toB3Type(returnType),
             [&] (PatchpointValue* patchpoint) {
                 patchpoint->effects.writesPinned = true;
                 patchpoint->effects.readsPinned = true;
@@ -1119,8 +1128,8 @@
                     jit.call(params[returnType == Void ? 0 : 1].gpr());
                 });
             });
-        UpsilonValue* jsCallResultUpsilon = returnType == Void ? nullptr : isJSBlock->appendNew<UpsilonValue>(m_proc, origin(), jsCallResult);
-        isJSBlock->appendNewControlValue(m_proc, Jump, origin(), continuation);
+        UpsilonValue* embedderCallResultUpsilon = returnType == Void ? nullptr : isEmbedderBlock->appendNew<UpsilonValue>(m_proc, origin(), embedderCallResult);
+        isEmbedderBlock->appendNewControlValue(m_proc, Jump, origin(), continuation);
 
         m_currentBlock = continuation;
 
@@ -1129,7 +1138,7 @@
         else {
             result = continuation->appendNew<Value>(m_proc, Phi, toB3Type(returnType), origin());
             wasmCallResultUpsilon->setPhi(result);
-            jsCallResultUpsilon->setPhi(result);
+            embedderCallResultUpsilon->setPhi(result);
         }
 
         // The call could have been to another WebAssembly instance, and / or could have modified our Memory.
@@ -1165,17 +1174,17 @@
     m_maxNumJSCallArguments = std::max(m_maxNumJSCallArguments, static_cast<uint32_t>(args.size()));
 
     ExpressionType callableFunctionBuffer;
-    ExpressionType jsFunctionBuffer;
+    ExpressionType instancesBuffer;
     ExpressionType callableFunctionBufferSize;
     {
         ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfTable()));
+            instanceValue(), safeCast<int32_t>(JSWebAssemblyInstance::offsetOfWasmTable()));
         callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfFunctions()));
-        jsFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfJSFunctions()));
+            table, safeCast<int32_t>(Table::offsetOfFunctions()));
+        instancesBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+            table, safeCast<int32_t>(Table::offsetOfInstances()));
         callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(),
-            table, safeCast<int32_t>(JSWebAssemblyTable::offsetOfSize()));
+            table, safeCast<int32_t>(Table::offsetOfSize()));
     }
 
     // Check the index we are looking for is valid.
@@ -1195,6 +1204,7 @@
     ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, origin(), callableFunctionBuffer, offset);
 
     // Check that the CallableFunction is initialized. We trap if it isn't. An "invalid" SignatureIndex indicates it's not initialized.
+    // FIXME: when we have trap handlers, we can just let the call fail because Signature::invalidIndex is 0. https://bugs.webkit.org/show_bug.cgi?id=177210
     static_assert(sizeof(CallableFunction::signatureIndex) == sizeof(uint32_t), "Load codegen assumes i32");
     ExpressionType calleeSignatureIndex = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(), callableFunction, safeCast<int32_t>(OBJECT_OFFSETOF(CallableFunction, signatureIndex)));
     {
@@ -1223,19 +1233,17 @@
     {
         Value* offset = m_currentBlock->appendNew<Value>(m_proc, Mul, origin(),
             m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin(), calleeIndex),
-            constant(pointerType(), sizeof(WriteBarrier<JSObject>)));
-        Value* jsObject = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            m_currentBlock->appendNew<Value>(m_proc, Add, origin(), jsFunctionBuffer, offset));
+            constant(pointerType(), sizeof(Instance*)));
+        Value* newContextInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
+            m_currentBlock->appendNew<Value>(m_proc, Add, origin(), instancesBuffer, offset));
 
         BasicBlock* continuation = m_proc.addBlock();
         BasicBlock* doContextSwitch = m_proc.addBlock();
 
-        Value* newContext = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            jsObject, safeCast<int32_t>(WebAssemblyFunctionBase::offsetOfInstance()));
-        Value* isSameContext = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
-            newContext, instanceValue());
+        Value* isSameContextInstance = m_currentBlock->appendNew<Value>(m_proc, Equal, origin(),
+            newContextInstance, instanceValue());
         m_currentBlock->appendNewControlValue(m_proc, B3::Branch, origin(),
-            isSameContext, FrequentedBlock(continuation), FrequentedBlock(doContextSwitch));
+            isSameContextInstance, FrequentedBlock(continuation), FrequentedBlock(doContextSwitch));
 
         PatchpointValue* patchpoint = doContextSwitch->appendNew<PatchpointValue>(m_proc, B3::Void, origin());
         patchpoint->effects.writesPinned = true;
@@ -1243,26 +1251,26 @@
         // FIXME: We shouldn't have to do this: https://bugs.webkit.org/show_bug.cgi?id=172181
         patchpoint->clobber(PinnedRegisterInfo::get().toSave(MemoryMode::BoundsChecking));
         patchpoint->clobber(RegisterSet::macroScratchRegisters());
-        patchpoint->append(newContext, ValueRep::SomeRegister);
+        patchpoint->append(newContextInstance, ValueRep::SomeRegister);
         patchpoint->append(instanceValue(), ValueRep::SomeRegister);
         patchpoint->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams& params) {
             AllowMacroScratchRegisterUsage allowScratch(jit);
-            GPRReg newContext = params[0].gpr();
-            GPRReg oldContext = params[1].gpr();
+            GPRReg newContextInstance = params[0].gpr();
+            GPRReg oldContextInstance = params[1].gpr();
             const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
             const auto& sizeRegs = pinnedRegs.sizeRegisters;
             GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-            ASSERT(newContext != baseMemory);
-            jit.loadPtr(CCallHelpers::Address(oldContext, Context::offsetOfCachedStackLimit()), baseMemory);
-            jit.storePtr(baseMemory, CCallHelpers::Address(newContext, Context::offsetOfCachedStackLimit()));
-            jit.storeWasmContext(newContext);
-            jit.loadPtr(CCallHelpers::Address(newContext, Context::offsetOfMemory()), baseMemory); // JSWebAssemblyMemory*.
+            ASSERT(newContextInstance != baseMemory);
+            jit.loadPtr(CCallHelpers::Address(oldContextInstance, JSWebAssemblyInstance::offsetOfCachedStackLimit()), baseMemory);
+            jit.storePtr(baseMemory, CCallHelpers::Address(newContextInstance, JSWebAssemblyInstance::offsetOfCachedStackLimit()));
+            jit.storeWasmContextInstance(newContextInstance);
+            jit.loadPtr(CCallHelpers::Address(newContextInstance, JSWebAssemblyInstance::offsetOfWasmMemory()), baseMemory); // Memory*.
             ASSERT(sizeRegs.size() == 1);
             ASSERT(sizeRegs[0].sizeRegister != baseMemory);
-            ASSERT(sizeRegs[0].sizeRegister != newContext);
+            ASSERT(sizeRegs[0].sizeRegister != newContextInstance);
             ASSERT(!sizeRegs[0].sizeOffset);
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory); // WasmMemory::void*.
+            jit.loadPtr(CCallHelpers::Address(baseMemory, Memory::offsetOfSize()), sizeRegs[0].sizeRegister); // Memory size.
+            jit.loadPtr(CCallHelpers::Address(baseMemory, Memory::offsetOfMemory()), baseMemory); // Memory::void*.
         });
         doContextSwitch->appendNewControlValue(m_proc, Jump, origin(), continuation);
 
@@ -1339,194 +1347,6 @@
     dataLogLn();
 }
 
-std::unique_ptr<InternalFunction> createJSToWasmWrapper(CompilationContext& compilationContext, const Signature& signature, Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, unsigned functionIndex)
-{
-    CCallHelpers& jit = *compilationContext.jsEntrypointJIT;
-
-    auto result = std::make_unique<InternalFunction>();
-    jit.emitFunctionPrologue();
-
-    // FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321
-    jit.store64(CCallHelpers::TrustedImm64(0), CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register))));
-    MacroAssembler::DataLabelPtr calleeMoveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), GPRInfo::nonPreservedNonReturnGPR);
-    jit.storePtr(GPRInfo::nonPreservedNonReturnGPR, CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
-    CodeLocationDataLabelPtr* linkedCalleeMove = &result->calleeMoveLocation;
-    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-        *linkedCalleeMove = linkBuffer.locationOf(calleeMoveLocation);
-    });
-
-    const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
-    RegisterSet toSave = pinnedRegs.toSave(mode);
-
-#if !ASSERT_DISABLED
-    unsigned toSaveSize = toSave.numberOfSetGPRs();
-    // They should all be callee saves.
-    toSave.filter(RegisterSet::calleeSaveRegisters());
-    ASSERT(toSave.numberOfSetGPRs() == toSaveSize);
-#endif
-
-    RegisterAtOffsetList registersToSpill(toSave, RegisterAtOffsetList::OffsetBaseType::FramePointerBased);
-    result->entrypoint.calleeSaveRegisters = registersToSpill;
-
-    unsigned totalFrameSize = registersToSpill.size() * sizeof(void*);
-    totalFrameSize += WasmCallingConvention::headerSizeInBytes();
-    totalFrameSize -= sizeof(CallerFrameAndPC);
-    unsigned numGPRs = 0;
-    unsigned numFPRs = 0;
-    for (unsigned i = 0; i < signature.argumentCount(); i++) {
-        switch (signature.argument(i)) {
-        case Wasm::I64:
-        case Wasm::I32:
-            if (numGPRs >= wasmCallingConvention().m_gprArgs.size())
-                totalFrameSize += sizeof(void*);
-            ++numGPRs;
-            break;
-        case Wasm::F32:
-        case Wasm::F64:
-            if (numFPRs >= wasmCallingConvention().m_fprArgs.size())
-                totalFrameSize += sizeof(void*);
-            ++numFPRs;
-            break;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-    }
-
-    totalFrameSize = WTF::roundUpToMultipleOf(stackAlignmentBytes(), totalFrameSize);
-    jit.subPtr(MacroAssembler::TrustedImm32(totalFrameSize), MacroAssembler::stackPointerRegister);
-
-    // We save all these registers regardless of having a memory or not.
-    // The reason is that we use one of these as a scratch. That said,
-    // almost all real wasm programs use memory, so it's not really
-    // worth optimizing for the case that they don't.
-    for (const RegisterAtOffset& regAtOffset : registersToSpill) {
-        GPRReg reg = regAtOffset.reg().gpr();
-        ptrdiff_t offset = regAtOffset.offset();
-        jit.storePtr(reg, CCallHelpers::Address(GPRInfo::callFrameRegister, offset));
-    }
-
-    GPRReg wasmContextGPR = pinnedRegs.wasmContextPointer;
-
-    {
-        CCallHelpers::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC)));
-        numGPRs = 0;
-        numFPRs = 0;
-        // We're going to set the pinned registers after this. So
-        // we can use this as a scratch for now since we saved it above.
-        GPRReg scratchReg = pinnedRegs.baseMemoryPointer;
-
-        ptrdiff_t jsOffset = CallFrameSlot::thisArgument * sizeof(EncodedJSValue);
-
-        // vmEntryToWasm passes Wasm::Context* as the first JS argument when we're
-        // not using fast TLS to hold the Wasm::Context*.
-        if (!useFastTLSForContext()) {
-            jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmContextGPR);
-            jsOffset += sizeof(EncodedJSValue);
-        }
-
-        ptrdiff_t wasmOffset = CallFrame::headerSizeInRegisters * sizeof(void*);
-        for (unsigned i = 0; i < signature.argumentCount(); i++) {
-            switch (signature.argument(i)) {
-            case Wasm::I32:
-            case Wasm::I64:
-                if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) {
-                    if (signature.argument(i) == Wasm::I32) {
-                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
-                        jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset));
-                    } else {
-                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
-                        jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset));
-                    }
-                    wasmOffset += sizeof(void*);
-                } else {
-                    if (signature.argument(i) == Wasm::I32)
-                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr());
-                    else
-                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr());
-                }
-                ++numGPRs;
-                break;
-            case Wasm::F32:
-            case Wasm::F64:
-                if (numFPRs >= wasmCallingConvention().m_fprArgs.size()) {
-                    if (signature.argument(i) == Wasm::F32) {
-                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
-                        jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset));
-                    } else {
-                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
-                        jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset));
-                    }
-                    wasmOffset += sizeof(void*);
-                } else {
-                    if (signature.argument(i) == Wasm::F32)
-                        jit.loadFloat(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr());
-                    else
-                        jit.loadDouble(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr());
-                }
-                ++numFPRs;
-                break;
-            default:
-                RELEASE_ASSERT_NOT_REACHED();
-            }
-
-            jsOffset += sizeof(EncodedJSValue);
-        }
-    }
-
-    if (!!info.memory) {
-        GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
-
-        if (!useFastTLSForContext())
-            jit.loadPtr(CCallHelpers::Address(wasmContextGPR, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
-        else {
-            jit.loadWasmContext(baseMemory);
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfMemory()), baseMemory);
-        }
-
-        if (mode != MemoryMode::Signaling) {
-            const auto& sizeRegs = pinnedRegs.sizeRegisters;
-            ASSERT(sizeRegs.size() >= 1);
-            ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
-            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfSize()), sizeRegs[0].sizeRegister);
-            for (unsigned i = 1; i < sizeRegs.size(); ++i)
-                jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
-        }
-
-        jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyMemory::offsetOfMemory()), baseMemory);
-    }
-
-    CCallHelpers::Call call = jit.threadSafePatchableNearCall();
-    unsigned functionIndexSpace = functionIndex + info.importFunctionCount();
-    ASSERT(functionIndexSpace < info.functionIndexSpaceSize());
-    jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndexSpace] (LinkBuffer& linkBuffer) {
-        unlinkedWasmToWasmCalls->append({ linkBuffer.locationOfNearCall(call), functionIndexSpace });
-    });
-
-
-    for (const RegisterAtOffset& regAtOffset : registersToSpill) {
-        GPRReg reg = regAtOffset.reg().gpr();
-        ASSERT(reg != GPRInfo::returnValueGPR);
-        ptrdiff_t offset = regAtOffset.offset();
-        jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, offset), reg);
-    }
-
-    switch (signature.returnType()) {
-    case Wasm::F32:
-        jit.moveFloatTo32(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR);
-        break;
-    case Wasm::F64:
-        jit.moveDoubleTo64(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR);
-        break;
-    default:
-        break;
-    }
-
-    jit.emitFunctionEpilogue();
-    jit.ret();
-
-    return result;
-}
-
 auto B3IRGenerator::origin() -> Origin
 {
     OpcodeOrigin origin(m_parser->currentOpcode(), m_parser->currentOpcodeStartingOffset());
@@ -1534,7 +1354,7 @@
     return bitwise_cast<Origin>(origin);
 }
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, TierUpCount* tierUp)
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext& compilationContext, const uint8_t* functionStart, size_t functionLength, const Signature& signature, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, CompilationMode compilationMode, uint32_t functionIndex, TierUpCount* tierUp, ThrowWasmException throwWasmException)
 {
     auto result = std::make_unique<InternalFunction>();
 
@@ -1558,11 +1378,11 @@
         ? Options::webAssemblyBBQOptimizationLevel()
         : Options::webAssemblyOMGOptimizationLevel());
 
-    B3IRGenerator context(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, compilationMode, functionIndex, tierUp);
-    FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, info);
+    B3IRGenerator irGenerator(info, procedure, result.get(), unlinkedWasmToWasmCalls, mode, compilationMode, functionIndex, tierUp, throwWasmException);
+    FunctionParser<B3IRGenerator> parser(irGenerator, functionStart, functionLength, signature, info);
     WASM_FAIL_IF_HELPER_FAILS(parser.parse());
 
-    context.insertConstants();
+    irGenerator.insertConstants();
 
     procedure.resetReachability();
     if (!ASSERT_DISABLED)
diff --git a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
index e2c6adb..69be448 100644
--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.h
@@ -31,6 +31,7 @@
 #include "B3Compilation.h"
 #include "B3OpaqueByproducts.h"
 #include "CCallHelpers.h"
+#include "WasmEmbedder.h"
 #include "WasmMemory.h"
 #include "WasmModuleInformation.h"
 #include "WasmTierUpCount.h"
@@ -54,9 +55,7 @@
     std::unique_ptr<B3::OpaqueByproducts> wasmEntrypointByproducts;
 };
 
-Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const uint8_t*, size_t, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, TierUpCount* = nullptr);
-
-std::unique_ptr<InternalFunction> createJSToWasmWrapper(CompilationContext&, const Signature&, Vector<UnlinkedWasmToWasmCall>*, const ModuleInformation&, MemoryMode, uint32_t functionIndex);
+Expected<std::unique_ptr<InternalFunction>, String> parseAndCompile(CompilationContext&, const uint8_t*, size_t, const Signature&, Vector<UnlinkedWasmToWasmCall>&, const ModuleInformation&, MemoryMode, CompilationMode, uint32_t functionIndex, TierUpCount* = nullptr, ThrowWasmException = nullptr);
 
 } } // namespace JSC::Wasm
 
diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
index 22edd16..d0eafa1 100644
--- a/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.cpp
@@ -29,8 +29,6 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3Compilation.h"
-#include "JSCInlines.h"
-#include "JSGlobalObject.h"
 #include "WasmB3IRGenerator.h"
 #include "WasmBinding.h"
 #include "WasmCallee.h"
@@ -53,21 +51,21 @@
 static const bool verbose = false;
 }
 
-BBQPlan::BBQPlan(VM* vm, Ref<ModuleInformation> info, AsyncWork work, CompletionTask&& task)
-    : Base(vm, WTFMove(info), WTFMove(task))
+BBQPlan::BBQPlan(Context* context, Ref<ModuleInformation> info, AsyncWork work, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+    : Base(context, WTFMove(info), WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException)
     , m_state(State::Validated)
     , m_asyncWork(work)
 {
 }
 
-BBQPlan::BBQPlan(VM* vm, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task)
-    : BBQPlan(vm, adoptRef(*new ModuleInformation(WTFMove(source))), work, WTFMove(task))
+BBQPlan::BBQPlan(Context* context, Vector<uint8_t>&& source, AsyncWork work, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+    : BBQPlan(context, adoptRef(*new ModuleInformation(WTFMove(source))), work, WTFMove(task), WTFMove(createEmbedderWrapper), throwWasmException)
 {
     m_state = State::Initial;
 }
 
-BBQPlan::BBQPlan(VM* vm, const uint8_t* source, size_t sourceLength, AsyncWork work, CompletionTask&& task)
-    : Base(vm, source, sourceLength, WTFMove(task))
+BBQPlan::BBQPlan(Context* context, const uint8_t* source, size_t sourceLength, AsyncWork work, CompletionTask&& task)
+    : Base(context, source, sourceLength, WTFMove(task))
     , m_state(State::Initial)
     , m_asyncWork(work)
 {
@@ -269,7 +267,7 @@
 
         m_unlinkedWasmToWasmCalls[functionIndex] = Vector<UnlinkedWasmToWasmCall>();
         TierUpCount* tierUp = Options::useBBQTierUpChecks() ? &m_tierUpCounts[functionIndex] : nullptr;
-        auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp);
+        auto parseAndCompileResult = parseAndCompile(m_compilationContexts[functionIndex], functionStart, functionLength, signature, m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, CompilationMode::BBQMode, functionIndex, tierUp, m_throwWasmException);
 
         if (UNLIKELY(!parseAndCompileResult)) {
             auto locker = holdLock(m_lock);
@@ -285,7 +283,7 @@
 
         if (m_exportedFunctionIndices.contains(functionIndex)) {
             auto locker = holdLock(m_lock);
-            auto result = m_jsToWasmInternalFunctions.add(functionIndex, createJSToWasmWrapper(m_compilationContexts[functionIndex], signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
+            auto result = m_embedderToWasmInternalFunctions.add(functionIndex, m_createEmbedderWrapper(m_compilationContexts[functionIndex], signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
             ASSERT_UNUSED(result, result.isNewEntry);
         }
 
@@ -314,14 +312,14 @@
                     WTFMove(context.wasmEntrypointByproducts));
             }
 
-            if (auto jsToWasmInternalFunction = m_jsToWasmInternalFunctions.get(functionIndex)) {
+            if (auto embedderToWasmInternalFunction = m_embedderToWasmInternalFunctions.get(functionIndex)) {
                 LinkBuffer linkBuffer(*context.jsEntrypointJIT, nullptr, JITCompilationCanFail);
                 if (UNLIKELY(linkBuffer.didFailToAllocate())) {
                     Base::fail(locker, makeString("Out of executable memory in function entrypoint at index ", String::number(functionIndex)));
                     return;
                 }
 
-                jsToWasmInternalFunction->entrypoint.compilation = std::make_unique<B3::Compilation>(
+                embedderToWasmInternalFunction->entrypoint.compilation = std::make_unique<B3::Compilation>(
                     FINALIZE_CODE(linkBuffer, ("JavaScript->WebAssembly entrypoint[%i] %s", functionIndex, SignatureInformation::get(signatureIndex).toString().ascii().data())),
                     WTFMove(context.jsEntrypointByproducts));
             }
diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlan.h b/Source/JavaScriptCore/wasm/WasmBBQPlan.h
index 359f13b..c6ea497 100644
--- a/Source/JavaScriptCore/wasm/WasmBBQPlan.h
+++ b/Source/JavaScriptCore/wasm/WasmBBQPlan.h
@@ -28,12 +28,12 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "CompilationResult.h"
-#include "VM.h"
 #include "WasmB3IRGenerator.h"
 #include "WasmModuleInformation.h"
 #include "WasmPlan.h"
 #include "WasmTierUpCount.h"
 #include <wtf/Bag.h>
+#include <wtf/Function.h>
 #include <wtf/SharedTask.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/Vector.h>
@@ -41,8 +41,6 @@
 namespace JSC {
 
 class CallLinkInfo;
-class JSGlobalObject;
-class JSPromiseDeferred;
 
 namespace Wasm {
 
@@ -50,12 +48,13 @@
 public:
     using Base = Plan;
     enum AsyncWork : uint8_t { FullCompile, Validation };
+
     // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
-    BBQPlan(VM*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&);
-    JS_EXPORT_PRIVATE BBQPlan(VM*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&);
+    BBQPlan(Context*, Ref<ModuleInformation>, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
+    JS_EXPORT_PRIVATE BBQPlan(Context*, Vector<uint8_t>&&, AsyncWork, CompletionTask&&, CreateEmbedderWrapper&&, ThrowWasmException);
     // Note: This constructor should only be used if you are not actually building a module e.g. validation/function tests
     // FIXME: When we get rid of function tests we should remove AsyncWork from this constructor.
-    JS_EXPORT_PRIVATE BBQPlan(VM*, const uint8_t*, size_t, AsyncWork, CompletionTask&&);
+    JS_EXPORT_PRIVATE BBQPlan(Context*, const uint8_t*, size_t, AsyncWork, CompletionTask&&);
 
     bool parseAndValidateModule();
 
@@ -141,7 +140,7 @@
     Vector<MacroAssemblerCodeRef> m_wasmToWasmExitStubs;
     Vector<std::unique_ptr<InternalFunction>> m_wasmInternalFunctions;
     HashSet<uint32_t, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_exportedFunctionIndices;
-    HashMap<uint32_t, std::unique_ptr<InternalFunction>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_jsToWasmInternalFunctions;
+    HashMap<uint32_t, std::unique_ptr<InternalFunction>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderToWasmInternalFunctions;
     Vector<CompilationContext> m_compilationContexts;
     Vector<TierUpCount> m_tierUpCounts;
 
diff --git a/Source/JavaScriptCore/wasm/WasmBBQPlanInlines.h b/Source/JavaScriptCore/wasm/WasmBBQPlanInlines.h
index 1b8b56f..444790b 100644
--- a/Source/JavaScriptCore/wasm/WasmBBQPlanInlines.h
+++ b/Source/JavaScriptCore/wasm/WasmBBQPlanInlines.h
@@ -39,10 +39,10 @@
     ASSERT(!failed());
     for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
 
-        RefPtr<Wasm::Callee> jsEntrypointCallee;
-        if (auto jsToWasmFunction = m_jsToWasmInternalFunctions.get(internalFunctionIndex)) {
-            jsEntrypointCallee = Wasm::Callee::create(WTFMove(jsToWasmFunction->entrypoint));
-            MacroAssembler::repatchPointer(jsToWasmFunction->calleeMoveLocation, CalleeBits::boxWasm(jsEntrypointCallee.get()));
+        RefPtr<Wasm::Callee> embedderEntrypointCallee;
+        if (auto embedderToWasmFunction = m_embedderToWasmInternalFunctions.get(internalFunctionIndex)) {
+            embedderEntrypointCallee = Wasm::Callee::create(WTFMove(embedderToWasmFunction->entrypoint));
+            MacroAssembler::repatchPointer(embedderToWasmFunction->calleeMoveLocation, CalleeBits::boxWasm(embedderEntrypointCallee.get()));
         }
 
         InternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
@@ -50,7 +50,7 @@
         Ref<Wasm::Callee> wasmEntrypointCallee = Wasm::Callee::create(WTFMove(function->entrypoint), functionIndexSpace, m_moduleInformation->nameSection.get(functionIndexSpace));
         MacroAssembler::repatchPointer(function->calleeMoveLocation, CalleeBits::boxWasm(wasmEntrypointCallee.ptr()));
 
-        callback(internalFunctionIndex, WTFMove(jsEntrypointCallee), WTFMove(wasmEntrypointCallee));
+        callback(internalFunctionIndex, WTFMove(embedderEntrypointCallee), WTFMove(wasmEntrypointCallee));
     }
 }
 
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);
 
diff --git a/Source/JavaScriptCore/wasm/WasmBinding.h b/Source/JavaScriptCore/wasm/WasmBinding.h
index 4e262ba..fec6bd7 100644
--- a/Source/JavaScriptCore/wasm/WasmBinding.h
+++ b/Source/JavaScriptCore/wasm/WasmBinding.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -28,9 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3Compilation.h"
-#include "VM.h"
 #include "WasmFormat.h"
-#include <wtf/Bag.h>
 #include <wtf/Expected.h>
 
 namespace JSC {
@@ -44,7 +42,6 @@
 };
 
 Expected<MacroAssemblerCodeRef, BindingFailure> wasmToWasm(unsigned importIndex);
-Expected<MacroAssemblerCodeRef, BindingFailure> wasmToJs(VM*, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex, unsigned importIndex);
 
 } } // namespace JSC::Wasm
 
diff --git a/Source/JavaScriptCore/wasm/WasmCodeBlock.cpp b/Source/JavaScriptCore/wasm/WasmCodeBlock.cpp
index 70fefb0..dd27e43 100644
--- a/Source/JavaScriptCore/wasm/WasmCodeBlock.cpp
+++ b/Source/JavaScriptCore/wasm/WasmCodeBlock.cpp
@@ -31,20 +31,28 @@
 
 #include "WasmBBQPlanInlines.h"
 #include "WasmCallee.h"
+#include "WasmFormat.h"
 #include "WasmWorklist.h"
 
 namespace JSC { namespace Wasm {
 
-CodeBlock::CodeBlock(MemoryMode mode, ModuleInformation& moduleInformation)
+Ref<CodeBlock> CodeBlock::create(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
+{
+    auto* result = new (NotNull, fastMalloc(sizeof(CodeBlock))) CodeBlock(context, mode, moduleInformation, WTFMove(createEmbedderWrapper), throwWasmException);
+    return adoptRef(*result);
+}
+
+CodeBlock::CodeBlock(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
     : m_calleeCount(moduleInformation.internalFunctionCount())
     , m_mode(mode)
 {
     RefPtr<CodeBlock> protectedThis = this;
-    m_plan = adoptRef(*new BBQPlan(nullptr, makeRef(moduleInformation), BBQPlan::FullCompile, createSharedTask<Plan::CallbackType>([this, protectedThis = WTFMove(protectedThis)] (VM*, Plan&) {
+
+    m_plan = adoptRef(*new BBQPlan(context, makeRef(moduleInformation), BBQPlan::FullCompile, createSharedTask<Plan::CallbackType>([this, protectedThis = WTFMove(protectedThis)] (Plan&) {
         auto locker = holdLock(m_lock);
         if (m_plan->failed()) {
             m_errorMessage = m_plan->errorMessage();
-            m_plan = nullptr;
+            setCompilationFinished();
             return;
         }
 
@@ -66,10 +74,10 @@
         m_wasmToWasmCallsites = m_plan->takeWasmToWasmCallsites();
         m_tierUpCounts = m_plan->takeTierUpCounts();
 
-        m_plan = nullptr;
-    })));
-
+        setCompilationFinished();
+    }), WTFMove(createEmbedderWrapper), throwWasmException));
     m_plan->setMode(mode);
+
     auto& worklist = Wasm::ensureWorklist();
     // Note, immediately after we enqueue the plan, there is a chance the above callback will be called.
     worklist.enqueue(makeRef(*m_plan.get()));
@@ -92,7 +100,7 @@
     // else, if we don't have a plan, we're already compiled.
 }
 
-void CodeBlock::compileAsync(VM& vm, AsyncCompilationCallback&& task)
+void CodeBlock::compileAsync(Context* context, AsyncCompilationCallback&& task)
 {
     RefPtr<Plan> plan;
     {
@@ -104,12 +112,11 @@
         // We don't need to keep a RefPtr on the Plan because the worklist will keep
         // a RefPtr on the Plan until the plan finishes notifying all of its callbacks.
         RefPtr<CodeBlock> protectedThis = this;
-        plan->addCompletionTask(vm, createSharedTask<Plan::CallbackType>([this, task = WTFMove(task), protectedThis = WTFMove(protectedThis)] (VM* vm, Plan&) {
-            ASSERT(vm);
-            task->run(*vm, makeRef(*this));
+        plan->addCompletionTask(context, createSharedTask<Plan::CallbackType>([this, task = WTFMove(task), protectedThis = WTFMove(protectedThis)] (Plan&) {
+            task->run(makeRef(*this));
         }));
     } else
-        task->run(vm, makeRef(*this));
+        task->run(makeRef(*this));
 }
 
 bool CodeBlock::isSafeToRun(MemoryMode memoryMode)
@@ -130,6 +137,13 @@
     return false;
 }
 
+
+void CodeBlock::setCompilationFinished()
+{
+    m_plan = nullptr;
+    m_compilationFinished.store(true);
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmCodeBlock.h b/Source/JavaScriptCore/wasm/WasmCodeBlock.h
index 2dbf7e4..9fc1945 100644
--- a/Source/JavaScriptCore/wasm/WasmCodeBlock.h
+++ b/Source/JavaScriptCore/wasm/WasmCodeBlock.h
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "MacroAssemblerCodeRef.h"
+#include "WasmEmbedder.h"
 #include "WasmTierUpCount.h"
 #include <wtf/Lock.h>
 #include <wtf/RefPtr.h>
@@ -37,11 +38,10 @@
 
 namespace JSC {
 
-class VM;
-
 namespace Wasm {
 
 class Callee;
+struct Context;
 class BBQPlan;
 class OMGPlan;
 struct ModuleInformation;
@@ -51,20 +51,16 @@
     
 class CodeBlock : public ThreadSafeRefCounted<CodeBlock> {
 public:
-    typedef void CallbackType(VM&, Ref<CodeBlock>&&);
+    typedef void CallbackType(Ref<CodeBlock>&&);
     using AsyncCompilationCallback = RefPtr<WTF::SharedTask<CallbackType>>;
-    static Ref<CodeBlock> create(MemoryMode mode, ModuleInformation& moduleInformation)
-    {
-        return adoptRef(*new CodeBlock(mode, moduleInformation));
-    }
+    static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
 
     void waitUntilFinished();
-    void compileAsync(VM&, AsyncCompilationCallback&&);
+    void compileAsync(Context*, AsyncCompilationCallback&&);
 
     bool compilationFinished()
     {
-        auto locker = holdLock(m_lock);
-        return !m_plan;
+        return m_compilationFinished.load();
     }
     bool runnable() { return compilationFinished() && !m_errorMessage; }
 
@@ -79,8 +75,11 @@
 
     unsigned functionImportCount() const { return m_wasmToWasmExitStubs.size(); }
 
+    // These two callee getters are only valid once the callees have been populated.
+
     Callee& jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     {
+        ASSERT(runnable());
         RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
         unsigned calleeIndex = functionIndexSpace - functionImportCount();
 
@@ -90,6 +89,7 @@
     }
     Callee& wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     {
+        ASSERT(runnable());
         RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
         unsigned calleeIndex = functionIndexSpace - functionImportCount();
         if (m_optimizedCallees[calleeIndex])
@@ -117,7 +117,8 @@
 private:
     friend class OMGPlan;
 
-    CodeBlock(MemoryMode, ModuleInformation&);
+    CodeBlock(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
+    void setCompilationFinished();
     unsigned m_calleeCount;
     MemoryMode m_mode;
     Vector<RefPtr<Callee>> m_callees;
@@ -128,6 +129,7 @@
     Vector<Vector<UnlinkedWasmToWasmCall>> m_wasmToWasmCallsites;
     Vector<MacroAssemblerCodeRef> m_wasmToWasmExitStubs;
     RefPtr<BBQPlan> m_plan;
+    std::atomic<bool> m_compilationFinished { false };
     String m_errorMessage;
     Lock m_lock;
 };
diff --git a/Source/JavaScriptCore/wasm/WasmContext.cpp b/Source/JavaScriptCore/wasm/WasmContext.cpp
index fea16de..cf34851 100644
--- a/Source/JavaScriptCore/wasm/WasmContext.cpp
+++ b/Source/JavaScriptCore/wasm/WasmContext.cpp
@@ -28,30 +28,41 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "VM.h"
+#include "JSWebAssemblyInstance.h"
+#include "Options.h"
+
 #include <mutex>
 #include <wtf/FastTLS.h>
 
 namespace JSC { namespace Wasm {
 
-Context* loadContext(VM& vm)
+bool Context::useFastTLS()
 {
 #if ENABLE(FAST_TLS_JIT)
-    if (useFastTLSForContext())
-        return bitwise_cast<Context*>(_pthread_getspecific_direct(WTF_WASM_CONTEXT_KEY));
+    return Options::useFastTLSForWasmContext();
+#else
+    return false;
 #endif
-    return vm.wasmContext;
 }
 
-void storeContext(VM& vm, Context* context)
+JSWebAssemblyInstance* Context::load() const
 {
 #if ENABLE(FAST_TLS_JIT)
-    if (useFastTLSForContext())
-        _pthread_setspecific_direct(WTF_WASM_CONTEXT_KEY, bitwise_cast<void*>(context));
+    if (useFastTLS())
+        return bitwise_cast<JSWebAssemblyInstance*>(_pthread_getspecific_direct(WTF_WASM_CONTEXT_KEY));
 #endif
-    vm.wasmContext = context;
-    if (context)
-        context->setCachedStackLimit(vm.softStackLimit());
+    return instance;
+}
+
+void Context::store(JSWebAssemblyInstance* inst, void* softStackLimit)
+{
+#if ENABLE(FAST_TLS_JIT)
+    if (useFastTLS())
+        _pthread_setspecific_direct(WTF_WASM_CONTEXT_KEY, bitwise_cast<void*>(inst));
+#endif
+    instance = inst;
+    if (instance)
+        instance->setCachedStackLimit(softStackLimit);
 }
 
 } } // namespace JSC::Wasm
diff --git a/Source/JavaScriptCore/wasm/WasmContext.h b/Source/JavaScriptCore/wasm/WasmContext.h
index 3cf65fb..c2b51df 100644
--- a/Source/JavaScriptCore/wasm/WasmContext.h
+++ b/Source/JavaScriptCore/wasm/WasmContext.h
@@ -27,37 +27,20 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "JSWebAssemblyInstance.h"
-#include "Options.h"
-
 namespace JSC {
 
-class VM;
+class JSWebAssemblyInstance;
 
 namespace Wasm {
 
-// FIXME: We might want this to be something else at some point:
-// https://bugs.webkit.org/show_bug.cgi?id=170260
-using Context = JSWebAssemblyInstance;
+struct Context {
+    JSWebAssemblyInstance* instance { nullptr };
 
-inline bool useFastTLS()
-{
-#if ENABLE(FAST_TLS_JIT)
-    return Options::useWebAssemblyFastTLS();
-#else
-    return false;
-#endif
-}
+    JSWebAssemblyInstance* load() const;
+    void store(JSWebAssemblyInstance*, void* softStackLimit);
 
-inline bool useFastTLSForContext()
-{
-    if (useFastTLS())
-        return Options::useFastTLSForWasmContext();
-    return false;
-}
-
-Context* loadContext(VM&);
-void storeContext(VM&, Context*);
+    static bool useFastTLS();
+};
 
 } } // namespace JSC::Wasm
 
diff --git a/Source/JavaScriptCore/wasm/WasmEmbedder.h b/Source/JavaScriptCore/wasm/WasmEmbedder.h
new file mode 100644
index 0000000..228794f
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmEmbedder.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "WasmExceptionType.h"
+#include "WasmMemory.h"
+#include <wtf/Forward.h>
+#include <wtf/Function.h>
+
+#include <memory>
+
+namespace JSC {
+
+class ExecState;
+class JSWebAssemblyInstance; // FIXME this should be Wasm::Instance, so should use below. https://webkit.org/b/177472
+
+namespace Wasm {
+
+struct CompilationContext;
+struct InternalFunction;
+struct ModuleInformation;
+class Signature;
+struct UnlinkedWasmToWasmCall;
+
+// Create wrapper code to call from embedder -> WebAssembly.
+using CreateEmbedderWrapper = WTF::Function<std::unique_ptr<InternalFunction>(CompilationContext&, const Signature&, Vector<UnlinkedWasmToWasmCall>*, const ModuleInformation&, MemoryMode, uint32_t)>;
+
+// Called as soon as an exception is detected. The return value is the PC to continue at.
+using ThrowWasmException = void* (*)(ExecState*, Wasm::ExceptionType, JSWebAssemblyInstance*);
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
index 2b1d828..cc1e7d1 100644
--- a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
+++ b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp
@@ -30,11 +30,11 @@
 
 #include "ExecutableAllocator.h"
 #include "MachineContext.h"
-#include "VM.h"
 #include "WasmExceptionType.h"
 #include "WasmMemory.h"
 #include "WasmThunks.h"
 
+#include <wtf/HashSet.h>
 #include <wtf/Lock.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/threads/Signals.h>
diff --git a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h
index 3812836..e5e07a9 100644
--- a/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h
+++ b/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h
@@ -27,8 +27,6 @@
 
 namespace JSC {
 
-class VM;
-
 namespace Wasm {
 
 void registerCode(void* start, void* end);
diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h
index b222217..e7b3df5 100644
--- a/Source/JavaScriptCore/wasm/WasmFormat.h
+++ b/Source/JavaScriptCore/wasm/WasmFormat.h
@@ -44,14 +44,15 @@
 
 namespace JSC {
 
-class JSFunction;
-
 namespace B3 {
 class Compilation;
 }
 
 namespace Wasm {
 
+struct CompilationContext;
+struct ModuleInformation;
+
 inline bool isValueType(Type type)
 {
     switch (type) {
diff --git a/Source/JavaScriptCore/wasm/WasmInstance.cpp b/Source/JavaScriptCore/wasm/WasmInstance.cpp
new file mode 100644
index 0000000..34be0e7
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmInstance.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmInstance.h"
+
+#include "Register.h"
+#include "WasmModuleInformation.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+namespace JSC { namespace Wasm {
+
+namespace {
+size_t globalMemoryByteSize(Module& module)
+{
+    return module.moduleInformation().globals.size() * sizeof(Register);
+}
+}
+
+Instance::Instance(Ref<Module>&& module)
+    : m_module(WTFMove(module))
+    , m_globals(MallocPtr<uint64_t>::malloc(globalMemoryByteSize(m_module.get())))
+{
+}
+
+Instance::~Instance() { }
+
+size_t Instance::extraMemoryAllocated() const
+{
+    return globalMemoryByteSize(m_module.get());
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmInstance.h b/Source/JavaScriptCore/wasm/WasmInstance.h
new file mode 100644
index 0000000..06fb891
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmInstance.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "WasmFormat.h"
+#include "WasmMemory.h"
+#include "WasmModule.h"
+#include "WasmTable.h"
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace JSC { namespace Wasm {
+
+class Instance : public ThreadSafeRefCounted<Instance> {
+public:
+    static Ref<Instance> create(Ref<Module>&& module)
+    {
+        return adoptRef(*new Instance(WTFMove(module)));
+    }
+
+    void finalizeCreation(Ref<CodeBlock>&& codeBlock)
+    {
+        m_codeBlock = WTFMove(codeBlock);
+    }
+
+    JS_EXPORT_PRIVATE ~Instance();
+
+    size_t extraMemoryAllocated() const;
+
+    Module& module() { return m_module.get(); }
+    CodeBlock* codeBlock() { return m_codeBlock.get(); }
+    Memory* memory() { return m_memory.get(); }
+    Table* table() { return m_table.get(); }
+
+    int32_t loadI32Global(unsigned i) const { return m_globals.get()[i]; }
+    int64_t loadI64Global(unsigned i) const { return m_globals.get()[i]; }
+    float loadF32Global(unsigned i) const { return bitwise_cast<float>(loadI32Global(i)); }
+    double loadF64Global(unsigned i) const { return bitwise_cast<double>(loadI64Global(i)); }
+    void setGlobal(unsigned i, int64_t bits) { m_globals.get()[i] = bits; }
+
+    static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(Instance, m_cachedStackLimit); }
+    void* cachedStackLimit() const { return m_cachedStackLimit; }
+    void setCachedStackLimit(void* limit) { m_cachedStackLimit = limit; }
+
+    friend class JSC::JSWebAssemblyInstance; // FIXME remove this once refactored https://webkit.org/b/177472.
+
+private:
+    Instance(Ref<Module>&&);
+
+    Ref<Module> m_module;
+    RefPtr<CodeBlock> m_codeBlock;
+    RefPtr<Memory> m_memory;
+    RefPtr<Table> m_table;
+    MallocPtr<uint64_t> m_globals;
+    void* m_cachedStackLimit { bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) };
+};
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmMemory.cpp b/Source/JavaScriptCore/wasm/WasmMemory.cpp
index c5f48e9..1c1cf59 100644
--- a/Source/JavaScriptCore/wasm/WasmMemory.cpp
+++ b/Source/JavaScriptCore/wasm/WasmMemory.cpp
@@ -28,13 +28,19 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "VM.h"
-#include "WasmThunks.h"
+#include "Options.h"
+#include <wtf/DataLog.h>
 #include <wtf/Gigacage.h>
 #include <wtf/Lock.h>
+#include <wtf/OSAllocator.h>
+#include <wtf/PageBlock.h>
 #include <wtf/Platform.h>
 #include <wtf/PrintStream.h>
 #include <wtf/RAMSize.h>
+#include <wtf/Vector.h>
+
+#include <cstring>
+#include <mutex>
 
 namespace JSC { namespace Wasm {
 
@@ -51,19 +57,19 @@
 struct MemoryResult {
     enum Kind {
         Success,
-        SuccessAndAsyncGC,
-        SyncGCAndRetry
+        SuccessAndNotifyMemoryPressure,
+        SyncTryToReclaimMemory
     };
-    
+
     static const char* toString(Kind kind)
     {
         switch (kind) {
         case Success:
             return "Success";
-        case SuccessAndAsyncGC:
-            return "SuccessAndAsyncGC";
-        case SyncGCAndRetry:
-            return "SyncGCAndRetry";
+        case SuccessAndNotifyMemoryPressure:
+            return "SuccessAndNotifyMemoryPressure";
+        case SyncTryToReclaimMemory:
+            return "SyncTryToReclaimMemory";
         }
         RELEASE_ASSERT_NOT_REACHED();
         return nullptr;
@@ -98,17 +104,17 @@
         MemoryResult result = [&] {
             auto holder = holdLock(m_lock);
             if (m_memories.size() >= m_maxCount)
-                return MemoryResult(nullptr, MemoryResult::SyncGCAndRetry);
+                return MemoryResult(nullptr, MemoryResult::SyncTryToReclaimMemory);
             
             void* result = Gigacage::tryAllocateVirtualPages(Gigacage::Primitive, Memory::fastMappedBytes());
             if (!result)
-                return MemoryResult(nullptr, MemoryResult::SyncGCAndRetry);
+                return MemoryResult(nullptr, MemoryResult::SyncTryToReclaimMemory);
             
             m_memories.append(result);
             
             return MemoryResult(
                 result,
-                m_memories.size() >= m_maxCount / 2 ? MemoryResult::SuccessAndAsyncGC : MemoryResult::Success);
+                m_memories.size() >= m_maxCount / 2 ? MemoryResult::SuccessAndNotifyMemoryPressure : MemoryResult::Success);
         }();
         
         if (Options::logWebAssemblyMemory())
@@ -153,12 +159,12 @@
         MemoryResult::Kind result = [&] {
             auto holder = holdLock(m_lock);
             if (m_physicalBytes + bytes > memoryLimit())
-                return MemoryResult::SyncGCAndRetry;
+                return MemoryResult::SyncTryToReclaimMemory;
             
             m_physicalBytes += bytes;
             
             if (m_physicalBytes >= memoryLimit() / 2)
-                return MemoryResult::SuccessAndAsyncGC;
+                return MemoryResult::SuccessAndNotifyMemoryPressure;
             
             return MemoryResult::Success;
         }();
@@ -205,7 +211,7 @@
 }
 
 template<typename Func>
-bool tryAndGC(VM& vm, const Func& allocate)
+bool tryAllocate(const Func& allocate, const WTF::Function<void(Memory::NotifyPressure)>& notifyMemoryPressure, const WTF::Function<void(Memory::SyncTryToReclaim)>& syncTryToReclaimMemory)
 {
     unsigned numTries = 2;
     bool done = false;
@@ -214,14 +220,16 @@
         case MemoryResult::Success:
             done = true;
             break;
-        case MemoryResult::SuccessAndAsyncGC:
-            vm.heap.collectAsync(CollectionScope::Full);
+        case MemoryResult::SuccessAndNotifyMemoryPressure:
+            if (notifyMemoryPressure)
+                notifyMemoryPressure(Memory::NotifyPressureTag);
             done = true;
             break;
-        case MemoryResult::SyncGCAndRetry:
+        case MemoryResult::SyncTryToReclaimMemory:
             if (i + 1 == numTries)
                 break;
-            vm.heap.collectSync(CollectionScope::Full);
+            if (syncTryToReclaimMemory)
+                syncTryToReclaimMemory(Memory::SyncTryToReclaimTag);
             break;
         }
     }
@@ -230,32 +238,32 @@
 
 } // anonymous namespace
 
-const char* makeString(MemoryMode mode)
+Memory::Memory()
 {
-    switch (mode) {
-    case MemoryMode::BoundsChecking: return "BoundsChecking";
-    case MemoryMode::Signaling: return "Signaling";
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return "";
 }
 
-Memory::Memory(PageCount initial, PageCount maximum)
+Memory::Memory(PageCount initial, PageCount maximum, Function<void(NotifyPressure)>&& notifyMemoryPressure, Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback)
     : m_initial(initial)
     , m_maximum(maximum)
+    , m_notifyMemoryPressure(WTFMove(notifyMemoryPressure))
+    , m_syncTryToReclaimMemory(WTFMove(syncTryToReclaimMemory))
+    , m_growSuccessCallback(WTFMove(growSuccessCallback))
 {
     ASSERT(!initial.bytes());
     ASSERT(m_mode == MemoryMode::BoundsChecking);
     dataLogLnIf(verbose, "Memory::Memory allocating ", *this);
 }
 
-Memory::Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode mode)
+Memory::Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode mode, Function<void(NotifyPressure)>&& notifyMemoryPressure, Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback)
     : m_memory(memory)
     , m_size(initial.bytes())
     , m_initial(initial)
     , m_maximum(maximum)
     , m_mappedCapacity(mappedCapacity)
     , m_mode(mode)
+    , m_notifyMemoryPressure(WTFMove(notifyMemoryPressure))
+    , m_syncTryToReclaimMemory(WTFMove(syncTryToReclaimMemory))
+    , m_growSuccessCallback(WTFMove(growSuccessCallback))
 {
     dataLogLnIf(verbose, "Memory::Memory allocating ", *this);
 }
@@ -275,7 +283,12 @@
 #endif
 }
 
-RefPtr<Memory> Memory::create(VM& vm, PageCount initial, PageCount maximum)
+RefPtr<Memory> Memory::create()
+{
+    return adoptRef(new Memory());
+}
+
+RefPtr<Memory> Memory::create(PageCount initial, PageCount maximum, WTF::Function<void(NotifyPressure)>&& notifyMemoryPressure, WTF::Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback)
 {
     ASSERT(initial);
     RELEASE_ASSERT(!maximum || maximum >= initial); // This should be guaranteed by our caller.
@@ -283,33 +296,27 @@
     const size_t initialBytes = initial.bytes();
     const size_t maximumBytes = maximum ? maximum.bytes() : 0;
 
-    // We need to be sure we have a stub prior to running code.
-    if (UNLIKELY(!Thunks::singleton().stub(throwExceptionFromWasmThunkGenerator)))
-        return nullptr;
-
     if (maximum && !maximumBytes) {
         // User specified a zero maximum, initial size must also be zero.
         RELEASE_ASSERT(!initialBytes);
-        return adoptRef(new Memory(initial, maximum));
+        return adoptRef(new Memory(initial, maximum, WTFMove(notifyMemoryPressure), WTFMove(syncTryToReclaimMemory), WTFMove(growSuccessCallback)));
     }
     
-    bool done = tryAndGC(
-        vm,
+    bool done = tryAllocate(
         [&] () -> MemoryResult::Kind {
             return memoryManager().tryAllocatePhysicalBytes(initialBytes);
-        });
+        }, notifyMemoryPressure, syncTryToReclaimMemory);
     if (!done)
         return nullptr;
         
     char* fastMemory = nullptr;
     if (Options::useWebAssemblyFastMemory()) {
-        tryAndGC(
-            vm,
+        tryAllocate(
             [&] () -> MemoryResult::Kind {
                 auto result = memoryManager().tryAllocateVirtualPages();
                 fastMemory = bitwise_cast<char*>(result.basePtr);
                 return result.kind;
-            });
+            }, notifyMemoryPressure, syncTryToReclaimMemory);
     }
     
     if (fastMemory) {
@@ -320,15 +327,15 @@
         }
 
         commitZeroPages(fastMemory, initialBytes);
-        
-        return adoptRef(new Memory(fastMemory, initial, maximum, Memory::fastMappedBytes(), MemoryMode::Signaling));
+
+        return adoptRef(new Memory(fastMemory, initial, maximum, Memory::fastMappedBytes(), MemoryMode::Signaling, WTFMove(notifyMemoryPressure), WTFMove(syncTryToReclaimMemory), WTFMove(growSuccessCallback)));
     }
     
     if (UNLIKELY(Options::crashIfWebAssemblyCantFastMemory()))
         webAssemblyCouldntGetFastMemory();
 
     if (!initialBytes)
-        return adoptRef(new Memory(initial, maximum));
+        return adoptRef(new Memory(initial, maximum, WTFMove(notifyMemoryPressure), WTFMove(syncTryToReclaimMemory), WTFMove(growSuccessCallback)));
     
     void* slowMemory = Gigacage::tryAlignedMalloc(Gigacage::Primitive, WTF::pageSize(), initialBytes);
     if (!slowMemory) {
@@ -336,7 +343,7 @@
         return nullptr;
     }
     memset(slowMemory, 0, initialBytes);
-    return adoptRef(new Memory(slowMemory, initial, maximum, initialBytes, MemoryMode::BoundsChecking));
+    return adoptRef(new Memory(slowMemory, initial, maximum, initialBytes, MemoryMode::BoundsChecking, WTFMove(notifyMemoryPressure), WTFMove(syncTryToReclaimMemory), WTFMove(growSuccessCallback)));
 }
 
 Memory::~Memory()
@@ -345,7 +352,10 @@
         memoryManager().freePhysicalBytes(m_size);
         switch (m_mode) {
         case MemoryMode::Signaling:
-            mprotect(m_memory, Memory::fastMappedBytes(), PROT_READ | PROT_WRITE);
+            if (mprotect(m_memory, Memory::fastMappedBytes(), PROT_READ | PROT_WRITE)) {
+                dataLog("mprotect failed: ", strerror(errno), "\n");
+                RELEASE_ASSERT_NOT_REACHED();
+            }
             memoryManager().freeVirtualPages(m_memory);
             break;
         case MemoryMode::BoundsChecking:
@@ -371,34 +381,50 @@
     return memoryManager().containsAddress(address);
 }
 
-bool Memory::grow(VM& vm, PageCount newSize)
+Expected<PageCount, Memory::GrowFailReason> Memory::grow(PageCount delta)
 {
-    RELEASE_ASSERT(newSize > PageCount::fromBytes(m_size));
+    const Wasm::PageCount oldPageCount = sizeInPages();
 
-    dataLogLnIf(verbose, "Memory::grow to ", newSize, " from ", *this);
+    if (!delta.isValid())
+        return makeUnexpected(GrowFailReason::InvalidDelta);
+    
+    const Wasm::PageCount newPageCount = oldPageCount + delta;
+    if (!newPageCount)
+        return makeUnexpected(GrowFailReason::InvalidGrowSize);
 
-    if (maximum() && newSize > maximum())
-        return false;
+    auto success = [&] () {
+        m_growSuccessCallback(GrowSuccessTag, oldPageCount, newPageCount);
+        return oldPageCount;
+    };
 
-    size_t desiredSize = newSize.bytes();
+    if (delta.pageCount() == 0)
+        return success();
+
+    dataLogLnIf(verbose, "Memory::grow(", delta, ") to ", newPageCount, " from ", *this);
+    RELEASE_ASSERT(newPageCount > PageCount::fromBytes(m_size));
+
+    if (maximum() && newPageCount > maximum())
+        return makeUnexpected(GrowFailReason::WouldExceedMaximum);
+
+    size_t desiredSize = newPageCount.bytes();
     RELEASE_ASSERT(desiredSize > m_size);
     size_t extraBytes = desiredSize - m_size;
     RELEASE_ASSERT(extraBytes);
-    bool success = tryAndGC(
-        vm,
+    bool allocationSuccess = tryAllocate(
         [&] () -> MemoryResult::Kind {
             return memoryManager().tryAllocatePhysicalBytes(extraBytes);
-        });
-    if (!success)
-        return false;
-        
+        }, m_notifyMemoryPressure, m_syncTryToReclaimMemory);
+    if (!allocationSuccess)
+        return makeUnexpected(GrowFailReason::OutOfMemory);
+
     switch (mode()) {
     case MemoryMode::BoundsChecking: {
         RELEASE_ASSERT(maximum().bytes() != 0);
-        
+
         void* newMemory = Gigacage::tryAlignedMalloc(Gigacage::Primitive, WTF::pageSize(), desiredSize);
         if (!newMemory)
-            return false;
+            return makeUnexpected(GrowFailReason::OutOfMemory);
+
         memcpy(newMemory, m_memory, m_size);
         memset(static_cast<char*>(newMemory) + m_size, 0, desiredSize - m_size);
         if (m_memory)
@@ -406,7 +432,7 @@
         m_memory = newMemory;
         m_mappedCapacity = desiredSize;
         m_size = desiredSize;
-        return true;
+        return success();
     }
     case MemoryMode::Signaling: {
         RELEASE_ASSERT(m_memory);
@@ -415,16 +441,17 @@
         
         dataLogLnIf(verbose, "Marking WebAssembly memory's ", RawPointer(m_memory), " as read+write in range [", RawPointer(startAddress), ", ", RawPointer(startAddress + extraBytes), ")");
         if (mprotect(startAddress, extraBytes, PROT_READ | PROT_WRITE)) {
-            dataLogLnIf(verbose, "Memory::grow in-place failed ", *this);
-            return false;
+            dataLog("mprotect failed: ", strerror(errno), "\n");
+            RELEASE_ASSERT_NOT_REACHED();
         }
         commitZeroPages(startAddress, extraBytes);
         m_size = desiredSize;
-        return true;
-    } }
-    
+        return success();
+    }
+    }
+
     RELEASE_ASSERT_NOT_REACHED();
-    return false;
+    return oldPageCount;
 }
 
 void Memory::dump(PrintStream& out) const
diff --git a/Source/JavaScriptCore/wasm/WasmMemory.h b/Source/JavaScriptCore/wasm/WasmMemory.h
index 60a9bb7..cd586a8 100644
--- a/Source/JavaScriptCore/wasm/WasmMemory.h
+++ b/Source/JavaScriptCore/wasm/WasmMemory.h
@@ -27,8 +27,11 @@
 
 #if ENABLE(WEBASSEMBLY)
 
+#include "WasmMemoryMode.h"
 #include "WasmPageCount.h"
 
+#include <wtf/Expected.h>
+#include <wtf/Function.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
@@ -38,18 +41,8 @@
 
 namespace JSC {
 
-class VM;
-
 namespace Wasm {
 
-// FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
-enum class MemoryMode : uint8_t {
-    BoundsChecking,
-    Signaling
-};
-static constexpr size_t NumberOfMemoryModes = 2;
-JS_EXPORT_PRIVATE const char* makeString(MemoryMode);
-
 class Memory : public RefCounted<Memory> {
     WTF_MAKE_NONCOPYABLE(Memory);
     WTF_MAKE_FAST_ALLOCATED;
@@ -58,7 +51,12 @@
 
     explicit operator bool() const { return !!m_memory; }
     
-    static RefPtr<Memory> create(VM&, PageCount initial, PageCount maximum);
+    enum NotifyPressure { NotifyPressureTag };
+    enum SyncTryToReclaim { SyncTryToReclaimTag };
+    enum GrowSuccess { GrowSuccessTag };
+
+    static RefPtr<Memory> create();
+    static RefPtr<Memory> create(PageCount initial, PageCount maximum, WTF::Function<void(NotifyPressure)>&& notifyMemoryPressure, WTF::Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback);
 
     ~Memory();
 
@@ -75,22 +73,34 @@
 
     MemoryMode mode() const { return m_mode; }
 
-    // grow() should only be called from the JSWebAssemblyMemory object since that object needs to update internal
-    // pointers with the current base and size.
-    bool grow(VM&, PageCount);
+    enum class GrowFailReason {
+        InvalidDelta,
+        InvalidGrowSize,
+        WouldExceedMaximum,
+        OutOfMemory,
+    };
+    Expected<PageCount, GrowFailReason> grow(PageCount);
 
     void check() {  ASSERT(!deletionHasBegun()); }
-private:
-    Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode);
-    Memory(PageCount initial, PageCount maximum);
 
-    // FIXME: we should move these to the instance to avoid a load on instance->instance calls.
+    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Memory, m_memory); }
+    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
+
+private:
+    Memory();
+    Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, MemoryMode, WTF::Function<void(NotifyPressure)>&& notifyMemoryPressure, WTF::Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback);
+    Memory(PageCount initial, PageCount maximum, WTF::Function<void(NotifyPressure)>&& notifyMemoryPressure, WTF::Function<void(SyncTryToReclaim)>&& syncTryToReclaimMemory, WTF::Function<void(GrowSuccess, PageCount, PageCount)>&& growSuccessCallback);
+
+    // FIXME: we cache these on the instances to avoid a load on instance->instance calls. This will require updating all the instances when grow is called. https://bugs.webkit.org/show_bug.cgi?id=177305
     void* m_memory { nullptr };
     size_t m_size { 0 };
     PageCount m_initial;
     PageCount m_maximum;
     size_t m_mappedCapacity { 0 };
     MemoryMode m_mode { MemoryMode::BoundsChecking };
+    WTF::Function<void(NotifyPressure)> m_notifyMemoryPressure;
+    WTF::Function<void(SyncTryToReclaim)> m_syncTryToReclaimMemory;
+    WTF::Function<void(GrowSuccess, PageCount, PageCount)> m_growSuccessCallback;
 };
 
 } } // namespace JSC::Wasm
diff --git a/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp b/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp
index bf565f0..b5c34bd 100644
--- a/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp
+++ b/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp
@@ -57,7 +57,7 @@
     std::call_once(staticPinnedRegisterInfoFlag, [] () {
         Vector<PinnedSizeRegisterInfo> sizeRegisters;
         GPRReg baseMemoryPointer = InvalidGPRReg;
-        GPRReg wasmContextPointer = InvalidGPRReg;
+        GPRReg wasmContextInstancePointer = InvalidGPRReg;
 
         // FIXME: We should support more than one memory size register, and we should allow different
         //        WebAssembly.Instance to have different pins. Right now we take a vector with only one entry.
@@ -65,27 +65,27 @@
         //        see: https://bugs.webkit.org/show_bug.cgi?id=162952
         Vector<unsigned> pinnedSizes = { 0 };
         unsigned numberOfPinnedRegisters = pinnedSizes.size() + 1;
-        if (!useFastTLSForContext())
+        if (!Context::useFastTLS())
             ++numberOfPinnedRegisters;
         Vector<GPRReg> pinnedRegs = getPinnedRegisters(numberOfPinnedRegisters);
 
         baseMemoryPointer = pinnedRegs.takeLast();
-        if (!useFastTLSForContext())
-            wasmContextPointer = pinnedRegs.takeLast();
+        if (!Context::useFastTLS())
+            wasmContextInstancePointer = pinnedRegs.takeLast();
 
         ASSERT(pinnedSizes.size() == pinnedRegs.size());
         for (unsigned i = 0; i < pinnedSizes.size(); ++i)
             sizeRegisters.append({ pinnedRegs[i], pinnedSizes[i] });
-        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer, wasmContextPointer);
+        staticPinnedRegisterInfo.construct(WTFMove(sizeRegisters), baseMemoryPointer, wasmContextInstancePointer);
     });
 
     return staticPinnedRegisterInfo.get();
 }
 
-PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer, GPRReg wasmContextPointer)
+PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegisters, GPRReg baseMemoryPointer, GPRReg wasmContextInstancePointer)
     : sizeRegisters(WTFMove(sizeRegisters))
     , baseMemoryPointer(baseMemoryPointer)
-    , wasmContextPointer(wasmContextPointer)
+    , wasmContextInstancePointer(wasmContextInstancePointer)
 {
 }
 
diff --git a/Source/JavaScriptCore/wasm/WasmMemoryInformation.h b/Source/JavaScriptCore/wasm/WasmMemoryInformation.h
index 4237bac..23329eb 100644
--- a/Source/JavaScriptCore/wasm/WasmMemoryInformation.h
+++ b/Source/JavaScriptCore/wasm/WasmMemoryInformation.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -44,7 +44,7 @@
 struct PinnedRegisterInfo {
     Vector<PinnedSizeRegisterInfo> sizeRegisters;
     GPRReg baseMemoryPointer;
-    GPRReg wasmContextPointer;
+    GPRReg wasmContextInstancePointer;
     static const PinnedRegisterInfo& get();
     PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&&, GPRReg, GPRReg);
 
@@ -52,8 +52,8 @@
     {
         RegisterSet result;
         result.set(baseMemoryPointer);
-        if (wasmContextPointer != InvalidGPRReg)
-            result.set(wasmContextPointer);
+        if (wasmContextInstancePointer != InvalidGPRReg)
+            result.set(wasmContextInstancePointer);
         if (mode != MemoryMode::Signaling) {
             for (const auto& info : sizeRegisters)
                 result.set(info.sizeRegister);
diff --git a/Source/JavaScriptCore/wasm/WasmMemoryMode.cpp b/Source/JavaScriptCore/wasm/WasmMemoryMode.cpp
new file mode 100644
index 0000000..b1bc985
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmMemoryMode.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmMemoryMode.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include <wtf/Assertions.h>
+
+namespace JSC { namespace Wasm {
+
+const char* makeString(MemoryMode mode)
+{
+    switch (mode) {
+    case MemoryMode::BoundsChecking: return "BoundsChecking";
+    case MemoryMode::Signaling: return "Signaling";
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return "";
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmMemoryMode.h b/Source/JavaScriptCore/wasm/WasmMemoryMode.h
new file mode 100644
index 0000000..0a2855a
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmMemoryMode.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSExportMacros.h"
+
+namespace JSC { namespace Wasm {
+
+// FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
+enum class MemoryMode : uint8_t {
+    BoundsChecking,
+    Signaling
+};
+
+static constexpr size_t NumberOfMemoryModes = 2;
+JS_EXPORT_PRIVATE const char* makeString(MemoryMode);
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMLY)
diff --git a/Source/JavaScriptCore/wasm/WasmModule.cpp b/Source/JavaScriptCore/wasm/WasmModule.cpp
index d683ae9..0b21ca2 100644
--- a/Source/JavaScriptCore/wasm/WasmModule.cpp
+++ b/Source/JavaScriptCore/wasm/WasmModule.cpp
@@ -56,27 +56,26 @@
 
 static Plan::CompletionTask makeValidationCallback(Module::AsyncValidationCallback&& callback)
 {
-    return createSharedTask<Plan::CallbackType>([callback = WTFMove(callback)] (VM* vm, Plan& plan) {
+    return createSharedTask<Plan::CallbackType>([callback = WTFMove(callback)] (Plan& plan) {
         ASSERT(!plan.hasWork());
-        ASSERT(vm);
-        callback->run(*vm, makeValidationResult(static_cast<BBQPlan&>(plan)));
+        callback->run(makeValidationResult(static_cast<BBQPlan&>(plan)));
     });
 }
 
-Module::ValidationResult Module::validateSync(VM& vm, Vector<uint8_t>&& source)
+Module::ValidationResult Module::validateSync(Context* context, Vector<uint8_t>&& source)
 {
-    Ref<BBQPlan> plan = adoptRef(*new BBQPlan(&vm, WTFMove(source), BBQPlan::Validation, Plan::dontFinalize()));
+    Ref<BBQPlan> plan = adoptRef(*new BBQPlan(context, WTFMove(source), BBQPlan::Validation, Plan::dontFinalize(), nullptr, nullptr));
     plan->parseAndValidateModule();
     return makeValidationResult(plan.get());
 }
 
-void Module::validateAsync(VM& vm, Vector<uint8_t>&& source, Module::AsyncValidationCallback&& callback)
+void Module::validateAsync(Context* context, Vector<uint8_t>&& source, Module::AsyncValidationCallback&& callback)
 {
-    Ref<Plan> plan = adoptRef(*new BBQPlan(&vm, WTFMove(source), BBQPlan::Validation, makeValidationCallback(WTFMove(callback))));
+    Ref<Plan> plan = adoptRef(*new BBQPlan(context, WTFMove(source), BBQPlan::Validation, makeValidationCallback(WTFMove(callback)), nullptr, nullptr));
     Wasm::ensureWorklist().enqueue(WTFMove(plan));
 }
 
-Ref<CodeBlock> Module::getOrCreateCodeBlock(MemoryMode mode)
+Ref<CodeBlock> Module::getOrCreateCodeBlock(Context* context, MemoryMode mode, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
 {
     RefPtr<CodeBlock> codeBlock;
     auto locker = holdLock(m_lock);
@@ -87,23 +86,23 @@
     // 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(mode, const_cast<ModuleInformation&>(moduleInformation()));
+        codeBlock = CodeBlock::create(context, mode, const_cast<ModuleInformation&>(moduleInformation()), WTFMove(createEmbedderWrapper), throwWasmException);
         m_codeBlocks[static_cast<uint8_t>(mode)] = codeBlock;
     }
     return codeBlock.releaseNonNull();
 }
 
-Ref<CodeBlock> Module::compileSync(MemoryMode mode)
+Ref<CodeBlock> Module::compileSync(Context* context, MemoryMode mode, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
 {
-    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(mode);
+    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode, WTFMove(createEmbedderWrapper), throwWasmException);
     codeBlock->waitUntilFinished();
     return codeBlock;
 }
 
-void Module::compileAsync(VM& vm, MemoryMode mode, CodeBlock::AsyncCompilationCallback&& task)
+void Module::compileAsync(Context* context, MemoryMode mode, CodeBlock::AsyncCompilationCallback&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
 {
-    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(mode);
-    codeBlock->compileAsync(vm, WTFMove(task));
+    Ref<CodeBlock> codeBlock = getOrCreateCodeBlock(context, mode, WTFMove(createEmbedderWrapper), throwWasmException);
+    codeBlock->compileAsync(context, WTFMove(task));
 }
 
 } } // namespace JSC::Wasm
diff --git a/Source/JavaScriptCore/wasm/WasmModule.h b/Source/JavaScriptCore/wasm/WasmModule.h
index a1af758..a6ae29f 100644
--- a/Source/JavaScriptCore/wasm/WasmModule.h
+++ b/Source/JavaScriptCore/wasm/WasmModule.h
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "WasmCodeBlock.h"
+#include "WasmEmbedder.h"
 #include "WasmMemory.h"
 #include <wtf/Expected.h>
 #include <wtf/Lock.h>
@@ -36,19 +37,20 @@
 
 namespace JSC { namespace Wasm {
 
+struct Context;
 struct ModuleInformation;
 class Plan;
 
 using SignatureIndex = uint32_t;
-    
+
 class Module : public ThreadSafeRefCounted<Module> {
 public:
     using ValidationResult = WTF::Expected<RefPtr<Module>, String>;
-    typedef void CallbackType(VM&, ValidationResult&&);
+    typedef void CallbackType(ValidationResult&&);
     using AsyncValidationCallback = RefPtr<SharedTask<CallbackType>>;
 
-    static ValidationResult validateSync(VM&, Vector<uint8_t>&& source);
-    static void validateAsync(VM&, Vector<uint8_t>&& source, Module::AsyncValidationCallback&&);
+    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)
     {
@@ -58,14 +60,14 @@
     Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const;
     const Wasm::ModuleInformation& moduleInformation() const { return m_moduleInformation.get(); }
 
-    Ref<CodeBlock> compileSync(MemoryMode);
-    void compileAsync(VM&, MemoryMode, CodeBlock::AsyncCompilationCallback&&);
+    Ref<CodeBlock> compileSync(Context*, MemoryMode, CreateEmbedderWrapper&&, ThrowWasmException);
+    void compileAsync(Context*, MemoryMode, CodeBlock::AsyncCompilationCallback&&, CreateEmbedderWrapper&&, ThrowWasmException);
 
     JS_EXPORT_PRIVATE ~Module();
 
     CodeBlock* codeBlockFor(MemoryMode mode) { return m_codeBlocks[static_cast<uint8_t>(mode)].get(); }
 private:
-    Ref<CodeBlock> getOrCreateCodeBlock(MemoryMode);
+    Ref<CodeBlock> getOrCreateCodeBlock(Context*, MemoryMode, CreateEmbedderWrapper&&, ThrowWasmException);
 
     Module(Ref<ModuleInformation>&&);
     Ref<ModuleInformation> m_moduleInformation;
diff --git a/Source/JavaScriptCore/wasm/WasmModuleParser.cpp b/Source/JavaScriptCore/wasm/WasmModuleParser.cpp
index 6c948b5..6d44ac2 100644
--- a/Source/JavaScriptCore/wasm/WasmModuleParser.cpp
+++ b/Source/JavaScriptCore/wasm/WasmModuleParser.cpp
@@ -29,7 +29,6 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "IdentifierInlines.h"
-#include "JSWebAssemblyTable.h"
 #include "WasmMemoryInformation.h"
 #include "WasmNameSectionParser.h"
 #include "WasmOps.h"
@@ -265,7 +264,7 @@
     PartialResult limits = parseResizableLimits(initial, maximum);
     if (UNLIKELY(!limits))
         return limits.getUnexpected();
-    WASM_PARSER_FAIL_IF(!JSWebAssemblyTable::isValidSize(initial), "Table's initial page count of ", initial, " is invalid");
+    WASM_PARSER_FAIL_IF(initial > maxTableEntries, "Table's initial page count of ", initial, " is too big, maximum ", maxTableEntries);
 
     ASSERT(!maximum || *maximum >= initial);
 
diff --git a/Source/JavaScriptCore/wasm/WasmNameSection.h b/Source/JavaScriptCore/wasm/WasmNameSection.h
new file mode 100644
index 0000000..137f652
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmNameSection.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WasmName.h"
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/Vector.h>
+
+namespace JSC { namespace Wasm {
+
+struct NameSection : ThreadSafeRefCounted<NameSection> {
+    static Ref<NameSection> create()
+    {
+        return adoptRef(*new NameSection());
+    }
+
+    Name moduleName;
+    Vector<Name> functionNames;
+    const Name* get(size_t functionIndexSpace)
+    {
+        return functionIndexSpace < functionNames.size() ? &functionNames[functionIndexSpace] : nullptr;
+    }
+};
+
+} } // namespace JSC::Wasm
diff --git a/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp b/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
index 74cf653..ccdf72d 100644
--- a/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmOMGPlan.cpp
@@ -31,9 +31,10 @@
 #include "B3Compilation.h"
 #include "B3OpaqueByproducts.h"
 #include "JSCInlines.h"
-#include "JSWebAssemblyModule.h"
+#include "JSWebAssemblyInstance.h"
 #include "LinkBuffer.h"
 #include "WasmB3IRGenerator.h"
+#include "WasmCallee.h"
 #include "WasmContext.h"
 #include "WasmMachineThreads.h"
 #include "WasmMemory.h"
@@ -51,10 +52,10 @@
 static const bool verbose = false;
 }
 
-OMGPlan::OMGPlan(Ref<Module> module, uint32_t functionIndex, MemoryMode mode, CompletionTask&& task)
-    : Base(nullptr, makeRef(const_cast<ModuleInformation&>(module->moduleInformation())), WTFMove(task))
-    , m_module(module.copyRef())
-    , m_codeBlock(*module->codeBlockFor(mode))
+OMGPlan::OMGPlan(Context* context, Ref<Module>&& module, uint32_t functionIndex, MemoryMode mode, CompletionTask&& task)
+    : Base(context, makeRef(const_cast<ModuleInformation&>(module->moduleInformation())), WTFMove(task))
+    , m_module(WTFMove(module))
+    , m_codeBlock(*m_module->codeBlockFor(mode))
     , m_functionIndex(functionIndex)
 {
     setMode(mode);
@@ -162,13 +163,13 @@
     complete(holdLock(m_lock));
 }
 
-void runOMGPlanForIndex(Context* context, uint32_t functionIndex)
+void OMGPlan::runForIndex(JSWebAssemblyInstance* instance, uint32_t functionIndex)
 {
-    JSWebAssemblyCodeBlock* codeBlock = context->codeBlock();
-    ASSERT(context->memoryMode() == codeBlock->m_codeBlock->mode());
+    Wasm::CodeBlock& codeBlock = instance->wasmCodeBlock();
+    ASSERT(instance->wasmMemory()->mode() == codeBlock.mode());
 
-    if (codeBlock->m_codeBlock->tierUpCount(functionIndex).shouldStartTierUp()) {
-        Ref<Plan> plan = adoptRef(*new OMGPlan(context->module()->module(), functionIndex, codeBlock->m_codeBlock->mode(), Plan::dontFinalize()));
+    if (codeBlock.tierUpCount(functionIndex).shouldStartTierUp()) {
+        Ref<Plan> plan = adoptRef(*new OMGPlan(instance->context(), Ref<Wasm::Module>(instance->wasmModule()), functionIndex, codeBlock.mode(), Plan::dontFinalize()));
         ensureWorklist().enqueue(plan.copyRef());
         if (UNLIKELY(!Options::useConcurrentJIT()))
             plan->waitForCompletion();
diff --git a/Source/JavaScriptCore/wasm/WasmOMGPlan.h b/Source/JavaScriptCore/wasm/WasmOMGPlan.h
index 7164a9e..b808251 100644
--- a/Source/JavaScriptCore/wasm/WasmOMGPlan.h
+++ b/Source/JavaScriptCore/wasm/WasmOMGPlan.h
@@ -27,7 +27,6 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "VM.h"
 #include "WasmContext.h"
 #include "WasmModule.h"
 #include "WasmPlan.h"
@@ -41,17 +40,20 @@
 class OMGPlan final : public Plan {
 public:
     using Base = Plan;
-    // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
-    OMGPlan(Ref<Module>, uint32_t functionIndex, MemoryMode, CompletionTask&&);
 
     bool hasWork() const override { return !m_completed; }
     void work(CompilationEffort) override;
     bool multiThreaded() const override { return false; }
 
+    static void runForIndex(JSWebAssemblyInstance*, uint32_t functionIndex);
+
 private:
     // For some reason friendship doesn't extend to parent classes...
     using Base::m_lock;
 
+    // Note: CompletionTask should not hold a reference to the Plan otherwise there will be a reference cycle.
+    OMGPlan(Context*, Ref<Module>&&, uint32_t functionIndex, MemoryMode, CompletionTask&&);
+
     bool isComplete() const override { return m_completed; }
     void complete(const AbstractLocker& locker) override
     {
@@ -65,8 +67,6 @@
     uint32_t m_functionIndex;
 };
 
-void runOMGPlanForIndex(Context*, uint32_t functionIndex);
-
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmPageCount.h b/Source/JavaScriptCore/wasm/WasmPageCount.h
index e43847c..ef05f33 100644
--- a/Source/JavaScriptCore/wasm/WasmPageCount.h
+++ b/Source/JavaScriptCore/wasm/WasmPageCount.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -57,6 +57,11 @@
     {
         return pageCount <= maxPageCount;
     }
+    
+    bool isValid() const
+    {
+        return isValid(m_pageCount);
+    }
 
     static PageCount fromBytes(uint64_t bytes)
     {
diff --git a/Source/JavaScriptCore/wasm/WasmPlan.cpp b/Source/JavaScriptCore/wasm/WasmPlan.cpp
index ba27cf9..d063cc1 100644
--- a/Source/JavaScriptCore/wasm/WasmPlan.cpp
+++ b/Source/JavaScriptCore/wasm/WasmPlan.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -29,8 +29,6 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "B3Compilation.h"
-#include "JSCInlines.h"
-#include "JSGlobalObject.h"
 #include "WasmB3IRGenerator.h"
 #include "WasmBinding.h"
 #include "WasmCallee.h"
@@ -51,20 +49,27 @@
 static const bool verbose = false;
 }
 
-Plan::Plan(VM* vm, Ref<ModuleInformation> info, CompletionTask&& task)
+Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task, CreateEmbedderWrapper&& createEmbedderWrapper, ThrowWasmException throwWasmException)
     : m_moduleInformation(WTFMove(info))
+    , m_createEmbedderWrapper(WTFMove(createEmbedderWrapper))
+    , m_throwWasmException(throwWasmException)
     , m_source(m_moduleInformation->source.data())
     , m_sourceLength(m_moduleInformation->source.size())
 {
-    m_completionTasks.append(std::make_pair(vm, WTFMove(task)));
+    m_completionTasks.append(std::make_pair(context, WTFMove(task)));
 }
 
-Plan::Plan(VM* vm, const uint8_t* source, size_t sourceLength, CompletionTask&& task)
+Plan::Plan(Context* context, Ref<ModuleInformation> info, CompletionTask&& task)
+    : Plan(context, WTFMove(info), WTFMove(task), nullptr, nullptr)
+{
+}
+
+Plan::Plan(Context* context, const uint8_t* source, size_t sourceLength, CompletionTask&& task)
     : m_moduleInformation(adoptRef(*new ModuleInformation(Vector<uint8_t>())))
     , m_source(source)
     , m_sourceLength(sourceLength)
 {
-    m_completionTasks.append(std::make_pair(vm, WTFMove(task)));
+    m_completionTasks.append(std::make_pair(context, WTFMove(task)));
 }
 
 void Plan::runCompletionTasks(const AbstractLocker&)
@@ -72,18 +77,18 @@
     ASSERT(isComplete() && !hasWork());
 
     for (auto& task : m_completionTasks)
-        task.second->run(task.first, *this);
+        task.second->run(*this);
     m_completionTasks.clear();
     m_completed.notifyAll();
 }
 
-void Plan::addCompletionTask(VM& vm, CompletionTask&& task)
+void Plan::addCompletionTask(Context* context, CompletionTask&& task)
 {
     LockHolder locker(m_lock);
     if (!isComplete())
-        m_completionTasks.append(std::make_pair(&vm, WTFMove(task)));
+        m_completionTasks.append(std::make_pair(context, WTFMove(task)));
     else
-        task->run(&vm, *this);
+        task->run(*this);
 }
 
 void Plan::waitForCompletion()
@@ -94,19 +99,19 @@
     }
 }
 
-bool Plan::tryRemoveVMAndCancelIfLast(VM& vm)
+bool Plan::tryRemoveContextAndCancelIfLast(Context& context)
 {
     LockHolder locker(m_lock);
 
     if (!ASSERT_DISABLED) {
-        // We allow the first completion task to not have a vm.
+        // We allow the first completion task to not have a Context.
         for (unsigned i = 1; i < m_completionTasks.size(); ++i)
             ASSERT(m_completionTasks[i].first);
     }
 
     bool removedAnyTasks = false;
-    m_completionTasks.removeAllMatching([&] (const std::pair<VM*, CompletionTask>& pair) {
-        bool shouldRemove = pair.first == &vm;
+    m_completionTasks.removeAllMatching([&] (const std::pair<Context*, CompletionTask>& pair) {
+        bool shouldRemove = pair.first == &context;
         removedAnyTasks |= shouldRemove;
         return shouldRemove;
     });
diff --git a/Source/JavaScriptCore/wasm/WasmPlan.h b/Source/JavaScriptCore/wasm/WasmPlan.h
index 10f8a1b..7a07bfd 100644
--- a/Source/JavaScriptCore/wasm/WasmPlan.h
+++ b/Source/JavaScriptCore/wasm/WasmPlan.h
@@ -28,8 +28,8 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "CompilationResult.h"
-#include "VM.h"
 #include "WasmB3IRGenerator.h"
+#include "WasmEmbedder.h"
 #include "WasmModuleInformation.h"
 #include <wtf/Bag.h>
 #include <wtf/SharedTask.h>
@@ -39,25 +39,27 @@
 namespace JSC {
 
 class CallLinkInfo;
-class JSGlobalObject;
-class JSPromiseDeferred;
 
 namespace Wasm {
 
+struct Context;
+
 class Plan : public ThreadSafeRefCounted<Plan> {
 public:
-    typedef void CallbackType(VM*, Plan&);
+    typedef void CallbackType(Plan&);
     using CompletionTask = RefPtr<SharedTask<CallbackType>>;
-    static CompletionTask dontFinalize() { return createSharedTask<CallbackType>([](VM*, Plan&) { }); }
-    Plan(VM*, Ref<ModuleInformation>, CompletionTask&&);
+
+    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
-    JS_EXPORT_PRIVATE Plan(VM*, const uint8_t*, size_t, CompletionTask&&);
+    JS_EXPORT_PRIVATE Plan(Context*, const uint8_t*, size_t, CompletionTask&&);
     virtual JS_EXPORT_PRIVATE ~Plan();
 
     // If you guarantee the ordering here, you can rely on FIFO of the
     // completion tasks being called.
-    void addCompletionTask(VM&, CompletionTask&&);
+    void addCompletionTask(Context*, CompletionTask&&);
 
     void setMode(MemoryMode mode) { m_mode = mode; }
     MemoryMode mode() const { return m_mode; }
@@ -72,7 +74,7 @@
 
     void waitForCompletion();
     // Returns true if it cancelled the plan.
-    bool tryRemoveVMAndCancelIfLast(VM&);
+    bool tryRemoveContextAndCancelIfLast(Context&);
 
 protected:
     void runCompletionTasks(const AbstractLocker&);
@@ -83,7 +85,10 @@
 
     Ref<ModuleInformation> m_moduleInformation;
 
-    Vector<std::pair<VM*, CompletionTask>, 1> m_completionTasks;
+    Vector<std::pair<Context*, CompletionTask>, 1> m_completionTasks;
+
+    CreateEmbedderWrapper m_createEmbedderWrapper;
+    ThrowWasmException m_throwWasmException { nullptr };
 
     const uint8_t* m_source;
     const size_t m_sourceLength;
diff --git a/Source/JavaScriptCore/wasm/WasmSignature.cpp b/Source/JavaScriptCore/wasm/WasmSignature.cpp
index 8b600ed..6a42d51 100644
--- a/Source/JavaScriptCore/wasm/WasmSignature.cpp
+++ b/Source/JavaScriptCore/wasm/WasmSignature.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -28,10 +28,10 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "VM.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/HashFunctions.h>
 #include <wtf/PrintStream.h>
+#include <wtf/text/WTFString.h>
 
 namespace JSC { namespace Wasm {
 
diff --git a/Source/JavaScriptCore/wasm/WasmSignature.h b/Source/JavaScriptCore/wasm/WasmSignature.h
index e413b25..aaced5d 100644
--- a/Source/JavaScriptCore/wasm/WasmSignature.h
+++ b/Source/JavaScriptCore/wasm/WasmSignature.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -43,8 +43,6 @@
 
 namespace JSC {
 
-class VM;
-
 namespace Wasm {
 
 using SignatureArgCount = uint32_t;
@@ -156,7 +154,7 @@
 
 namespace JSC { namespace Wasm {
 
-// Signature information is held globally and shared by VMs to allow all signatures to be unique. This is required when wasm calls another wasm instance, and must work when modules are shared between multiple VMs.
+// Signature information is held globally and shared by the entire process to allow all signatures to be unique. This is required when wasm calls another wasm instance, and must work when modules are shared between multiple VMs.
 // Note: signatures are never removed because that would require accounting for all WebAssembly.Module and which signatures they use. The maximum number of signatures is bounded, and isn't worth the counting overhead. We could clear everything when we reach zero outstanding WebAssembly.Module. https://bugs.webkit.org/show_bug.cgi?id=166037
 class SignatureInformation {
     WTF_MAKE_NONCOPYABLE(SignatureInformation);
diff --git a/Source/JavaScriptCore/wasm/WasmTable.cpp b/Source/JavaScriptCore/wasm/WasmTable.cpp
new file mode 100644
index 0000000..fbea8d0
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmTable.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmTable.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include <wtf/CheckedArithmetic.h>
+#include <wtf/StdLibExtras.h>
+#include <type_traits>
+
+namespace JSC { namespace Wasm {
+
+RefPtr<Table> Table::create(uint32_t initial, std::optional<uint32_t> maximum)
+{
+    if (!isValidSize(initial))
+        return nullptr;
+    return adoptRef(new (NotNull, fastMalloc(sizeof(Table))) Table(initial, maximum));
+}
+
+Table::~Table()
+{
+}
+
+Table::Table(uint32_t initial, std::optional<uint32_t> maximum)
+{
+    m_size = initial;
+    m_maximum = maximum;
+    ASSERT(isValidSize(m_size));
+    ASSERT(!m_maximum || *m_maximum >= m_size);
+
+    // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
+    // But for now, we're not doing that.
+    m_functions = MallocPtr<Wasm::CallableFunction>::malloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(size()));
+    m_instances = MallocPtr<JSWebAssemblyInstance*>::malloc(sizeof(JSWebAssemblyInstance*) * static_cast<size_t>(size()));
+    for (uint32_t i = 0; i < size(); ++i) {
+        new (&m_functions.get()[i]) CallableFunction();
+        ASSERT(m_functions.get()[i].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
+        m_instances.get()[i] = nullptr;
+    }
+}
+
+std::optional<uint32_t> Table::grow(uint32_t delta)
+{
+    if (delta == 0)
+        return size();
+
+    using Checked = Checked<uint32_t, RecordOverflow>;
+    Checked newSizeChecked = size();
+    newSizeChecked += delta;
+    uint32_t newSize;
+    if (newSizeChecked.safeGet(newSize) == CheckedState::DidOverflow)
+        return std::nullopt;
+
+    if (maximum() && newSize > *maximum())
+        return std::nullopt;
+    if (!isValidSize(newSize))
+        return std::nullopt;
+
+    auto checkedGrow = [&] (auto& container) {
+        Checked reallocSizeChecked = newSizeChecked;
+        reallocSizeChecked *= sizeof(*container.get());
+        uint32_t reallocSize;
+        if (reallocSizeChecked.safeGet(reallocSize) == CheckedState::DidOverflow)
+            return false;
+        container.realloc(reallocSize);
+        for (uint32_t i = m_size; i < newSize; ++i)
+            new (&container.get()[i]) std::remove_reference_t<decltype(*container.get())>();
+        return true;
+    };
+
+    if (!checkedGrow(m_functions))
+        return std::nullopt;
+    if (!checkedGrow(m_instances))
+        return std::nullopt;
+
+    m_size = newSize;
+
+    return newSize;
+}
+
+void Table::clearFunction(uint32_t index)
+{
+    RELEASE_ASSERT(index < size());
+    m_functions.get()[index] = Wasm::CallableFunction();
+    ASSERT(m_functions.get()[index].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
+    m_instances.get()[index] = nullptr;
+}
+
+void Table::setFunction(uint32_t index, CallableFunction function, JSWebAssemblyInstance* instance)
+{
+    RELEASE_ASSERT(index < size());
+    m_functions.get()[index] = function;
+    m_instances.get()[index] = instance;
+}
+
+} } // namespace JSC::Table
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmTable.h b/Source/JavaScriptCore/wasm/WasmTable.h
new file mode 100644
index 0000000..a92a9a9
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/WasmTable.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "WasmFormat.h"
+#include "WasmLimits.h"
+#include <wtf/MallocPtr.h>
+#include <wtf/Optional.h>
+#include <wtf/Ref.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace JSC {
+
+class JSWebAssemblyInstance; // FIXME this should be Wasm::Instance https://webkit.org/b/177472
+
+namespace Wasm {
+
+class Table : public ThreadSafeRefCounted<Table> {
+public:
+    static RefPtr<Table> create(uint32_t initial, std::optional<uint32_t> maximum);
+
+    JS_EXPORT_PRIVATE ~Table();
+
+    std::optional<uint32_t> maximum() const { return m_maximum; }
+    uint32_t size() const { return m_size; }
+    std::optional<uint32_t> grow(uint32_t delta) WARN_UNUSED_RETURN;
+    void clearFunction(uint32_t);
+    void setFunction(uint32_t, CallableFunction, JSWebAssemblyInstance*); // FIXME make this Wasm::Instance. https://webkit.org/b/177472
+
+    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Table, m_size); }
+    static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(Table, m_functions); }
+    static ptrdiff_t offsetOfInstances() { return OBJECT_OFFSETOF(Table, m_instances); }
+
+    static bool isValidSize(uint32_t size) { return size < maxTableEntries; }
+
+private:
+    Table(uint32_t initial, std::optional<uint32_t> maximum);
+
+    std::optional<uint32_t> m_maximum;
+    uint32_t m_size;
+    MallocPtr<CallableFunction> m_functions;
+    // call_indirect needs to do an Instance check to potentially context switch when calling a function to another instance. We can hold raw pointers to Instance here because the embedder ensures that Table keeps all the instances alive. We couldn't hold a Ref here because it would cause cycles.
+    MallocPtr<JSWebAssemblyInstance*> m_instances; // FIXME make this a Wasm::Instance. https://webkit.org/b/177472
+};
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/WasmThunks.cpp b/Source/JavaScriptCore/wasm/WasmThunks.cpp
index 977b01b..c235980 100644
--- a/Source/JavaScriptCore/wasm/WasmThunks.cpp
+++ b/Source/JavaScriptCore/wasm/WasmThunks.cpp
@@ -29,11 +29,9 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "CCallHelpers.h"
-#include "FrameTracers.h"
 #include "HeapCellInlines.h"
 #include "JITExceptions.h"
 #include "JSWebAssemblyInstance.h"
-#include "JSWebAssemblyRuntimeError.h"
 #include "LinkBuffer.h"
 #include "ScratchRegisterAllocator.h"
 #include "WasmContext.h"
@@ -48,46 +46,18 @@
 
     // The thing that jumps here must move ExceptionType into the argumentGPR1 before jumping here.
     // We're allowed to use temp registers here. We are not allowed to use callee saves.
-    jit.loadWasmContext(GPRInfo::argumentGPR2);
-    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Context::offsetOfVM()), GPRInfo::argumentGPR0);
+    jit.loadWasmContextInstance(GPRInfo::argumentGPR2);
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, JSWebAssemblyInstance::offsetOfVM()), GPRInfo::argumentGPR0);
     jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     CCallHelpers::Call call = jit.call();
     jit.jump(GPRInfo::returnValueGPR);
     jit.breakpoint(); // We should not reach this.
 
-    void* (*throwWasmException)(ExecState*, Wasm::ExceptionType, Wasm::Context*) = [] (ExecState* exec, Wasm::ExceptionType type, Wasm::Context* wasmContext) -> void* {
-        VM* vm = wasmContext->vm();
-        NativeCallFrameTracer tracer(vm, exec);
-
-        {
-            auto throwScope = DECLARE_THROW_SCOPE(*vm);
-            JSGlobalObject* globalObject = wasmContext->globalObject();
-
-            JSObject* error; 
-            if (type == ExceptionType::StackOverflow)
-                error = createStackOverflowError(exec, globalObject);
-            else
-                error = JSWebAssemblyRuntimeError::create(exec, *vm, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
-            throwException(exec, throwScope, error);
-        }
-
-        genericUnwind(vm, exec);
-        ASSERT(!!vm->callFrameForCatch);
-        ASSERT(!!vm->targetMachinePCForThrow);
-        // FIXME: We could make this better:
-        // This is a total hack, but the llint (both op_catch and handleUncaughtException)
-        // require a cell in the callee field to load the VM. (The baseline JIT does not require
-        // this since it is compiled with a constant VM pointer.) We could make the calling convention
-        // for exceptions first load callFrameForCatch info call frame register before jumping
-        // to the exception handler. If we did this, we could remove this terrible hack.
-        // https://bugs.webkit.org/show_bug.cgi?id=170440
-        bitwise_cast<uint64_t*>(exec)[CallFrameSlot::callee] = bitwise_cast<uint64_t>(wasmContext->webAssemblyToJSCallee());
-        return vm->targetMachinePCForThrow;
-    };
-
+    ThrowWasmException throwWasmException = Thunks::singleton().throwWasmException();
+    RELEASE_ASSERT(throwWasmException);
     LinkBuffer linkBuffer(jit, GLOBAL_THUNK_ID);
-    linkBuffer.link(call, throwWasmException);
+    linkBuffer.link(call, FunctionPtr(throwWasmException));
     return FINALIZE_CODE(linkBuffer, ("Throw exception from Wasm"));
 }
 
@@ -119,8 +89,10 @@
 #endif
     unsigned numberOfStackBytesUsedForRegisterPreservation = ScratchRegisterAllocator::preserveRegistersToStackForCall(jit, registersToSpill, extraPaddingBytes);
 
-    jit.loadWasmContext(GPRInfo::argumentGPR0);
-    jit.move(MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(runOMGPlanForIndex)), GPRInfo::argumentGPR2);
+    jit.loadWasmContextInstance(GPRInfo::argumentGPR0);
+    typedef void (*Run)(JSWebAssemblyInstance*, uint32_t);
+    Run run = OMGPlan::runForIndex;
+    jit.move(MacroAssembler::TrustedImmPtr(reinterpret_cast<void*>(run)), GPRInfo::argumentGPR2);
     jit.call(GPRInfo::argumentGPR2);
 
     ScratchRegisterAllocator::restoreRegistersFromStackForCall(jit, registersToSpill, RegisterSet(), numberOfStackBytesUsedForRegisterPreservation, extraPaddingBytes);
@@ -142,6 +114,19 @@
     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 Thunks::stub(ThunkGenerator generator)
 {
     auto locker = holdLock(m_lock);
diff --git a/Source/JavaScriptCore/wasm/WasmThunks.h b/Source/JavaScriptCore/wasm/WasmThunks.h
index df14ca2..529764e 100644
--- a/Source/JavaScriptCore/wasm/WasmThunks.h
+++ b/Source/JavaScriptCore/wasm/WasmThunks.h
@@ -28,6 +28,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "MacroAssemblerCodeRef.h"
+#include "WasmEmbedder.h"
 
 namespace JSC { namespace Wasm {
 
@@ -42,6 +43,9 @@
     static void initialize();
     static Thunks& singleton();
 
+    void setThrowWasmException(ThrowWasmException);
+    ThrowWasmException throwWasmException();
+
     MacroAssemblerCodeRef stub(ThunkGenerator);
     MacroAssemblerCodeRef stub(const AbstractLocker&, ThunkGenerator);
     MacroAssemblerCodeRef existingStub(ThunkGenerator);
@@ -50,6 +54,7 @@
     Thunks() = default;
 
     HashMap<ThunkGenerator, MacroAssemblerCodeRef> m_stubs;
+    ThrowWasmException m_throwWasmException { nullptr };
     Lock m_lock;
 };
 
diff --git a/Source/JavaScriptCore/wasm/WasmWorklist.cpp b/Source/JavaScriptCore/wasm/WasmWorklist.cpp
index 9c5b684..2fe132c 100644
--- a/Source/JavaScriptCore/wasm/WasmWorklist.cpp
+++ b/Source/JavaScriptCore/wasm/WasmWorklist.cpp
@@ -22,6 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+
 #include "config.h"
 #include "WasmWorklist.h"
 
@@ -172,13 +173,13 @@
     plan.waitForCompletion();
 }
 
-void Worklist::stopAllPlansForVM(VM& vm)
+void Worklist::stopAllPlansForContext(Context& context)
 {
     LockHolder locker(*m_lock);
     Vector<QueueElement> elements;
     while (!m_queue.isEmpty()) {
         QueueElement element = m_queue.dequeue();
-        bool didCancel = element.plan->tryRemoveVMAndCancelIfLast(vm);
+        bool didCancel = element.plan->tryRemoveContextAndCancelIfLast(context);
         if (!didCancel)
             elements.append(WTFMove(element));
     }
@@ -188,7 +189,7 @@
 
     for (auto& thread : m_threads) {
         if (thread->element.plan) {
-            bool didCancel = thread->element.plan->tryRemoveVMAndCancelIfLast(vm);
+            bool didCancel = thread->element.plan->tryRemoveContextAndCancelIfLast(context);
             if (didCancel) {
                 // We don't have to worry about the deadlocking since the thread can't block without checking for a new plan and must hold the lock to do so.
                 thread->synchronize.wait(*m_lock);
diff --git a/Source/JavaScriptCore/wasm/WasmWorklist.h b/Source/JavaScriptCore/wasm/WasmWorklist.h
index 6b69352..748a9ec 100644
--- a/Source/JavaScriptCore/wasm/WasmWorklist.h
+++ b/Source/JavaScriptCore/wasm/WasmWorklist.h
@@ -27,8 +27,6 @@
 
 #if ENABLE(WEBASSEMBLY)
 
-#include "VM.h"
-
 #include <queue>
 
 #include <wtf/AutomaticThread.h>
@@ -37,10 +35,9 @@
 
 namespace JSC {
 
-class JSPromiseDeferred;
-
 namespace Wasm {
 
+struct Context;
 class Plan;
 
 class Worklist {
@@ -50,13 +47,10 @@
     ~Worklist();
 
     JS_EXPORT_PRIVATE void enqueue(Ref<Plan>);
-    void stopAllPlansForVM(VM&);
+    void stopAllPlansForContext(Context&);
 
     JS_EXPORT_PRIVATE void completePlanSynchronously(Plan&);
 
-    void activatePlan(JSPromiseDeferred*, Plan*);
-    void deactivePlan(JSPromiseDeferred*, Plan*);
-
     enum class Priority {
         Shutdown,
         Synchronous,
diff --git a/Source/JavaScriptCore/wasm/js/JSToWasm.cpp b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp
new file mode 100644
index 0000000..c2b7109
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp
@@ -0,0 +1,227 @@
+/*
+ * 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSToWasm.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "CCallHelpers.h"
+#include "JSWebAssemblyInstance.h"
+#include "WasmCallingConvention.h"
+
+namespace JSC { namespace Wasm {
+
+std::unique_ptr<InternalFunction> createJSToWasmWrapper(CompilationContext& compilationContext, const Signature& signature, Vector<UnlinkedWasmToWasmCall>* unlinkedWasmToWasmCalls, const ModuleInformation& info, MemoryMode mode, unsigned functionIndex)
+{
+    CCallHelpers& jit = *compilationContext.jsEntrypointJIT;
+
+    auto result = std::make_unique<InternalFunction>();
+    jit.emitFunctionPrologue();
+
+    // FIXME Stop using 0 as codeBlocks. https://bugs.webkit.org/show_bug.cgi?id=165321
+    jit.store64(CCallHelpers::TrustedImm64(0), CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register))));
+    MacroAssembler::DataLabelPtr calleeMoveLocation = jit.moveWithPatch(MacroAssembler::TrustedImmPtr(nullptr), GPRInfo::nonPreservedNonReturnGPR);
+    jit.storePtr(GPRInfo::nonPreservedNonReturnGPR, CCallHelpers::Address(GPRInfo::callFrameRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register))));
+    CodeLocationDataLabelPtr* linkedCalleeMove = &result->calleeMoveLocation;
+    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+        *linkedCalleeMove = linkBuffer.locationOf(calleeMoveLocation);
+    });
+
+    const PinnedRegisterInfo& pinnedRegs = PinnedRegisterInfo::get();
+    RegisterSet toSave = pinnedRegs.toSave(mode);
+
+#if !ASSERT_DISABLED
+    unsigned toSaveSize = toSave.numberOfSetGPRs();
+    // They should all be callee saves.
+    toSave.filter(RegisterSet::calleeSaveRegisters());
+    ASSERT(toSave.numberOfSetGPRs() == toSaveSize);
+#endif
+
+    RegisterAtOffsetList registersToSpill(toSave, RegisterAtOffsetList::OffsetBaseType::FramePointerBased);
+    result->entrypoint.calleeSaveRegisters = registersToSpill;
+
+    unsigned totalFrameSize = registersToSpill.size() * sizeof(void*);
+    totalFrameSize += WasmCallingConvention::headerSizeInBytes();
+    totalFrameSize -= sizeof(CallerFrameAndPC);
+    unsigned numGPRs = 0;
+    unsigned numFPRs = 0;
+    for (unsigned i = 0; i < signature.argumentCount(); i++) {
+        switch (signature.argument(i)) {
+        case Wasm::I64:
+        case Wasm::I32:
+            if (numGPRs >= wasmCallingConvention().m_gprArgs.size())
+                totalFrameSize += sizeof(void*);
+            ++numGPRs;
+            break;
+        case Wasm::F32:
+        case Wasm::F64:
+            if (numFPRs >= wasmCallingConvention().m_fprArgs.size())
+                totalFrameSize += sizeof(void*);
+            ++numFPRs;
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+
+    totalFrameSize = WTF::roundUpToMultipleOf(stackAlignmentBytes(), totalFrameSize);
+    jit.subPtr(MacroAssembler::TrustedImm32(totalFrameSize), MacroAssembler::stackPointerRegister);
+
+    // We save all these registers regardless of having a memory or not.
+    // The reason is that we use one of these as a scratch. That said,
+    // almost all real wasm programs use memory, so it's not really
+    // worth optimizing for the case that they don't.
+    for (const RegisterAtOffset& regAtOffset : registersToSpill) {
+        GPRReg reg = regAtOffset.reg().gpr();
+        ptrdiff_t offset = regAtOffset.offset();
+        jit.storePtr(reg, CCallHelpers::Address(GPRInfo::callFrameRegister, offset));
+    }
+
+    GPRReg wasmContextInstanceGPR = pinnedRegs.wasmContextInstancePointer;
+
+    {
+        CCallHelpers::Address calleeFrame = CCallHelpers::Address(MacroAssembler::stackPointerRegister, -static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC)));
+        numGPRs = 0;
+        numFPRs = 0;
+        // We're going to set the pinned registers after this. So
+        // we can use this as a scratch for now since we saved it above.
+        GPRReg scratchReg = pinnedRegs.baseMemoryPointer;
+
+        ptrdiff_t jsOffset = CallFrameSlot::thisArgument * sizeof(EncodedJSValue);
+
+        // vmEntryToWasm passes Wasm::Context*'s instance as the first JS argument when we're
+        // not using fast TLS to hold the Wasm::Context*'s instance.
+        if (!Context::useFastTLS()) {
+            jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmContextInstanceGPR);
+            jsOffset += sizeof(EncodedJSValue);
+        }
+
+        ptrdiff_t wasmOffset = CallFrame::headerSizeInRegisters * sizeof(void*);
+        for (unsigned i = 0; i < signature.argumentCount(); i++) {
+            switch (signature.argument(i)) {
+            case Wasm::I32:
+            case Wasm::I64:
+                if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) {
+                    if (signature.argument(i) == Wasm::I32) {
+                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
+                        jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset));
+                    } else {
+                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
+                        jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset));
+                    }
+                    wasmOffset += sizeof(void*);
+                } else {
+                    if (signature.argument(i) == Wasm::I32)
+                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr());
+                    else
+                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_gprArgs[numGPRs].gpr());
+                }
+                ++numGPRs;
+                break;
+            case Wasm::F32:
+            case Wasm::F64:
+                if (numFPRs >= wasmCallingConvention().m_fprArgs.size()) {
+                    if (signature.argument(i) == Wasm::F32) {
+                        jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
+                        jit.store32(scratchReg, calleeFrame.withOffset(wasmOffset));
+                    } else {
+                        jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
+                        jit.store64(scratchReg, calleeFrame.withOffset(wasmOffset));
+                    }
+                    wasmOffset += sizeof(void*);
+                } else {
+                    if (signature.argument(i) == Wasm::F32)
+                        jit.loadFloat(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr());
+                    else
+                        jit.loadDouble(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), wasmCallingConvention().m_fprArgs[numFPRs].fpr());
+                }
+                ++numFPRs;
+                break;
+            default:
+                RELEASE_ASSERT_NOT_REACHED();
+            }
+
+            jsOffset += sizeof(EncodedJSValue);
+        }
+    }
+
+    if (!!info.memory) {
+        GPRReg baseMemory = pinnedRegs.baseMemoryPointer;
+
+        if (!Context::useFastTLS())
+            jit.loadPtr(CCallHelpers::Address(wasmContextInstanceGPR, JSWebAssemblyInstance::offsetOfWasmMemory()), baseMemory);
+        else {
+            jit.loadWasmContextInstance(baseMemory);
+            jit.loadPtr(CCallHelpers::Address(baseMemory, JSWebAssemblyInstance::offsetOfWasmMemory()), baseMemory);
+        }
+
+        if (mode != MemoryMode::Signaling) {
+            const auto& sizeRegs = pinnedRegs.sizeRegisters;
+            ASSERT(sizeRegs.size() >= 1);
+            ASSERT(!sizeRegs[0].sizeOffset); // The following code assumes we start at 0, and calculates subsequent size registers relative to 0.
+            jit.loadPtr(CCallHelpers::Address(baseMemory, Wasm::Memory::offsetOfSize()), sizeRegs[0].sizeRegister);
+            for (unsigned i = 1; i < sizeRegs.size(); ++i)
+                jit.add64(CCallHelpers::TrustedImm32(-sizeRegs[i].sizeOffset), sizeRegs[0].sizeRegister, sizeRegs[i].sizeRegister);
+        }
+
+        jit.loadPtr(CCallHelpers::Address(baseMemory, Wasm::Memory::offsetOfMemory()), baseMemory);
+    }
+
+    CCallHelpers::Call call = jit.threadSafePatchableNearCall();
+    unsigned functionIndexSpace = functionIndex + info.importFunctionCount();
+    ASSERT(functionIndexSpace < info.functionIndexSpaceSize());
+    jit.addLinkTask([unlinkedWasmToWasmCalls, call, functionIndexSpace] (LinkBuffer& linkBuffer) {
+        unlinkedWasmToWasmCalls->append({ linkBuffer.locationOfNearCall(call), functionIndexSpace });
+    });
+
+
+    for (const RegisterAtOffset& regAtOffset : registersToSpill) {
+        GPRReg reg = regAtOffset.reg().gpr();
+        ASSERT(reg != GPRInfo::returnValueGPR);
+        ptrdiff_t offset = regAtOffset.offset();
+        jit.loadPtr(CCallHelpers::Address(GPRInfo::callFrameRegister, offset), reg);
+    }
+
+    switch (signature.returnType()) {
+    case Wasm::F32:
+        jit.moveFloatTo32(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR);
+        break;
+    case Wasm::F64:
+        jit.moveDoubleTo64(FPRInfo::returnValueFPR, GPRInfo::returnValueGPR);
+        break;
+    default:
+        break;
+    }
+
+    jit.emitFunctionEpilogue();
+    jit.ret();
+
+    return result;
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/js/JSToWasm.h b/Source/JavaScriptCore/wasm/js/JSToWasm.h
new file mode 100644
index 0000000..b4b98d1
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/js/JSToWasm.h
@@ -0,0 +1,48 @@
+/*
+ * 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "InternalFunction.h"
+#include "WasmB3IRGenerator.h"
+#include "WasmFormat.h"
+#include "WasmMemory.h"
+#include "WasmModuleInformation.h"
+#include "WasmSignature.h"
+#include <wtf/Vector.h>
+
+#include <memory>
+
+namespace JSC {
+
+namespace Wasm {
+
+std::unique_ptr<InternalFunction> createJSToWasmWrapper(CompilationContext&, const Signature&, Vector<UnlinkedWasmToWasmCall>*, const ModuleInformation&, MemoryMode, uint32_t functionIndex);
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/JSWebAssembly.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssembly.cpp
similarity index 100%
rename from Source/JavaScriptCore/wasm/JSWebAssembly.cpp
rename to Source/JavaScriptCore/wasm/js/JSWebAssembly.cpp
diff --git a/Source/JavaScriptCore/wasm/JSWebAssembly.h b/Source/JavaScriptCore/wasm/js/JSWebAssembly.h
similarity index 62%
rename from Source/JavaScriptCore/wasm/JSWebAssembly.h
rename to Source/JavaScriptCore/wasm/js/JSWebAssembly.h
index 0faf977..c578df2 100644
--- a/Source/JavaScriptCore/wasm/JSWebAssembly.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssembly.h
@@ -28,31 +28,31 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "JSObject.h"
-#include "js/JSWebAssemblyCompileError.h"
-#include "js/JSWebAssemblyInstance.h"
-#include "js/JSWebAssemblyLinkError.h"
-#include "js/JSWebAssemblyMemory.h"
-#include "js/JSWebAssemblyModule.h"
-#include "js/JSWebAssemblyRuntimeError.h"
-#include "js/JSWebAssemblyTable.h"
-#include "js/WebAssemblyCompileErrorConstructor.h"
-#include "js/WebAssemblyCompileErrorPrototype.h"
-#include "js/WebAssemblyFunction.h"
-#include "js/WebAssemblyInstanceConstructor.h"
-#include "js/WebAssemblyInstancePrototype.h"
-#include "js/WebAssemblyLinkErrorConstructor.h"
-#include "js/WebAssemblyLinkErrorPrototype.h"
-#include "js/WebAssemblyMemoryConstructor.h"
-#include "js/WebAssemblyMemoryPrototype.h"
-#include "js/WebAssemblyModuleConstructor.h"
-#include "js/WebAssemblyModulePrototype.h"
-#include "js/WebAssemblyModuleRecord.h"
-#include "js/WebAssemblyPrototype.h"
-#include "js/WebAssemblyRuntimeErrorConstructor.h"
-#include "js/WebAssemblyRuntimeErrorPrototype.h"
-#include "js/WebAssemblyTableConstructor.h"
-#include "js/WebAssemblyTablePrototype.h"
-#include "js/WebAssemblyToJSCallee.h"
+#include "JSWebAssemblyCompileError.h"
+#include "JSWebAssemblyInstance.h"
+#include "JSWebAssemblyLinkError.h"
+#include "JSWebAssemblyMemory.h"
+#include "JSWebAssemblyModule.h"
+#include "JSWebAssemblyRuntimeError.h"
+#include "JSWebAssemblyTable.h"
+#include "WebAssemblyCompileErrorConstructor.h"
+#include "WebAssemblyCompileErrorPrototype.h"
+#include "WebAssemblyFunction.h"
+#include "WebAssemblyInstanceConstructor.h"
+#include "WebAssemblyInstancePrototype.h"
+#include "WebAssemblyLinkErrorConstructor.h"
+#include "WebAssemblyLinkErrorPrototype.h"
+#include "WebAssemblyMemoryConstructor.h"
+#include "WebAssemblyMemoryPrototype.h"
+#include "WebAssemblyModuleConstructor.h"
+#include "WebAssemblyModulePrototype.h"
+#include "WebAssemblyModuleRecord.h"
+#include "WebAssemblyPrototype.h"
+#include "WebAssemblyRuntimeErrorConstructor.h"
+#include "WebAssemblyRuntimeErrorPrototype.h"
+#include "WebAssemblyTableConstructor.h"
+#include "WebAssemblyTablePrototype.h"
+#include "WebAssemblyToJSCallee.h"
 
 namespace JSC {
 
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp
index f91e6c7..e15ca34 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp
@@ -31,9 +31,8 @@
 #include "JSCInlines.h"
 #include "JSWebAssemblyLinkError.h"
 #include "JSWebAssemblyMemory.h"
-#include "JSWebAssemblyModule.h"
-#include "WasmBinding.h"
 #include "WasmModuleInformation.h"
+#include "WasmToJS.h"
 
 #include <wtf/CurrentTime.h>
 
@@ -41,11 +40,10 @@
 
 const ClassInfo JSWebAssemblyCodeBlock::s_info = { "WebAssemblyCodeBlock", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyCodeBlock) };
 
-JSWebAssemblyCodeBlock* JSWebAssemblyCodeBlock::create(VM& vm, Ref<Wasm::CodeBlock> codeBlock, JSWebAssemblyModule* module)
+JSWebAssemblyCodeBlock* JSWebAssemblyCodeBlock::create(VM& vm, Ref<Wasm::CodeBlock> codeBlock, const Wasm::ModuleInformation& moduleInformation)
 {
-    const Wasm::ModuleInformation& moduleInformation = module->module().moduleInformation();
-    auto* result = new (NotNull, allocateCell<JSWebAssemblyCodeBlock>(vm.heap, allocationSize(moduleInformation.importFunctionCount()))) JSWebAssemblyCodeBlock(vm, WTFMove(codeBlock), moduleInformation);
-    result->finishCreation(vm, module);
+    auto* result = new (NotNull, allocateCell<JSWebAssemblyCodeBlock>(vm.heap)) JSWebAssemblyCodeBlock(vm, WTFMove(codeBlock), moduleInformation);
+    result->finishCreation(vm);
     return result;
 }
 
@@ -58,7 +56,7 @@
     m_wasmToJSExitStubs.reserveCapacity(m_codeBlock->functionImportCount());
     for (unsigned importIndex = 0; importIndex < m_codeBlock->functionImportCount(); ++importIndex) {
         Wasm::SignatureIndex signatureIndex = moduleInformation.importFunctionSignatureIndices.at(importIndex);
-        auto binding = Wasm::wasmToJs(&vm, m_callLinkInfos, signatureIndex, importIndex);
+        auto binding = Wasm::wasmToJS(&vm, m_callLinkInfos, signatureIndex, importIndex);
         if (UNLIKELY(!binding)) {
             switch (binding.error()) {
             case Wasm::BindingFailure::OutOfMemory:
@@ -68,14 +66,12 @@
             RELEASE_ASSERT_NOT_REACHED();
         }
         m_wasmToJSExitStubs.uncheckedAppend(binding.value());
-        importWasmToJSStub(importIndex) = m_wasmToJSExitStubs[importIndex].code().executableAddress();
     }
 }
 
-void JSWebAssemblyCodeBlock::finishCreation(VM& vm, JSWebAssemblyModule* module)
+void JSWebAssemblyCodeBlock::finishCreation(VM& vm)
 {
     Base::finishCreation(vm);
-    m_module.set(vm, this, module);
 }
 
 void JSWebAssemblyCodeBlock::destroy(JSCell* cell)
@@ -83,11 +79,6 @@
     static_cast<JSWebAssemblyCodeBlock*>(cell)->JSWebAssemblyCodeBlock::~JSWebAssemblyCodeBlock();
 }
 
-bool JSWebAssemblyCodeBlock::isSafeToRun(JSWebAssemblyMemory* memory) const
-{
-    return m_codeBlock->isSafeToRun(memory->memory().mode());
-}
-
 void JSWebAssemblyCodeBlock::clearJSCallICs(VM& vm)
 {
     for (auto iter = m_callLinkInfos.begin(); !!iter; ++iter)
@@ -100,7 +91,6 @@
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
 
     Base::visitChildren(thisObject, visitor);
-    visitor.append(thisObject->m_module);
 
     visitor.addUnconditionalFinalizer(&thisObject->m_unconditionalFinalizer);
 }
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h
index 52703f8..890e272 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.h
@@ -40,7 +40,6 @@
 
 namespace JSC {
 
-class JSWebAssemblyModule;
 class JSWebAssemblyMemory;
 
 namespace Wasm {
@@ -52,7 +51,7 @@
     typedef JSCell Base;
     static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 
-    static JSWebAssemblyCodeBlock* create(VM&, Ref<Wasm::CodeBlock>, JSWebAssemblyModule*);
+    static JSWebAssemblyCodeBlock* create(VM&, Ref<Wasm::CodeBlock>, const Wasm::ModuleInformation&);
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
         return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
@@ -64,38 +63,11 @@
         return &vm.webAssemblyCodeBlockSpace;
     }
 
-    unsigned functionImportCount() const { return m_codeBlock->functionImportCount(); }
-    JSWebAssemblyModule* module() const { return m_module.get(); }
-
-    bool isSafeToRun(JSWebAssemblyMemory*) const;
-
-    void finishCreation(VM&, JSWebAssemblyModule*);
-
-    // These two callee getters are only valid once the callees have been populated.
-
-    Wasm::Callee& jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
-    {
-        ASSERT(runnable());
-        return m_codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(functionIndexSpace);
-    }
-    Wasm::WasmEntrypointLoadLocation wasmEntrypointLoadLocationFromFunctionIndexSpace(unsigned functionIndexSpace)
-    {
-        ASSERT(runnable());
-        return m_codeBlock->wasmEntrypointLoadLocationFromFunctionIndexSpace(functionIndexSpace);
-    }
-
-    Wasm::WasmEntrypointLoadLocation wasmToJsCallStubForImport(unsigned importIndex)
-    {
-        ASSERT(runnable());
-        return &importWasmToJSStub(importIndex);
-    }
-
-    static ptrdiff_t offsetOfImportWasmToJSStub(unsigned importIndex)
-    {
-        return offsetOfImportStubs() + sizeof(void*) * importIndex;
-    }
-
     Wasm::CodeBlock& codeBlock() { return m_codeBlock.get(); }
+    
+    void* wasmToEmbedderStubExecutableAddress(size_t importFunctionNum) { return m_wasmToJSExitStubs[importFunctionNum].code().executableAddress(); }
+
+    void finishCreation(VM&);
 
     void clearJSCallICs(VM&);
 
@@ -114,27 +86,11 @@
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    static size_t offsetOfImportStubs()
-    {
-        return WTF::roundUpToMultipleOf<sizeof(void*)>(sizeof(JSWebAssemblyCodeBlock));
-    }
-
-    static size_t allocationSize(Checked<size_t> functionImportCount)
-    {
-        return (offsetOfImportStubs() + sizeof(void*) * functionImportCount).unsafeGet();
-    }
-
-    void*& importWasmToJSStub(unsigned importIndex)
-    {
-        return *bitwise_cast<void**>(bitwise_cast<char*>(this) + offsetOfImportWasmToJSStub(importIndex));
-    }
-
     class UnconditionalFinalizer : public JSC::UnconditionalFinalizer {
         void finalizeUnconditionally() override;
     };
 
     Ref<Wasm::CodeBlock> m_codeBlock;
-    WriteBarrier<JSWebAssemblyModule> m_module;
     Vector<MacroAssemblerCodeRef> m_wasmToJSExitStubs;
     UnconditionalFinalizer m_unconditionalFinalizer;
     Bag<CallLinkInfo> m_callLinkInfos;
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
index c77fa05..9649296 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
@@ -49,12 +49,17 @@
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 }
 
-JSWebAssemblyInstance::JSWebAssemblyInstance(VM& vm, Structure* structure, unsigned numImportFunctions)
+JSWebAssemblyInstance::JSWebAssemblyInstance(VM& vm, Structure* structure, unsigned numImportFunctions, Ref<Wasm::Instance>&& instance)
     : Base(vm, structure)
+    , m_instance(WTFMove(instance))
     , m_vm(&vm)
+    , m_wasmModule(m_instance->module())
+    , m_wasmTable(m_instance->m_table.get())
+    , m_globals(m_instance->m_globals.get())
     , m_numImportFunctions(numImportFunctions)
 {
-    memset(importFunctions(), 0, m_numImportFunctions * sizeof(WriteBarrier<JSObject>));
+    for (unsigned i = 0; i < m_numImportFunctions; ++i)
+        new (importFunctionInfo(i)) ImportFunctionInfo();
 }
 
 void JSWebAssemblyInstance::finishCreation(VM& vm, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
@@ -63,12 +68,10 @@
     ASSERT(inherits(vm, info()));
 
     m_module.set(vm, this, module);
-    const size_t extraMemorySize = globalMemoryByteSize();
-    m_globals = MallocPtr<uint64_t>::malloc(extraMemorySize);
-    heap()->reportExtraMemoryAllocated(extraMemorySize);
-
     m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
     m_callee.set(vm, this, module->callee());
+    
+    heap()->reportExtraMemoryAllocated(m_instance->extraMemoryAllocated());
 }
 
 void JSWebAssemblyInstance::destroy(JSCell* cell)
@@ -88,40 +91,49 @@
     visitor.append(thisObject->m_memory);
     visitor.append(thisObject->m_table);
     visitor.append(thisObject->m_callee);
-    visitor.reportExtraMemoryVisited(thisObject->globalMemoryByteSize());
+    visitor.reportExtraMemoryVisited(thisObject->m_instance->extraMemoryAllocated());
     for (unsigned i = 0; i < thisObject->m_numImportFunctions; ++i)
-        visitor.append(thisObject->importFunctions()[i]);
+        visitor.append(thisObject->importFunctionInfo(i)->importFunction); // This also keeps the functions' JSWebAssemblyInstance alive.
 }
 
 void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec, Ref<Wasm::CodeBlock>&& wasmCodeBlock)
 {
+    m_instance->finalizeCreation(wasmCodeBlock.copyRef());
+    m_wasmCodeBlock = wasmCodeBlock.ptr();
+
     auto scope = DECLARE_THROW_SCOPE(vm);
+
     if (!wasmCodeBlock->runnable()) {
         throwException(exec, scope, JSWebAssemblyLinkError::create(exec, vm, globalObject()->WebAssemblyLinkErrorStructure(), wasmCodeBlock->errorMessage()));
         return;
     }
 
     RELEASE_ASSERT(wasmCodeBlock->isSafeToRun(memoryMode()));
-    JSWebAssemblyCodeBlock* codeBlock = module()->codeBlock(memoryMode());
-    if (codeBlock) {
+    JSWebAssemblyCodeBlock* jsCodeBlock = m_module->codeBlock(memoryMode());
+    if (jsCodeBlock) {
         // A CodeBlock might have already been compiled. If so, it means
         // that the CodeBlock we are trying to compile must be the same
         // because we will never compile a CodeBlock again once it's
         // runnable.
-        ASSERT(&codeBlock->codeBlock() == wasmCodeBlock.ptr());
-        m_codeBlock.set(vm, this, codeBlock);
+        ASSERT(&jsCodeBlock->codeBlock() == wasmCodeBlock.ptr());
+        m_codeBlock.set(vm, this, jsCodeBlock);
     } else {
-        codeBlock = JSWebAssemblyCodeBlock::create(vm, wasmCodeBlock.copyRef(), m_module.get());
-        if (UNLIKELY(!codeBlock->runnable())) {
-            throwException(exec, scope, JSWebAssemblyLinkError::create(exec, vm, globalObject()->WebAssemblyLinkErrorStructure(), codeBlock->errorMessage()));
+        jsCodeBlock = JSWebAssemblyCodeBlock::create(vm, WTFMove(wasmCodeBlock), wasmModule().moduleInformation());
+        if (UNLIKELY(!jsCodeBlock->runnable())) {
+            throwException(exec, scope, JSWebAssemblyLinkError::create(exec, vm, globalObject()->WebAssemblyLinkErrorStructure(), jsCodeBlock->errorMessage()));
             return;
         }
-        m_codeBlock.set(vm, this, codeBlock);
-        module()->setCodeBlock(vm, memoryMode(), codeBlock);
+        m_codeBlock.set(vm, this, jsCodeBlock);
+        m_module->setCodeBlock(vm, memoryMode(), jsCodeBlock);
+    }
+
+    for (size_t importFunctionNum = 0; importFunctionNum < m_numImportFunctions; ++importFunctionNum) {
+        ImportFunctionInfo* info = importFunctionInfo(importFunctionNum);
+        info->wasmToEmbedderStubExecutableAddress = m_codeBlock->wasmToEmbedderStubExecutableAddress(importFunctionNum);
     }
 
     auto* moduleRecord = jsCast<WebAssemblyModuleRecord*>(m_moduleNamespaceObject->moduleRecord());
-    moduleRecord->link(exec, module(), this);
+    moduleRecord->link(exec, m_module.get(), this);
     RETURN_IF_EXCEPTION(scope, void());
 
     JSValue startResult = moduleRecord->evaluate(exec);
@@ -129,7 +141,7 @@
     RETURN_IF_EXCEPTION(scope, void());
 }
 
-JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure)
+JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure, Ref<Wasm::Instance>&& instance)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
     auto* globalObject = exec->lexicalGlobalObject();
@@ -158,8 +170,8 @@
 
     JSModuleNamespaceObject* moduleNamespace = moduleRecord->getModuleNamespace(exec);
     // FIXME: These objects could be pretty big we should try to throw OOM here.
-    auto* instance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(moduleInformation.importFunctionCount()))) JSWebAssemblyInstance(vm, instanceStructure, moduleInformation.importFunctionCount());
-    instance->finishCreation(vm, jsModule, moduleNamespace);
+    auto* jsInstance = new (NotNull, allocateCell<JSWebAssemblyInstance>(vm.heap, allocationSize(moduleInformation.importFunctionCount()))) JSWebAssemblyInstance(vm, instanceStructure, moduleInformation.importFunctionCount(), WTFMove(instance));
+    jsInstance->finishCreation(vm, jsModule, moduleNamespace);
     RETURN_IF_EXCEPTION(throwScope, nullptr);
 
     // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
@@ -190,15 +202,21 @@
             if (!value.isFunction())
                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "import function", "must be callable")));
 
+            JSWebAssemblyInstance* calleeInstance = nullptr;
+            Wasm::WasmEntrypointLoadLocation wasmEntrypoint = nullptr;
             JSObject* function = jsCast<JSObject*>(value);
+
             // ii. If v is an Exported Function Exotic Object:
             WebAssemblyFunction* wasmFunction;
             WebAssemblyWrapperFunction* wasmWrapperFunction;
             if (isWebAssemblyHostFunction(vm, function, wasmFunction, wasmWrapperFunction)) {
                 // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError.
                 Wasm::SignatureIndex importedSignatureIndex;
-                if (wasmFunction)
+                if (wasmFunction) {
                     importedSignatureIndex = wasmFunction->signatureIndex();
+                    calleeInstance = wasmFunction->instance();
+                    wasmEntrypoint = wasmFunction->wasmEntrypointLoadLocation();
+                }
                 else {
                     importedSignatureIndex = wasmWrapperFunction->signatureIndex();
                     // b. Let closure be v.[[Closure]].
@@ -215,7 +233,10 @@
             // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction).
 
             ASSERT(numImportFunctions == import.kindIndex);
-            instance->importFunctions()[numImportFunctions++].set(vm, instance, function);
+            ImportFunctionInfo* info = jsInstance->importFunctionInfo(numImportFunctions++);
+            info->targetInstance = calleeInstance;
+            info->wasmEntrypoint = wasmEntrypoint;
+            info->importFunction.set(vm, jsInstance, function);
             // v. Append closure to imports.
             break;
         }
@@ -243,7 +264,8 @@
 
             // ii. Append v to tables.
             // iii. Append v.[[Table]] to imports.
-            instance->m_table.set(vm, instance, table);
+            jsInstance->m_table.set(vm, jsInstance, table);
+            jsInstance->m_wasmTable = table->table();
             break;
         }
 
@@ -273,8 +295,8 @@
 
             // ii. Append v to memories.
             // iii. Append v.[[Memory]] to imports.
-            ASSERT(!instance->m_memory);
-            instance->m_memory.set(vm, instance, memory);
+            ASSERT(!jsInstance->m_memory);
+            jsInstance->setMemory(vm, memory);
             RETURN_IF_EXCEPTION(throwScope, nullptr);
             break;
         }
@@ -291,13 +313,13 @@
             ASSERT(numImportGlobals == import.kindIndex);
             switch (moduleInformation.globals[import.kindIndex].type) {
             case Wasm::I32:
-                instance->setGlobal(numImportGlobals++, value.toInt32(exec));
+                jsInstance->instance().setGlobal(numImportGlobals++, value.toInt32(exec));
                 break;
             case Wasm::F32:
-                instance->setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec)));
+                jsInstance->instance().setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec)));
                 break;
             case Wasm::F64:
-                instance->setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber()));
+                jsInstance->instance().setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber()));
                 break;
             default:
                 RELEASE_ASSERT_NOT_REACHED();
@@ -315,14 +337,21 @@
         }
 
         if (moduleInformation.memory && !hasMemoryImport) {
-            RELEASE_ASSERT(!moduleInformation.memory.isImport());
             // We create a memory when it's a memory definition.
-            RefPtr<Wasm::Memory> memory = Wasm::Memory::create(vm, moduleInformation.memory.initial(), moduleInformation.memory.maximum());
+            RELEASE_ASSERT(!moduleInformation.memory.isImport());
+
+            auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure());
+            RETURN_IF_EXCEPTION(throwScope, nullptr);
+
+            RefPtr<Wasm::Memory> memory = Wasm::Memory::create(moduleInformation.memory.initial(), moduleInformation.memory.maximum(),
+                [&vm] (Wasm::Memory::NotifyPressure) { vm.heap.collectAsync(CollectionScope::Full); },
+                [&vm] (Wasm::Memory::SyncTryToReclaim) { vm.heap.collectSync(CollectionScope::Full); },
+                [&vm, jsMemory] (Wasm::Memory::GrowSuccess, Wasm::PageCount oldPageCount, Wasm::PageCount newPageCount) { jsMemory->growSuccessCallback(vm, oldPageCount, newPageCount); });
             if (!memory)
                 return exception(createOutOfMemoryError(exec));
 
-            instance->m_memory.set(vm, instance,
-                JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), memory.releaseNonNull()));
+            jsMemory->adopt(memory.releaseNonNull());
+            jsInstance->setMemory(vm, jsMemory);
             RETURN_IF_EXCEPTION(throwScope, nullptr);
         }
     }
@@ -336,19 +365,24 @@
         if (!!moduleInformation.tableInformation && !hasTableImport) {
             RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
             // We create a Table when it's a Table definition.
-            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(),
-                moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+            RefPtr<Wasm::Table> wasmTable = Wasm::Table::create(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+            if (!wasmTable)
+                return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
+            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
             // We should always be able to allocate a JSWebAssemblyTable we've defined.
             // If it's defined to be too large, we should have thrown a validation error.
             throwScope.assertNoException();
             ASSERT(table);
-            instance->m_table.set(vm, instance, table);
+            jsInstance->m_table.set(vm, jsInstance, table);
+            jsInstance->m_wasmTable = table->table();
         }
     }
     
-    if (!instance->memory()) {
+    if (!jsInstance->memory()) {
         // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
-        instance->m_memory.set(vm, instance, JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), Wasm::Memory::create(vm, 0, 0).releaseNonNull()));
+        auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure());
+        jsMemory->adopt(Wasm::Memory::create().releaseNonNull());
+        jsInstance->setMemory(vm, jsMemory);
         RETURN_IF_EXCEPTION(throwScope, nullptr);
     }
     
@@ -360,20 +394,13 @@
             ASSERT(global.initializationType != Wasm::Global::IsImport);
             if (global.initializationType == Wasm::Global::FromGlobalImport) {
                 ASSERT(global.initialBitsOrImportNumber < numImportGlobals);
-                instance->setGlobal(globalIndex, instance->loadI64Global(global.initialBitsOrImportNumber));
+                jsInstance->instance().setGlobal(globalIndex, jsInstance->instance().loadI64Global(global.initialBitsOrImportNumber));
             } else
-                instance->setGlobal(globalIndex, global.initialBitsOrImportNumber);
+                jsInstance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
         }
     }
 
-    ASSERT(!instance->codeBlock());
-
-    return instance;
-}
-
-size_t JSWebAssemblyInstance::globalMemoryByteSize() const
-{
-    return m_module->moduleInformation().globals.size() * sizeof(Register);
+    return jsInstance;
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
index 3cfe549..bb31ceb 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
@@ -32,6 +32,8 @@
 #include "JSWebAssemblyCodeBlock.h"
 #include "JSWebAssemblyMemory.h"
 #include "JSWebAssemblyTable.h"
+#include "WasmContext.h"
+#include "WasmInstance.h"
 
 namespace JSC {
 
@@ -39,75 +41,100 @@
 class JSWebAssemblyModule;
 class WebAssemblyToJSCallee;
 
+namespace Wasm {
+class CodeBlock;
+class Table; // FIXME remove this after refactoring. https://webkit.org/b/177472
+}
+
 class JSWebAssemblyInstance : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
 
-    static JSWebAssemblyInstance* create(VM&, ExecState*, JSWebAssemblyModule*, JSObject* importObject, Structure*);
+    static JSWebAssemblyInstance* create(VM&, ExecState*, JSWebAssemblyModule*, JSObject* importObject, Structure*, Ref<Wasm::Instance>&&);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_EXPORT_INFO;
 
-    JSWebAssemblyCodeBlock* codeBlock() const { return m_codeBlock.get(); }
     void finalizeCreation(VM&, ExecState*, Ref<Wasm::CodeBlock>&&);
-
-    JSWebAssemblyModule* module() const { return m_module.get(); }
-
-    JSObject* importFunction(unsigned idx) { RELEASE_ASSERT(idx < m_numImportFunctions); return importFunctions()[idx].get(); }
-
+    
+    Wasm::Instance& instance() { return m_instance.get(); }
+    Wasm::Context* context() const { return &m_vm->wasmContext; }
     JSModuleNamespaceObject* moduleNamespaceObject() { return m_moduleNamespaceObject.get(); }
-
-    JSWebAssemblyMemory* memory() { return m_memory.get(); }
-    void setMemory(VM& vm, JSWebAssemblyMemory* value) { ASSERT(!memory()); m_memory.set(vm, this, value); }
-    Wasm::MemoryMode memoryMode() { return memory()->memory().mode(); }
-
     JSWebAssemblyTable* table() { return m_table.get(); }
-
-    int32_t loadI32Global(unsigned i) const { return m_globals.get()[i]; }
-    int64_t loadI64Global(unsigned i) const { return m_globals.get()[i]; }
-    float loadF32Global(unsigned i) const { return bitwise_cast<float>(loadI32Global(i)); }
-    double loadF64Global(unsigned i) const { return bitwise_cast<double>(loadI64Global(i)); }
-    void setGlobal(unsigned i, int64_t bits) { m_globals.get()[i] = bits; }
-
-    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_memory); }
-    static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
-    static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_callee); }
-    static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
-    static ptrdiff_t offsetOfVM() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_vm); }
-    static ptrdiff_t offsetOfCodeBlock() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_codeBlock); }
-    static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_cachedStackLimit); }
-    static size_t offsetOfImportFunctions() { return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSCell>)>(sizeof(JSWebAssemblyInstance)); }
-    static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfImportFunctions() + importFunctionNum * sizeof(sizeof(WriteBarrier<JSCell>)); }
-
     WebAssemblyToJSCallee* webAssemblyToJSCallee() { return m_callee.get(); }
 
-    void* cachedStackLimit() const { return m_cachedStackLimit; }
-    void setCachedStackLimit(void* limit) { m_cachedStackLimit = limit; }
+    JSWebAssemblyMemory* memory() { return m_memory.get(); }
+    void setMemory(VM& vm, JSWebAssemblyMemory* value) { ASSERT(!memory()); m_memory.set(vm, this, value); m_wasmMemory = &memory()->memory(); }
+    Wasm::MemoryMode memoryMode() { return memory()->memory().mode(); }
+
+    // Tail accessors.
+    static size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(JSWebAssemblyInstance)); }
+    struct ImportFunctionInfo {
+        // Target instance and entrypoint are only set for wasm->wasm calls, and are otherwise nullptr. The embedder-specific logic occurs through import function.
+        JSWebAssemblyInstance* targetInstance { nullptr };
+        Wasm::WasmEntrypointLoadLocation wasmEntrypoint { nullptr };
+        void* wasmToEmbedderStubExecutableAddress { nullptr };
+        WriteBarrier<JSObject> importFunction { WriteBarrier<JSObject>() };
+    };
+    ImportFunctionInfo* importFunctionInfo(size_t importFunctionNum)
+    {
+        RELEASE_ASSERT(importFunctionNum < m_numImportFunctions);
+        return &bitwise_cast<ImportFunctionInfo*>(bitwise_cast<char*>(this) + offsetOfTail())[importFunctionNum];
+    }
+    static size_t offsetOfTargetInstance(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, targetInstance); }
+    static size_t offsetOfWasmEntrypoint(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, wasmEntrypoint); }
+    static size_t offsetOfWasmToEmbedderStubExecutableAddress(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, wasmToEmbedderStubExecutableAddress); }
+    static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, importFunction); }
+    JSObject* importFunction(unsigned importFunctionNum) { return importFunctionInfo(importFunctionNum)->importFunction.get(); }
+
+    // FIXME remove these after refactoring them out. https://webkit.org/b/177472
+    Wasm::Memory& internalMemory() { return memory()->memory(); }
+    Wasm::CodeBlock& wasmCodeBlock() const { return *m_instance->codeBlock(); }
+    static ptrdiff_t offsetOfWasmTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_wasmTable); }
+    static ptrdiff_t offsetOfCallee() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_callee); }
+    static ptrdiff_t offsetOfVM() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_vm); }
+    static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_globals); }
+    static ptrdiff_t offsetOfCodeBlock() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_codeBlock); }
+    static ptrdiff_t offsetOfWasmCodeBlock() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_wasmCodeBlock); }
+    static ptrdiff_t offsetOfCachedStackLimit() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_cachedStackLimit); }
+    static ptrdiff_t offsetOfWasmMemory() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_wasmMemory); }
+    void* cachedStackLimit() const { RELEASE_ASSERT(m_instance->cachedStackLimit() == m_cachedStackLimit); return m_cachedStackLimit; }
+    void setCachedStackLimit(void* limit) { m_instance->setCachedStackLimit(limit); m_cachedStackLimit = limit; }
+    Wasm::Memory* wasmMemory() { return m_wasmMemory; }
+    Wasm::Module& wasmModule() { return m_wasmModule; }
 
 protected:
-    JSWebAssemblyInstance(VM&, Structure*, unsigned numImportFunctions);
+    JSWebAssemblyInstance(VM&, Structure*, unsigned numImportFunctions, Ref<Wasm::Instance>&&);
     void finishCreation(VM&, JSWebAssemblyModule*, JSModuleNamespaceObject*);
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
     static size_t allocationSize(Checked<size_t> numImportFunctions)
     {
-        return (offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * numImportFunctions).unsafeGet();
+        return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions).unsafeGet();
     }
 
 private:
-    VM* m_vm;
-    WriteBarrier<JSObject>* importFunctions() { return bitwise_cast<WriteBarrier<JSObject>*>(bitwise_cast<char*>(this) + offsetOfImportFunctions()); }
-    size_t globalMemoryByteSize() const;
+    JSWebAssemblyModule* module() const { return m_module.get(); }
 
+    Ref<Wasm::Instance> m_instance;
+
+    VM* m_vm;
     WriteBarrier<JSWebAssemblyModule> m_module;
     WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
     WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
     WriteBarrier<JSWebAssemblyMemory> m_memory;
     WriteBarrier<JSWebAssemblyTable> m_table;
     WriteBarrier<WebAssemblyToJSCallee> m_callee;
-    MallocPtr<uint64_t> m_globals;
+    
+    // FIXME remove these after refactoring them out. https://webkit.org/b/177472
     void* m_cachedStackLimit { bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()) };
+    Wasm::CodeBlock* m_wasmCodeBlock { nullptr };
+    Wasm::Module& m_wasmModule;
+    Wasm::Memory* m_wasmMemory { nullptr };
+    Wasm::Table* m_wasmTable { nullptr };
+    uint64_t* m_globals { nullptr };
+
     unsigned m_numImportFunctions;
 };
 
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp
index 223c58b..d640a46 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp
@@ -37,7 +37,7 @@
 
 const ClassInfo JSWebAssemblyMemory::s_info = { "WebAssembly.Memory", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyMemory) };
 
-JSWebAssemblyMemory* JSWebAssemblyMemory::create(ExecState* exec, VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
+JSWebAssemblyMemory* JSWebAssemblyMemory::create(ExecState* exec, VM& vm, Structure* structure)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
     auto* globalObject = exec->lexicalGlobalObject();
@@ -50,10 +50,16 @@
     if (!globalObject->webAssemblyEnabled())
         return exception(createEvalError(exec, globalObject->webAssemblyDisabledErrorMessage()));
 
-    auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, WTFMove(memory));
-    instance->m_memory->check();
-    instance->finishCreation(vm);
-    return instance;
+    auto* memory = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure);
+    memory->finishCreation(vm);
+    return memory;
+}
+    
+void JSWebAssemblyMemory::adopt(Ref<Wasm::Memory>&& memory)
+{
+    m_memory.swap(memory);
+    ASSERT(m_memory->refCount() == 1);
+    m_memory->check();
 }
 
 Structure* JSWebAssemblyMemory::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
@@ -61,13 +67,10 @@
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 }
 
-JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
+JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure)
     : Base(vm, structure)
-    , m_memory(WTFMove(memory))
+    , m_memory(Wasm::Memory::create().releaseNonNull())
 {
-    ASSERT(m_memory->refCount() == 1);
-    m_memoryBase = m_memory->memory();
-    m_memorySize = m_memory->size();
 }
 
 JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
@@ -85,52 +88,45 @@
     return m_bufferWrapper.get();
 }
 
-Wasm::PageCount JSWebAssemblyMemory::grow(VM& vm, ExecState* exec, uint32_t delta, bool shouldThrowExceptionsOnFailure)
+Wasm::PageCount JSWebAssemblyMemory::grow(VM& vm, ExecState* exec, uint32_t delta)
 {
-    // Note: We can only use exec if shouldThrowExceptionsOnFailure is true.
     auto throwScope = DECLARE_THROW_SCOPE(vm);
 
-    Wasm::PageCount oldPageCount = memory().sizeInPages();
-
-    if (!Wasm::PageCount::isValid(delta)) {
-        if (shouldThrowExceptionsOnFailure)
+    auto grown = memory().grow(Wasm::PageCount(delta));
+    if (!grown) {
+        switch (grown.error()) {
+        case Wasm::Memory::GrowFailReason::InvalidDelta:
             throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the delta to be a valid page count")));
-        return Wasm::PageCount();
-    }
-
-    Wasm::PageCount newSize = oldPageCount + Wasm::PageCount(delta);
-    if (!newSize) {
-        if (shouldThrowExceptionsOnFailure)
+            break;
+        case Wasm::Memory::GrowFailReason::InvalidGrowSize:
             throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow expects the grown size to be a valid page count")));
+            break;
+        case Wasm::Memory::GrowFailReason::WouldExceedMaximum:
+            throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory.grow would exceed the memory's declared maximum size")));
+            break;
+        case Wasm::Memory::GrowFailReason::OutOfMemory:
+            throwException(exec, throwScope, createOutOfMemoryError(exec));
+            break;
+        }
         return Wasm::PageCount();
     }
 
-    if (delta) {
-        bool success = memory().grow(vm, newSize);
-        if (!success) {
-            ASSERT(m_memoryBase == memory().memory());
-            ASSERT(m_memorySize == memory().size());
-            if (shouldThrowExceptionsOnFailure)
-                throwException(exec, throwScope, createOutOfMemoryError(exec));
-            return Wasm::PageCount();
-        }
-        m_memoryBase = memory().memory();
-        m_memorySize = memory().size();
-    }
+    return grown.value();
+}
 
-    // We need to clear out the old array buffer because it might now be pointing
-    // to stale memory.
+void JSWebAssemblyMemory::growSuccessCallback(VM& vm, Wasm::PageCount oldPageCount, Wasm::PageCount newPageCount)
+{
+    // We need to clear out the old array buffer because it might now be pointing to stale memory.
     // Neuter the old array.
     if (m_buffer) {
         m_buffer->neuter(vm);
         m_buffer = nullptr;
         m_bufferWrapper.clear();
     }
-
+    
     memory().check();
-
-    vm.heap.reportExtraMemoryAllocated(Wasm::PageCount(delta).bytes());
-    return oldPageCount;
+    
+    vm.heap.reportExtraMemoryAllocated(newPageCount.bytes() - oldPageCount.bytes());
 }
 
 void JSWebAssemblyMemory::finishCreation(VM& vm)
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h
index 1d06c4c..4bbbccf 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h
@@ -48,26 +48,23 @@
         return &vm.eagerlySweptDestructibleObjectSpace;
     }
 
-    static JSWebAssemblyMemory* create(ExecState*, VM&, Structure*, Ref<Wasm::Memory>&&);
+    static JSWebAssemblyMemory* create(ExecState*, VM&, Structure*);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_EXPORT_INFO;
 
+    void adopt(Ref<Wasm::Memory>&&);
     Wasm::Memory& memory() { return m_memory.get(); }
     JSArrayBuffer* buffer(VM& vm, JSGlobalObject*);
-    Wasm::PageCount grow(VM&, ExecState*, uint32_t delta, bool shouldThrowExceptionsOnFailure);
-
-    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memoryBase); }
-    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memorySize); }
+    Wasm::PageCount grow(VM&, ExecState*, uint32_t delta);
+    void growSuccessCallback(VM&, Wasm::PageCount oldPageCount, Wasm::PageCount newPageCount);
 
 private:
-    JSWebAssemblyMemory(VM&, Structure*, Ref<Wasm::Memory>&&);
+    JSWebAssemblyMemory(VM&, Structure*);
     void finishCreation(VM&);
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    void* m_memoryBase;
-    size_t m_memorySize;
     Ref<Wasm::Memory> m_memory;
     WriteBarrier<JSArrayBuffer> m_bufferWrapper;
     RefPtr<ArrayBuffer> m_buffer;
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp
index bab1181..40c1006 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp
@@ -35,6 +35,7 @@
 #include "WasmCallee.h"
 #include "WasmFormat.h"
 #include "WasmMemory.h"
+#include "WasmModule.h"
 #include "WasmPlan.h"
 #include "WebAssemblyToJSCallee.h"
 #include <wtf/StdLibExtras.h>
@@ -61,6 +62,7 @@
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 }
 
+
 JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, Ref<Wasm::Module>&& module)
     : Base(vm, structure)
     , m_module(WTFMove(module))
@@ -91,6 +93,36 @@
     Wasm::SignatureInformation::tryCleanup();
 }
 
+const Wasm::ModuleInformation& JSWebAssemblyModule::moduleInformation() const
+{
+    return m_module->moduleInformation();
+}
+
+SymbolTable* JSWebAssemblyModule::exportSymbolTable() const
+{
+    return m_exportSymbolTable.get();
+}
+
+Wasm::SignatureIndex JSWebAssemblyModule::signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
+{
+    return m_module->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
+}
+
+WebAssemblyToJSCallee* JSWebAssemblyModule::callee() const
+{
+    return m_callee.get();
+}
+
+JSWebAssemblyCodeBlock* JSWebAssemblyModule::codeBlock(Wasm::MemoryMode mode)
+{
+    return m_codeBlocks[static_cast<size_t>(mode)].get();
+}
+
+Wasm::Module& JSWebAssemblyModule::module()
+{
+    return m_module.get();
+}
+
 void JSWebAssemblyModule::setCodeBlock(VM& vm, Wasm::MemoryMode mode, JSWebAssemblyCodeBlock* codeBlock)
 {
     m_codeBlocks[static_cast<size_t>(mode)].set(vm, this, codeBlock);
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
index 3dc67a3..01b5d07 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h
@@ -30,15 +30,19 @@
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
 #include "UnconditionalFinalizer.h"
-#include "WasmModule.h"
+#include "WasmMemoryMode.h"
 #include <wtf/Bag.h>
+#include <wtf/Expected.h>
 #include <wtf/Forward.h>
+#include <wtf/text/WTFString.h>
 
 namespace JSC {
 
 namespace Wasm {
 class Module;
+struct ModuleInformation;
 class Plan;
+using SignatureIndex = uint32_t;
 }
 
 class SymbolTable;
@@ -52,23 +56,20 @@
 
     DECLARE_EXPORT_INFO;
 
-    JS_EXPORT_PRIVATE static JSWebAssemblyModule* createStub(VM&, ExecState*, Structure*, Wasm::Module::ValidationResult&&);
+    JS_EXPORT_PRIVATE static JSWebAssemblyModule* createStub(VM&, ExecState*, Structure*, WTF::Expected<RefPtr<Wasm::Module>, String>&&);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
-    const Wasm::ModuleInformation& moduleInformation() const { return m_module->moduleInformation(); }
-    SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
-    Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
-    {
-        return m_module->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
-    }
-    WebAssemblyToJSCallee* callee() const { return m_callee.get(); }
+    const Wasm::ModuleInformation& moduleInformation() const;
+    SymbolTable* exportSymbolTable() const;
+    Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const;
+    WebAssemblyToJSCallee* callee() const;
 
-    JSWebAssemblyCodeBlock* codeBlock(Wasm::MemoryMode mode) { return m_codeBlocks[static_cast<size_t>(mode)].get(); }
+    JSWebAssemblyCodeBlock* codeBlock(Wasm::MemoryMode mode);
+    void setCodeBlock(VM&, Wasm::MemoryMode, JSWebAssemblyCodeBlock*);
 
     const Vector<uint8_t>& source() const;
 
-    Wasm::Module& module() { return m_module.get(); }
-    void setCodeBlock(VM&, Wasm::MemoryMode, JSWebAssemblyCodeBlock*);
+    JS_EXPORT_PRIVATE Wasm::Module& module();
 
 private:
     friend class JSWebAssemblyCodeBlock;
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp b/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp
index ff46d4d..aa172c7 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.cpp
@@ -29,30 +29,22 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "JSCInlines.h"
-#include "WasmFormat.h"
-#include <wtf/CheckedArithmetic.h>
 
 namespace JSC {
 
 const ClassInfo JSWebAssemblyTable::s_info = { "WebAssembly.Table", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyTable) };
 
-JSWebAssemblyTable* JSWebAssemblyTable::create(ExecState* exec, VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
+JSWebAssemblyTable* JSWebAssemblyTable::create(ExecState* exec, VM& vm, Structure* structure, Ref<Wasm::Table>&& table)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
     auto* globalObject = exec->lexicalGlobalObject();
 
-    auto exception = [&] (JSObject* error) {
-        throwException(exec, throwScope, error);
+    if (!globalObject->webAssemblyEnabled()) {
+        throwException(exec, throwScope, createEvalError(exec, globalObject->webAssemblyDisabledErrorMessage()));
         return nullptr;
-    };
+    }
 
-    if (!globalObject->webAssemblyEnabled())
-        return exception(createEvalError(exec, globalObject->webAssemblyDisabledErrorMessage()));
-
-    if (!isValidSize(initial))
-        return exception(createOutOfMemoryError(exec));
-
-    auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure, initial, maximum);
+    auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure, WTFMove(table));
     instance->finishCreation(vm);
     return instance;
 }
@@ -62,23 +54,15 @@
     return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
 }
 
-JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
+JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure, Ref<Wasm::Table>&& table)
     : Base(vm, structure)
+    , m_table(WTFMove(table))
 {
-    m_size = initial;
-    ASSERT(isValidSize(m_size));
-    m_maximum = maximum;
-    ASSERT(!m_maximum || *m_maximum >= m_size);
-
     // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
     // But for now, we're not doing that.
-    m_functions = MallocPtr<Wasm::CallableFunction>::malloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(m_size));
-    m_jsFunctions = MallocPtr<WriteBarrier<JSObject>>::malloc(sizeof(WriteBarrier<JSObject>) * static_cast<size_t>(m_size));
-    for (uint32_t i = 0; i < m_size; ++i) {
-        new (&m_functions.get()[i]) Wasm::CallableFunction();
-        ASSERT(m_functions.get()[i].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
-        new (&m_jsFunctions.get()[i]) WriteBarrier<JSObject>();
-    }
+    m_jsFunctions = MallocPtr<WriteBarrier<JSObject>>::malloc(sizeof(WriteBarrier<JSObject>) * static_cast<size_t>(size()));
+    for (uint32_t i = 0; i < size(); ++i)
+        new(&m_jsFunctions.get()[i]) WriteBarrier<JSObject>();
 }
 
 void JSWebAssemblyTable::finishCreation(VM& vm)
@@ -99,7 +83,7 @@
 
     Base::visitChildren(thisObject, visitor);
 
-    for (unsigned i = 0; i < thisObject->m_size; ++i)
+    for (unsigned i = 0; i < thisObject->size(); ++i)
         visitor.append(thisObject->m_jsFunctions.get()[i]);
 }
 
@@ -107,47 +91,44 @@
 {
     if (delta == 0)
         return true;
-    Checked<uint32_t, RecordOverflow> newSizeChecked = m_size;
-    newSizeChecked += delta;
-    uint32_t newSize;
-    if (newSizeChecked.safeGet(newSize) == CheckedState::DidOverflow)
-        return false;
-    if (maximum() && newSize > *maximum())
-        return false;
-    if (!isValidSize(newSize))
+
+    size_t oldSize = size();
+
+    auto grew = m_table->grow(delta);
+    if (!grew)
         return false;
 
-    m_functions.realloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(newSize));
-    m_jsFunctions.realloc(sizeof(WriteBarrier<JSObject>) * static_cast<size_t>(newSize));
+    size_t newSize = grew.value();
+    m_jsFunctions.realloc(sizeof(WriteBarrier<JSObject>) * newSize);
 
-    for (uint32_t i = m_size; i < newSize; ++i) {
-        new (&m_functions.get()[i]) Wasm::CallableFunction();
+    for (size_t i = oldSize; i < newSize; ++i)
         new (&m_jsFunctions.get()[i]) WriteBarrier<JSObject>();
-    }
-    m_size = newSize;
+
     return true;
 }
 
+JSObject* JSWebAssemblyTable::getFunction(uint32_t index)
+{
+    RELEASE_ASSERT(index < size());
+    return m_jsFunctions.get()[index].get();
+}
+
 void JSWebAssemblyTable::clearFunction(uint32_t index)
 {
-    RELEASE_ASSERT(index < m_size);
+    m_table->clearFunction(index);
     m_jsFunctions.get()[index] = WriteBarrier<JSObject>();
-    m_functions.get()[index] = Wasm::CallableFunction();
-    ASSERT(m_functions.get()[index].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
 }
 
 void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyFunction* function)
 {
-    RELEASE_ASSERT(index < m_size);
+    m_table->setFunction(index, function->callableFunction(), function->instance());
     m_jsFunctions.get()[index].set(vm, this, function);
-    m_functions.get()[index] = function->callableFunction();
 }
 
 void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyWrapperFunction* function)
 {
-    RELEASE_ASSERT(index < m_size);
+    m_table->setFunction(index, function->callableFunction(), function->instance());
     m_jsFunctions.get()[index].set(vm, this, function);
-    m_functions.get()[index] = function->callableFunction();
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h b/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h
index df83e97..4487530 100644
--- a/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h
+++ b/Source/JavaScriptCore/wasm/js/JSWebAssemblyTable.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * 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
@@ -29,57 +29,42 @@
 
 #include "JSDestructibleObject.h"
 #include "JSObject.h"
+#include "WasmLimits.h"
+#include "WasmTable.h"
 #include "WebAssemblyWrapperFunction.h"
 #include "WebAssemblyFunction.h"
 #include <wtf/MallocPtr.h>
 
 namespace JSC {
 
-namespace Wasm {
-struct CallableFunction;
-}
-
 class JSWebAssemblyTable : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
 
-    static JSWebAssemblyTable* create(ExecState*, VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
+    static JSWebAssemblyTable* create(ExecState*, VM&, Structure*, Ref<Wasm::Table>&&);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_INFO;
 
-    std::optional<uint32_t> maximum() const { return m_maximum; }
-    uint32_t size() const { return m_size; }
+    static bool isValidSize(uint32_t size) { return Wasm::Table::isValidSize(size); }
+    std::optional<uint32_t> maximum() const { return m_table->maximum(); }
+    uint32_t size() const { return m_table->size(); }
     bool grow(uint32_t delta) WARN_UNUSED_RETURN;
-    JSObject* getFunction(uint32_t index)
-    {
-        RELEASE_ASSERT(index < m_size);
-        return m_jsFunctions.get()[index].get();
-    }
-    void clearFunction(uint32_t index);
-    void setFunction(VM&, uint32_t index, WebAssemblyFunction*);
-    void setFunction(VM&, uint32_t index, WebAssemblyWrapperFunction*);
+    JSObject* getFunction(uint32_t);
+    void clearFunction(uint32_t);
+    void setFunction(VM&, uint32_t, WebAssemblyFunction*);
+    void setFunction(VM&, uint32_t, WebAssemblyWrapperFunction*);
 
-    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_size); }
-    static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_functions); }
-    static ptrdiff_t offsetOfJSFunctions() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_jsFunctions); }
-
-    static bool isValidSize(uint32_t size)
-    {
-        // This tops out at ~384 MB worth of data in this class.
-        return size < (1 << 24);
-    }
+    Wasm::Table* table() { return m_table.ptr(); }
 
 private:
-    JSWebAssemblyTable(VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
+    JSWebAssemblyTable(VM&, Structure*, Ref<Wasm::Table>&&);
     void finishCreation(VM&);
     static void destroy(JSCell*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    MallocPtr<Wasm::CallableFunction> m_functions;
+    Ref<Wasm::Table> m_table;
     MallocPtr<WriteBarrier<JSObject>> m_jsFunctions;
-    std::optional<uint32_t> m_maximum;
-    uint32_t m_size;
 };
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/wasm/js/WasmToJS.cpp b/Source/JavaScriptCore/wasm/js/WasmToJS.cpp
new file mode 100644
index 0000000..071d0d2
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/js/WasmToJS.cpp
@@ -0,0 +1,664 @@
+/*
+ * 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WasmToJS.h"
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "CCallHelpers.h"
+#include "FrameTracers.h"
+#include "JITExceptions.h"
+#include "JSCInlines.h"
+#include "JSWebAssemblyInstance.h"
+#include "JSWebAssemblyRuntimeError.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.loadWasmContextInstance(result);
+    jit.loadPtr(JIT::Address(result, JSWebAssemblyInstance::offsetOfImportFunction(importIndex)), result);
+}
+    
+static Expected<MacroAssemblerCodeRef, BindingFailure> handleBadI64Use(VM* vm, JIT& jit, const Signature& signature, unsigned importIndex)
+{
+    unsigned argCount = signature.argumentCount();
+
+    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.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm->topEntryFrame);
+        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+        jit.loadWasmContextInstance(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* instance) -> void {
+            VM* vm = &exec->vm();
+            NativeCallFrameTracer tracer(vm, exec);
+
+            {
+                auto throwScope = DECLARE_THROW_SCOPE(*vm);
+                JSGlobalObject* globalObject = instance->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));
+    }
+    
+    return MacroAssemblerCodeRef();
+}
+
+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
+
+    auto badI64 = handleBadI64Use(vm, jit, signature, importIndex);
+    if (!badI64 || badI64.value())
+        return badI64;
+
+    // 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.loadWasmContextInstance(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.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm->topEntryFrame);
+        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));
+
+        auto marshallFPR = [&] (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;
+        };
+
+        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);
+                marshallFPR(fprReg);
+                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);
+                }
+                marshallFPR(fprReg);
+                break;
+            }
+            }
+        }
+    }
+
+    jit.loadWasmContextInstance(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.copyCalleeSavesToEntryFrameCalleeSavesBuffer(vm->topEntryFrame);
+        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()));
+}
+
+void* wasmToJSException(ExecState* exec, Wasm::ExceptionType type, JSWebAssemblyInstance* instance)
+{
+    VM* vm = instance->vm();
+    NativeCallFrameTracer tracer(vm, exec);
+
+    {
+        auto throwScope = DECLARE_THROW_SCOPE(*vm);
+        JSGlobalObject* globalObject = instance->globalObject();
+
+        JSObject* error;
+        if (type == ExceptionType::StackOverflow)
+            error = createStackOverflowError(exec, globalObject);
+        else
+            error = JSWebAssemblyRuntimeError::create(exec, *vm, globalObject->WebAssemblyRuntimeErrorStructure(), Wasm::errorMessageForExceptionType(type));
+        throwException(exec, throwScope, error);
+    }
+
+    genericUnwind(vm, exec);
+    ASSERT(!!vm->callFrameForCatch);
+    ASSERT(!!vm->targetMachinePCForThrow);
+    // FIXME: We could make this better:
+    // This is a total hack, but the llint (both op_catch and handleUncaughtException)
+    // require a cell in the callee field to load the VM. (The baseline JIT does not require
+    // this since it is compiled with a constant VM pointer.) We could make the calling convention
+    // for exceptions first load callFrameForCatch info call frame register before jumping
+    // to the exception handler. If we did this, we could remove this terrible hack.
+    // https://bugs.webkit.org/show_bug.cgi?id=170440
+    bitwise_cast<uint64_t*>(exec)[CallFrameSlot::callee] = bitwise_cast<uint64_t>(instance->webAssemblyToJSCallee());
+    return vm->targetMachinePCForThrow;
+}
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/js/WasmToJS.h b/Source/JavaScriptCore/wasm/js/WasmToJS.h
new file mode 100644
index 0000000..fc24aa3
--- /dev/null
+++ b/Source/JavaScriptCore/wasm/js/WasmToJS.h
@@ -0,0 +1,49 @@
+/*
+ * 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 INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "B3Compilation.h"
+#include "WasmBinding.h"
+#include "WasmEmbedder.h"
+#include <wtf/Bag.h>
+#include <wtf/Expected.h>
+
+namespace JSC {
+
+class CallLinkInfo;
+class VM;
+
+namespace Wasm {
+
+Expected<MacroAssemblerCodeRef, BindingFailure> wasmToJS(VM*, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex, unsigned importIndex);
+
+void* wasmToJSException(ExecState*, Wasm::ExceptionType, JSWebAssemblyInstance*);
+
+} } // namespace JSC::Wasm
+
+#endif // ENABLE(WEBASSEMBLY)
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
index 0d27765..c585f09 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
@@ -60,7 +60,7 @@
     const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
 
     // Make sure that the memory we think we are going to run with matches the one we expect.
-    ASSERT(wasmFunction->instance()->codeBlock()->isSafeToRun(wasmFunction->instance()->memory()));
+    ASSERT(wasmFunction->instance()->instance().codeBlock()->isSafeToRun(wasmFunction->instance()->memory()->memory().mode()));
     {
         // Check if we have a disallowed I64 use.
 
@@ -82,11 +82,11 @@
     TraceScope traceScope(WebAssemblyExecuteStart, WebAssemblyExecuteEnd);
 
     Vector<JSValue> boxedArgs;
-    Wasm::Context* wasmContext = wasmFunction->instance();
-    // When we don't use fast TLS to store the context, the js
-    // entry wrapper expects the WasmContext* as the first argument.
-    if (!Wasm::useFastTLSForContext())
-        boxedArgs.append(wasmContext);
+    JSWebAssemblyInstance* instance = wasmFunction->instance();
+    // When we don't use fast TLS to store the context, the JS
+    // entry wrapper expects the instance as the first argument.
+    if (!Wasm::Context::useFastTLS())
+        boxedArgs.append(instance);
 
     for (unsigned argIndex = 0; argIndex < signature.argumentCount(); ++argIndex) {
         JSValue arg = exec->argument(argIndex);
@@ -127,7 +127,7 @@
     protoCallFrame.init(nullptr, wasmFunction, firstArgument, argCount, remainingArgs);
 
     // FIXME Do away with this entire function, and only use the entrypoint generated by B3. https://bugs.webkit.org/show_bug.cgi?id=166486
-    Wasm::Context* prevWasmContext = Wasm::loadContext(vm);
+    JSWebAssemblyInstance* prevInstance = vm.wasmContext.load();
     {
         // We do the stack check here for the wrapper function because we don't
         // want to emit a stack check inside every wrapper function.
@@ -137,22 +137,22 @@
         if (UNLIKELY((sp < stackSpaceUsed) || ((sp - stackSpaceUsed) < bitwise_cast<intptr_t>(vm.softStackLimit()))))
             return JSValue::encode(throwException(exec, scope, createStackOverflowError(exec)));
     }
-    Wasm::storeContext(vm, wasmContext);
+    vm.wasmContext.store(instance, vm.softStackLimit());
     ASSERT(wasmFunction->instance());
-    ASSERT(wasmFunction->instance() == Wasm::loadContext(vm));
+    ASSERT(wasmFunction->instance() == vm.wasmContext.load());
     EncodedJSValue rawResult = vmEntryToWasm(wasmFunction->jsEntrypoint(), &vm, &protoCallFrame);
     // We need to make sure this is in a register or on the stack since it's stored in Vector<JSValue>.
     // This probably isn't strictly necessary, since the WebAssemblyFunction* should keep the instance
     // alive. But it's good hygiene.
-    wasmContext->use();
-    if (prevWasmContext != wasmContext) {
+    instance->use();
+    if (prevInstance != instance) {
         // This is just for some extra safety instead of leaving a cached
         // value in there. If we ever forget to set the value to be a real
         // bounds, this will force every stack overflow check to immediately
         // fire.
-        wasmContext->setCachedStackLimit(bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()));
+        instance->setCachedStackLimit(bitwise_cast<void*>(std::numeric_limits<uintptr_t>::max()));
     }
-    Wasm::storeContext(vm, prevWasmContext);
+    vm.wasmContext.store(prevInstance, vm.softStackLimit());
     RETURN_IF_EXCEPTION(scope, { });
 
     switch (signature.returnType()) {
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp
index a9d8f0d..2fdd5a4 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp
@@ -32,12 +32,14 @@
 #include "JSCInlines.h"
 #include "JSModuleEnvironment.h"
 #include "JSModuleNamespaceObject.h"
+#include "JSToWasm.h"
 #include "JSWebAssemblyHelpers.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyLinkError.h"
 #include "JSWebAssemblyMemory.h"
 #include "JSWebAssemblyModule.h"
 #include "WasmPlan.h"
+#include "WasmToJS.h"
 #include "WasmWorklist.h"
 #include "WebAssemblyFunction.h"
 #include "WebAssemblyInstancePrototype.h"
@@ -75,10 +77,10 @@
     Structure* instanceStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
     RETURN_IF_EXCEPTION(scope, { });
 
-    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, instanceStructure);
+    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, instanceStructure, Wasm::Instance::create(Ref<Wasm::Module>(module->module())));
     RETURN_IF_EXCEPTION(scope, { });
 
-    instance->finalizeCreation(vm, exec, module->module().compileSync(instance->memoryMode()));
+    instance->finalizeCreation(vm, exec, module->module().compileSync(&vm.wasmContext, instance->memoryMode(), &Wasm::createJSToWasmWrapper, &Wasm::wasmToJSException));
     RETURN_IF_EXCEPTION(scope, { });
     return JSValue::encode(instance);
 }
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp
index 64989b5..d0435af 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp
@@ -96,13 +96,18 @@
         }
     }
 
-    RefPtr<Wasm::Memory> memory = Wasm::Memory::create(vm, initialPageCount, maximumPageCount);
+    auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure());
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+
+    RefPtr<Wasm::Memory> memory = Wasm::Memory::create(initialPageCount, maximumPageCount,
+        [&vm] (Wasm::Memory::NotifyPressure) { vm.heap.collectAsync(CollectionScope::Full); },
+        [&vm] (Wasm::Memory::SyncTryToReclaim) { vm.heap.collectSync(CollectionScope::Full); },
+        [&vm, jsMemory] (Wasm::Memory::GrowSuccess, Wasm::PageCount oldPageCount, Wasm::PageCount newPageCount) { jsMemory->growSuccessCallback(vm, oldPageCount, newPageCount); });
     if (!memory)
         return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
 
-    auto* jsMemory = JSWebAssemblyMemory::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*memory.leakRef()));
-    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-
+    jsMemory->adopt(memory.releaseNonNull());
+    
     return JSValue::encode(jsMemory);
 }
 
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryPrototype.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryPrototype.cpp
index e994dc8..4fca8c4 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryPrototype.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryPrototype.cpp
@@ -77,8 +77,7 @@
     uint32_t delta = toNonWrappingUint32(exec, exec->argument(0));
     RETURN_IF_EXCEPTION(throwScope, { });
 
-    bool shouldThrowExceptionsOnFailure = true;
-    Wasm::PageCount result = memory->grow(vm, exec, delta, shouldThrowExceptionsOnFailure);
+    Wasm::PageCount result = memory->grow(vm, exec, delta);
     RETURN_IF_EXCEPTION(throwScope, { });
 
     return JSValue::encode(jsNumber(result.pageCount()));
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp
index 961024d..75b5b62 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp
@@ -161,11 +161,13 @@
 static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyModule(ExecState* exec)
 {
     VM& vm = exec->vm();
-    auto throwScope = DECLARE_THROW_SCOPE(vm);
-    auto* structure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
-    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-    throwScope.release();
-    return JSValue::encode(WebAssemblyModuleConstructor::createModule(exec, exec->argument(0), structure));
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    
+    Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
+    RETURN_IF_EXCEPTION(scope, { });
+
+    scope.release();
+    return JSValue::encode(WebAssemblyModuleConstructor::createModule(exec, WTFMove(source)));
 }
 
 static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyModule(ExecState* exec)
@@ -175,16 +177,16 @@
     return JSValue::encode(throwConstructorCannotBeCalledAsFunctionTypeError(exec, scope, "WebAssembly.Module"));
 }
 
-JSValue WebAssemblyModuleConstructor::createModule(ExecState* exec, JSValue buffer, Structure* structure)
+JSWebAssemblyModule* WebAssemblyModuleConstructor::createModule(ExecState* exec, Vector<uint8_t>&& buffer)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, buffer);
-    RETURN_IF_EXCEPTION(scope, { });
+    auto* structure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), exec->lexicalGlobalObject()->WebAssemblyModuleStructure());
+    RETURN_IF_EXCEPTION(scope, nullptr);
 
     scope.release();
-    return JSWebAssemblyModule::createStub(vm, exec, structure, Wasm::Module::validateSync(vm, WTFMove(source)));
+    return JSWebAssemblyModule::createStub(vm, exec, structure, Wasm::Module::validateSync(&vm.wasmContext, WTFMove(buffer)));
 }
 
 WebAssemblyModuleConstructor* WebAssemblyModuleConstructor::create(VM& vm, Structure* structure, WebAssemblyModulePrototype* thisPrototype)
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.h b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.h
index 6025c98..13aca3f 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.h
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.h
@@ -30,8 +30,11 @@
 #include "InternalFunction.h"
 #include "JSObject.h"
 
+#include <wtf/Vector.h>
+
 namespace JSC {
 
+class JSWebAssemblyModule;
 class WebAssemblyModulePrototype;
 
 class WebAssemblyModuleConstructor : public InternalFunction {
@@ -44,7 +47,7 @@
 
     DECLARE_INFO;
 
-    static JSValue createModule(ExecState*, JSValue buffer, Structure*);
+    static JSWebAssemblyModule* createModule(ExecState*, Vector<uint8_t>&& buffer);
 
 protected:
     void finishCreation(VM&, WebAssemblyModulePrototype*);
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
index cb1fec1..0a866ee 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
@@ -93,7 +93,7 @@
     UNUSED_PARAM(scope);
     auto* globalObject = exec->lexicalGlobalObject();
 
-    JSWebAssemblyCodeBlock* codeBlock = instance->codeBlock();
+    Wasm::CodeBlock* codeBlock = instance->instance().codeBlock();
     const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
 
     SymbolTable* exportSymbolTable = module->exportSymbolTable();
@@ -152,7 +152,7 @@
             // Return ToJSValue(v).
             switch (global.type) {
             case Wasm::I32:
-                exportedValue = JSValue(instance->loadI32Global(exp.kindIndex));
+                exportedValue = JSValue(instance->instance().loadI32Global(exp.kindIndex));
                 break;
 
             case Wasm::I64:
@@ -160,11 +160,11 @@
                 return;
 
             case Wasm::F32:
-                exportedValue = JSValue(instance->loadF32Global(exp.kindIndex));
+                exportedValue = JSValue(instance->instance().loadF32Global(exp.kindIndex));
                 break;
 
             case Wasm::F64:
-                exportedValue = JSValue(instance->loadF64Global(exp.kindIndex));
+                exportedValue = JSValue(instance->instance().loadF64Global(exp.kindIndex));
                 break;
 
             default:
@@ -217,12 +217,12 @@
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    JSWebAssemblyModule* module = m_instance->module();
-    JSWebAssemblyCodeBlock* codeBlock = m_instance->codeBlock();
-    const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
+    Wasm::Module& module = m_instance->instance().module();
+    Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
+    const Wasm::ModuleInformation& moduleInformation = module.moduleInformation();
     JSWebAssemblyTable* table = m_instance->table();
 
-    const Vector<Wasm::Segment::Ptr>& data = m_instance->module()->moduleInformation().data;
+    const Vector<Wasm::Segment::Ptr>& data = moduleInformation.data;
     JSWebAssemblyMemory* jsMemory = m_instance->memory();
 
     std::optional<JSValue> exception;
@@ -239,7 +239,7 @@
                 continue;
 
             uint32_t tableIndex = element.offset.isGlobalImport()
-                ? static_cast<uint32_t>(m_instance->loadI32Global(element.offset.globalImportIndex()))
+                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
                 : element.offset.constValue();
 
             fn(element, tableIndex);
@@ -255,7 +255,7 @@
 
         for (const Wasm::Segment::Ptr& segment : data) {
             uint32_t offset = segment->offset.isGlobalImport()
-                ? static_cast<uint32_t>(m_instance->loadI32Global(segment->offset.globalImportIndex()))
+                ? static_cast<uint32_t>(m_instance->instance().loadI32Global(segment->offset.globalImportIndex()))
                 : segment->offset.constValue();
 
             fn(memory, sizeInBytes, segment, offset);
@@ -293,7 +293,7 @@
             // for the import.
             // https://bugs.webkit.org/show_bug.cgi?id=165510
             uint32_t functionIndex = element.functionIndices[i];
-            Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
+            Wasm::SignatureIndex signatureIndex = module.signatureIndexFromFunctionIndexSpace(functionIndex);
             if (functionIndex < codeBlock->functionImportCount()) {
                 JSObject* functionImport = jsCast<JSObject*>(m_instance->importFunction(functionIndex));
                 if (isWebAssemblyHostFunction(vm, functionImport)) {
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
index e9a634a..1fb943c 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
@@ -33,6 +33,7 @@
 #include "FunctionPrototype.h"
 #include "JSCInlines.h"
 #include "JSPromiseDeferred.h"
+#include "JSToWasm.h"
 #include "JSWebAssemblyHelpers.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyModule.h"
@@ -40,6 +41,7 @@
 #include "PromiseDeferredTimer.h"
 #include "StrongInlines.h"
 #include "WasmBBQPlan.h"
+#include "WasmToJS.h"
 #include "WasmWorklist.h"
 #include "WebAssemblyInstanceConstructor.h"
 #include "WebAssemblyModuleConstructor.h"
@@ -94,7 +96,7 @@
     if (UNLIKELY(scope.exception()))
         reject(exec, scope, promise);
     else {
-        Wasm::Module::validateAsync(vm, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject] (VM& vm, Wasm::Module::ValidationResult&& result) mutable {
+        Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable {
             vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, globalObject, result = WTFMove(result), &vm] () mutable {
                 auto scope = DECLARE_CATCH_SCOPE(vm);
                 ExecState* exec = globalObject->globalExec();
@@ -135,7 +137,7 @@
 {
     auto scope = DECLARE_CATCH_SCOPE(vm);
     // In order to avoid potentially recompiling a module. We first gather all the import/memory information prior to compiling code.
-    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
+    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure(), Wasm::Instance::create(Ref<Wasm::Module>(module->module())));
     RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise));
 
     Vector<Strong<JSCell>> dependencies;
@@ -143,13 +145,13 @@
     dependencies.append(Strong<JSCell>(vm, instance));
     vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
     // Note: This completion task may or may not get called immediately.
-    module->module().compileAsync(vm, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, resolveKind] (VM& vm, Ref<Wasm::CodeBlock>&& refCodeBlock) mutable {
+    module->module().compileAsync(&vm.wasmContext, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, resolveKind, &vm] (Ref<Wasm::CodeBlock>&& refCodeBlock) mutable {
         RefPtr<Wasm::CodeBlock> codeBlock = WTFMove(refCodeBlock);
         vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, instance, module, resolveKind, &vm, codeBlock = WTFMove(codeBlock)] () mutable {
             ExecState* exec = instance->globalObject()->globalExec();
             resolve(vm, exec, promise, instance, module, codeBlock.releaseNonNull(), resolveKind);
         });
-    }));
+    }), &Wasm::createJSToWasmWrapper, &Wasm::wasmToJSException);
 }
 
 static void compileAndInstantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSValue buffer, JSObject* importObject)
@@ -165,7 +167,7 @@
     Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, buffer);
     RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise));
 
-    Wasm::Module::validateAsync(vm, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, globalObject] (VM& vm, Wasm::Module::ValidationResult&& result) mutable {
+    Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable {
         vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, importObject, globalObject, result = WTFMove(result), &vm] () mutable {
             auto scope = DECLARE_CATCH_SCOPE(vm);
             ExecState* exec = globalObject->globalExec();
@@ -213,7 +215,7 @@
     size_t byteSize;
     uint8_t* base = getWasmBufferFromValue(exec, exec->argument(0), byteOffset, byteSize);
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    BBQPlan plan(&vm, base + byteOffset, byteSize, BBQPlan::Validation, Plan::dontFinalize());
+    BBQPlan plan(&vm.wasmContext, base + byteOffset, byteSize, 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()));
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp
index 11865f5..2c5bc70 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyTableConstructor.cpp
@@ -90,8 +90,15 @@
         }
     }
 
+    RefPtr<Wasm::Table> wasmTable = Wasm::Table::create(initial, maximum);
+    if (!wasmTable) {
+        return JSValue::encode(throwException(exec, throwScope,
+            createRangeError(exec, ASCIILiteral("couldn't create Table"))));
+    }
+
     throwScope.release();
-    return JSValue::encode(JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), initial, maximum));
+
+    return JSValue::encode(JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), wasmTable.releaseNonNull()));
 }
 
 static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyTable(ExecState* exec)
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyWrapperFunction.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyWrapperFunction.cpp
index f5f8f9c..36a0dca 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyWrapperFunction.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyWrapperFunction.cpp
@@ -63,7 +63,7 @@
     ASSERT_WITH_MESSAGE(!function->inherits(vm, WebAssemblyWrapperFunction::info()), "We should never double wrap a wrapper function.");
     String name = "";
     NativeExecutable* executable = vm.getHostFunction(callWebAssemblyWrapperFunction, NoIntrinsic, callHostFunctionAsConstructor, nullptr, name);
-    WebAssemblyWrapperFunction* result = new (NotNull, allocateCell<WebAssemblyWrapperFunction>(vm.heap)) WebAssemblyWrapperFunction(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), { signatureIndex, instance->codeBlock()->wasmToJsCallStubForImport(importIndex) });
+    WebAssemblyWrapperFunction* result = new (NotNull, allocateCell<WebAssemblyWrapperFunction>(vm.heap)) WebAssemblyWrapperFunction(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), Wasm::CallableFunction { signatureIndex, &instance->importFunctionInfo(importIndex)->wasmToEmbedderStubExecutableAddress } );
     const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
     result->finishCreation(vm, executable, signature.argumentCount(), name, function, instance);
     return result;