Changeset 213386 in webkit


Ignore:
Timestamp:
Mar 3, 2017 2:24:21 PM (7 years ago)
Author:
keith_miller@apple.com
Message:

WASM should support faster loads.
https://bugs.webkit.org/show_bug.cgi?id=162693

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch adds support for WebAssembly using a 32-bit address
space for memory (along with some extra space for offset
overflow). With a 32-bit address space (we call them
Signaling/fast memories), we reserve the virtual address space for
232 + offset bytes of memory and only mark the usable section as
read/write. If wasm code would read/write out of bounds we use a
custom signal handler to catch the SIGBUS. The signal handler then
checks if the faulting instruction is wasm code and tells the
thread to resume executing from the wasm exception
handler. Otherwise, the signal handler crashes the process, as
usual.

All of the allocations of these memories are managed by the
Wasm::Memory class. In order to avoid TLB churn in the OS we cache
old Signaling memories that are no longer in use. Since getting
the wrong memory can cause recompiles, we try to reserve a memory
for modules that do not import a memory. If a module does import a
memory, we try to guess the type of memory we are going to get
based on the last one allocated.

This patch also changes how the wasm JS-api manages objects. Since
we can compile different versions of code, this patch adds a new
JSWebAssemblyCodeBlock class that holds all the information
specific to running a module in a particular bounds checking
mode. Additionally, the Wasm::Memory object is now a reference
counted class that is shared between the JSWebAssemblyMemory
object and the ArrayBuffer that also views it.

(JSC::JITThunks::existingCTIStub):

  • jit/JITThunks.h:
  • jsc.cpp:

(jscmain):

  • runtime/Options.h:
  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:
  • wasm/JSWebAssemblyCodeBlock.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.

(JSC::JSWebAssemblyCodeBlock::create):
(JSC::JSWebAssemblyCodeBlock::createStructure):
(JSC::JSWebAssemblyCodeBlock::functionImportCount):
(JSC::JSWebAssemblyCodeBlock::mode):
(JSC::JSWebAssemblyCodeBlock::module):
(JSC::JSWebAssemblyCodeBlock::jsEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyCodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
(JSC::JSWebAssemblyCodeBlock::setJSEntrypointCallee):
(JSC::JSWebAssemblyCodeBlock::setWasmEntrypointCallee):
(JSC::JSWebAssemblyCodeBlock::callees):
(JSC::JSWebAssemblyCodeBlock::offsetOfCallees):
(JSC::JSWebAssemblyCodeBlock::allocationSize):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::B3IRGenerator::B3IRGenerator):
(JSC::Wasm::getMemoryBaseAndSize):
(JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
(JSC::Wasm::B3IRGenerator::emitLoadOp):
(JSC::Wasm::B3IRGenerator::emitStoreOp):

  • wasm/WasmCallingConvention.h:
  • wasm/WasmFaultSignalHandler.cpp: Added.

(JSC::Wasm::trapHandler):
(JSC::Wasm::registerCode):
(JSC::Wasm::unregisterCode):
(JSC::Wasm::fastMemoryEnabled):
(JSC::Wasm::enableFastMemory):

  • wasm/WasmFaultSignalHandler.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp.
  • wasm/WasmFormat.h:

(JSC::Wasm::ModuleInformation::importFunctionCount):
(JSC::Wasm::ModuleInformation::hasMemory): Deleted.

  • wasm/WasmMemory.cpp:

(JSC::Wasm::mmapBytes):
(JSC::Wasm::Memory::lastAllocatedMode):
(JSC::Wasm::availableFastMemories):
(JSC::Wasm::tryGetFastMemory):
(JSC::Wasm::releaseFastMemory):
(JSC::Wasm::Memory::Memory):
(JSC::Wasm::Memory::createImpl):
(JSC::Wasm::Memory::create):
(JSC::Wasm::Memory::~Memory):
(JSC::Wasm::Memory::grow):
(JSC::Wasm::Memory::dump):
(JSC::Wasm::Memory::makeString):

  • wasm/WasmMemory.h:

(JSC::Wasm::Memory::operator bool):
(JSC::Wasm::Memory::size):
(JSC::Wasm::Memory::check):
(JSC::Wasm::Memory::Memory): Deleted.
(JSC::Wasm::Memory::offsetOfMemory): Deleted.
(JSC::Wasm::Memory::offsetOfSize): Deleted.

  • wasm/WasmMemoryInformation.cpp:

(JSC::Wasm::MemoryInformation::MemoryInformation):

  • wasm/WasmMemoryInformation.h:

(JSC::Wasm::MemoryInformation::hasReservedMemory):
(JSC::Wasm::MemoryInformation::takeReservedMemory):
(JSC::Wasm::MemoryInformation::mode):

  • wasm/WasmModuleParser.cpp:
  • wasm/WasmModuleParser.h:

(JSC::Wasm::ModuleParser::ModuleParser):

  • wasm/WasmPlan.cpp:

(JSC::Wasm::Plan::parseAndValidateModule):
(JSC::Wasm::Plan::run):

  • wasm/WasmPlan.h:

(JSC::Wasm::Plan::mode):

  • wasm/js/JSWebAssemblyCallee.cpp:

(JSC::JSWebAssemblyCallee::finishCreation):
(JSC::JSWebAssemblyCallee::destroy):

  • wasm/js/JSWebAssemblyCodeBlock.cpp: Added.

(JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
(JSC::JSWebAssemblyCodeBlock::destroy):
(JSC::JSWebAssemblyCodeBlock::isSafeToRun):
(JSC::JSWebAssemblyCodeBlock::visitChildren):
(JSC::JSWebAssemblyCodeBlock::UnconditionalFinalizer::finalizeUnconditionally):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::setMemory):
(JSC::JSWebAssemblyInstance::finishCreation):
(JSC::JSWebAssemblyInstance::visitChildren):

  • wasm/js/JSWebAssemblyInstance.h:

(JSC::JSWebAssemblyInstance::module):
(JSC::JSWebAssemblyInstance::codeBlock):
(JSC::JSWebAssemblyInstance::memoryMode):
(JSC::JSWebAssemblyInstance::setMemory): Deleted.

  • wasm/js/JSWebAssemblyMemory.cpp:

(JSC::JSWebAssemblyMemory::create):
(JSC::JSWebAssemblyMemory::JSWebAssemblyMemory):
(JSC::JSWebAssemblyMemory::buffer):
(JSC::JSWebAssemblyMemory::grow):
(JSC::JSWebAssemblyMemory::destroy):

  • wasm/js/JSWebAssemblyMemory.h:

(JSC::JSWebAssemblyMemory::memory):
(JSC::JSWebAssemblyMemory::offsetOfMemory):
(JSC::JSWebAssemblyMemory::offsetOfSize):

  • wasm/js/JSWebAssemblyModule.cpp:

(JSC::JSWebAssemblyModule::buildCodeBlock):
(JSC::JSWebAssemblyModule::create):
(JSC::JSWebAssemblyModule::JSWebAssemblyModule):
(JSC::JSWebAssemblyModule::codeBlock):
(JSC::JSWebAssemblyModule::finishCreation):
(JSC::JSWebAssemblyModule::visitChildren):
(JSC::JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally): Deleted.

  • wasm/js/JSWebAssemblyModule.h:

(JSC::JSWebAssemblyModule::takeReservedMemory):
(JSC::JSWebAssemblyModule::signatureIndexFromFunctionIndexSpace):
(JSC::JSWebAssemblyModule::codeBlock):
(JSC::JSWebAssemblyModule::functionImportCount): Deleted.
(JSC::JSWebAssemblyModule::jsEntrypointCalleeFromFunctionIndexSpace): Deleted.
(JSC::JSWebAssemblyModule::wasmEntrypointCalleeFromFunctionIndexSpace): Deleted.
(JSC::JSWebAssemblyModule::setJSEntrypointCallee): Deleted.
(JSC::JSWebAssemblyModule::setWasmEntrypointCallee): Deleted.
(JSC::JSWebAssemblyModule::callees): Deleted.
(JSC::JSWebAssemblyModule::offsetOfCallees): Deleted.
(JSC::JSWebAssemblyModule::allocationSize): Deleted.

  • wasm/js/WebAssemblyFunction.cpp:

(JSC::callWebAssemblyFunction):

  • wasm/js/WebAssemblyInstanceConstructor.cpp:

(JSC::constructJSWebAssemblyInstance):

  • wasm/js/WebAssemblyMemoryConstructor.cpp:

(JSC::constructJSWebAssemblyMemory):

  • wasm/js/WebAssemblyModuleConstructor.cpp:

(JSC::WebAssemblyModuleConstructor::createModule):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):

Source/WTF:

Add new forms of dataLog that take a boolean which describes if the log should happen. This makes cases where we have a static const bool for printing nicer since you can do:

dataLogIf(verbose, things, to, print);

instead of:

if (verbose)

dataLog(things, to, print);

Also, add a operator! to Ref that has the same semantics as C++ refs.

  • wtf/DataLog.h:

(WTF::dataLogLn):
(WTF::dataLogIf):
(WTF::dataLogLnIf):

  • wtf/Ref.h:

(WTF::Ref::operator!):

Location:
trunk/Source
Files:
2 added
34 edited
2 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r213381 r213386  
     12017-03-03  Keith Miller  <keith_miller@apple.com>
     2
     3        WASM should support faster loads.
     4        https://bugs.webkit.org/show_bug.cgi?id=162693
     5
     6        Reviewed by Saam Barati.
     7
     8        This patch adds support for WebAssembly using a 32-bit address
     9        space for memory (along with some extra space for offset
     10        overflow). With a 32-bit address space (we call them
     11        Signaling/fast memories), we reserve the virtual address space for
     12        2^32 + offset bytes of memory and only mark the usable section as
     13        read/write. If wasm code would read/write out of bounds we use a
     14        custom signal handler to catch the SIGBUS. The signal handler then
     15        checks if the faulting instruction is wasm code and tells the
     16        thread to resume executing from the wasm exception
     17        handler. Otherwise, the signal handler crashes the process, as
     18        usual.
     19
     20        All of the allocations of these memories are managed by the
     21        Wasm::Memory class. In order to avoid TLB churn in the OS we cache
     22        old Signaling memories that are no longer in use. Since getting
     23        the wrong memory can cause recompiles, we try to reserve a memory
     24        for modules that do not import a memory. If a module does import a
     25        memory, we try to guess the type of memory we are going to get
     26        based on the last one allocated.
     27
     28        This patch also changes how the wasm JS-api manages objects. Since
     29        we can compile different versions of code, this patch adds a new
     30        JSWebAssemblyCodeBlock class that holds all the information
     31        specific to running a module in a particular bounds checking
     32        mode. Additionally, the Wasm::Memory object is now a reference
     33        counted class that is shared between the JSWebAssemblyMemory
     34        object and the ArrayBuffer that also views it.
     35
     36        * JavaScriptCore.xcodeproj/project.pbxproj:
     37        * jit/JITThunks.cpp:
     38        (JSC::JITThunks::existingCTIStub):
     39        * jit/JITThunks.h:
     40        * jsc.cpp:
     41        (jscmain):
     42        * runtime/Options.h:
     43        * runtime/VM.cpp:
     44        (JSC::VM::VM):
     45        * runtime/VM.h:
     46        * wasm/JSWebAssemblyCodeBlock.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h.
     47        (JSC::JSWebAssemblyCodeBlock::create):
     48        (JSC::JSWebAssemblyCodeBlock::createStructure):
     49        (JSC::JSWebAssemblyCodeBlock::functionImportCount):
     50        (JSC::JSWebAssemblyCodeBlock::mode):
     51        (JSC::JSWebAssemblyCodeBlock::module):
     52        (JSC::JSWebAssemblyCodeBlock::jsEntrypointCalleeFromFunctionIndexSpace):
     53        (JSC::JSWebAssemblyCodeBlock::wasmEntrypointCalleeFromFunctionIndexSpace):
     54        (JSC::JSWebAssemblyCodeBlock::setJSEntrypointCallee):
     55        (JSC::JSWebAssemblyCodeBlock::setWasmEntrypointCallee):
     56        (JSC::JSWebAssemblyCodeBlock::callees):
     57        (JSC::JSWebAssemblyCodeBlock::offsetOfCallees):
     58        (JSC::JSWebAssemblyCodeBlock::allocationSize):
     59        * wasm/WasmB3IRGenerator.cpp:
     60        (JSC::Wasm::B3IRGenerator::B3IRGenerator):
     61        (JSC::Wasm::getMemoryBaseAndSize):
     62        (JSC::Wasm::B3IRGenerator::emitCheckAndPreparePointer):
     63        (JSC::Wasm::B3IRGenerator::emitLoadOp):
     64        (JSC::Wasm::B3IRGenerator::emitStoreOp):
     65        * wasm/WasmCallingConvention.h:
     66        * wasm/WasmFaultSignalHandler.cpp: Added.
     67        (JSC::Wasm::trapHandler):
     68        (JSC::Wasm::registerCode):
     69        (JSC::Wasm::unregisterCode):
     70        (JSC::Wasm::fastMemoryEnabled):
     71        (JSC::Wasm::enableFastMemory):
     72        * wasm/WasmFaultSignalHandler.h: Copied from Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp.
     73        * wasm/WasmFormat.h:
     74        (JSC::Wasm::ModuleInformation::importFunctionCount):
     75        (JSC::Wasm::ModuleInformation::hasMemory): Deleted.
     76        * wasm/WasmMemory.cpp:
     77        (JSC::Wasm::mmapBytes):
     78        (JSC::Wasm::Memory::lastAllocatedMode):
     79        (JSC::Wasm::availableFastMemories):
     80        (JSC::Wasm::tryGetFastMemory):
     81        (JSC::Wasm::releaseFastMemory):
     82        (JSC::Wasm::Memory::Memory):
     83        (JSC::Wasm::Memory::createImpl):
     84        (JSC::Wasm::Memory::create):
     85        (JSC::Wasm::Memory::~Memory):
     86        (JSC::Wasm::Memory::grow):
     87        (JSC::Wasm::Memory::dump):
     88        (JSC::Wasm::Memory::makeString):
     89        * wasm/WasmMemory.h:
     90        (JSC::Wasm::Memory::operator bool):
     91        (JSC::Wasm::Memory::size):
     92        (JSC::Wasm::Memory::check):
     93        (JSC::Wasm::Memory::Memory): Deleted.
     94        (JSC::Wasm::Memory::offsetOfMemory): Deleted.
     95        (JSC::Wasm::Memory::offsetOfSize): Deleted.
     96        * wasm/WasmMemoryInformation.cpp:
     97        (JSC::Wasm::MemoryInformation::MemoryInformation):
     98        * wasm/WasmMemoryInformation.h:
     99        (JSC::Wasm::MemoryInformation::hasReservedMemory):
     100        (JSC::Wasm::MemoryInformation::takeReservedMemory):
     101        (JSC::Wasm::MemoryInformation::mode):
     102        * wasm/WasmModuleParser.cpp:
     103        * wasm/WasmModuleParser.h:
     104        (JSC::Wasm::ModuleParser::ModuleParser):
     105        * wasm/WasmPlan.cpp:
     106        (JSC::Wasm::Plan::parseAndValidateModule):
     107        (JSC::Wasm::Plan::run):
     108        * wasm/WasmPlan.h:
     109        (JSC::Wasm::Plan::mode):
     110        * wasm/js/JSWebAssemblyCallee.cpp:
     111        (JSC::JSWebAssemblyCallee::finishCreation):
     112        (JSC::JSWebAssemblyCallee::destroy):
     113        * wasm/js/JSWebAssemblyCodeBlock.cpp: Added.
     114        (JSC::JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock):
     115        (JSC::JSWebAssemblyCodeBlock::destroy):
     116        (JSC::JSWebAssemblyCodeBlock::isSafeToRun):
     117        (JSC::JSWebAssemblyCodeBlock::visitChildren):
     118        (JSC::JSWebAssemblyCodeBlock::UnconditionalFinalizer::finalizeUnconditionally):
     119        * wasm/js/JSWebAssemblyInstance.cpp:
     120        (JSC::JSWebAssemblyInstance::setMemory):
     121        (JSC::JSWebAssemblyInstance::finishCreation):
     122        (JSC::JSWebAssemblyInstance::visitChildren):
     123        * wasm/js/JSWebAssemblyInstance.h:
     124        (JSC::JSWebAssemblyInstance::module):
     125        (JSC::JSWebAssemblyInstance::codeBlock):
     126        (JSC::JSWebAssemblyInstance::memoryMode):
     127        (JSC::JSWebAssemblyInstance::setMemory): Deleted.
     128        * wasm/js/JSWebAssemblyMemory.cpp:
     129        (JSC::JSWebAssemblyMemory::create):
     130        (JSC::JSWebAssemblyMemory::JSWebAssemblyMemory):
     131        (JSC::JSWebAssemblyMemory::buffer):
     132        (JSC::JSWebAssemblyMemory::grow):
     133        (JSC::JSWebAssemblyMemory::destroy):
     134        * wasm/js/JSWebAssemblyMemory.h:
     135        (JSC::JSWebAssemblyMemory::memory):
     136        (JSC::JSWebAssemblyMemory::offsetOfMemory):
     137        (JSC::JSWebAssemblyMemory::offsetOfSize):
     138        * wasm/js/JSWebAssemblyModule.cpp:
     139        (JSC::JSWebAssemblyModule::buildCodeBlock):
     140        (JSC::JSWebAssemblyModule::create):
     141        (JSC::JSWebAssemblyModule::JSWebAssemblyModule):
     142        (JSC::JSWebAssemblyModule::codeBlock):
     143        (JSC::JSWebAssemblyModule::finishCreation):
     144        (JSC::JSWebAssemblyModule::visitChildren):
     145        (JSC::JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally): Deleted.
     146        * wasm/js/JSWebAssemblyModule.h:
     147        (JSC::JSWebAssemblyModule::takeReservedMemory):
     148        (JSC::JSWebAssemblyModule::signatureIndexFromFunctionIndexSpace):
     149        (JSC::JSWebAssemblyModule::codeBlock):
     150        (JSC::JSWebAssemblyModule::functionImportCount): Deleted.
     151        (JSC::JSWebAssemblyModule::jsEntrypointCalleeFromFunctionIndexSpace): Deleted.
     152        (JSC::JSWebAssemblyModule::wasmEntrypointCalleeFromFunctionIndexSpace): Deleted.
     153        (JSC::JSWebAssemblyModule::setJSEntrypointCallee): Deleted.
     154        (JSC::JSWebAssemblyModule::setWasmEntrypointCallee): Deleted.
     155        (JSC::JSWebAssemblyModule::callees): Deleted.
     156        (JSC::JSWebAssemblyModule::offsetOfCallees): Deleted.
     157        (JSC::JSWebAssemblyModule::allocationSize): Deleted.
     158        * wasm/js/WebAssemblyFunction.cpp:
     159        (JSC::callWebAssemblyFunction):
     160        * wasm/js/WebAssemblyInstanceConstructor.cpp:
     161        (JSC::constructJSWebAssemblyInstance):
     162        * wasm/js/WebAssemblyMemoryConstructor.cpp:
     163        (JSC::constructJSWebAssemblyMemory):
     164        * wasm/js/WebAssemblyModuleConstructor.cpp:
     165        (JSC::WebAssemblyModuleConstructor::createModule):
     166        * wasm/js/WebAssemblyModuleRecord.cpp:
     167        (JSC::WebAssemblyModuleRecord::link):
     168        (JSC::WebAssemblyModuleRecord::evaluate):
     169
    11702017-03-03  Mark Lam  <mark.lam@apple.com>
    2171
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r213238 r213386  
    13251325                5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
    13261326                5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
     1327                5381B9371E60E9660090F794 /* WasmFaultSignalHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */; };
     1328                5381B9391E60E97D0090F794 /* WasmFaultSignalHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */; };
     1329                5381B9401E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */; };
     1330                5383AA301E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */; };
    13271331                53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
    13281332                539FB8BA1C99DA7C00940FA1 /* JSArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 539FB8B91C99DA7C00940FA1 /* JSArrayInlines.h */; };
     
    37923796                5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
    37933797                5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
     3798                5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmFaultSignalHandler.cpp; sourceTree = "<group>"; };
     3799                5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmFaultSignalHandler.h; sourceTree = "<group>"; };
     3800                5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebAssemblyCodeBlock.h; sourceTree = "<group>"; };
     3801                5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSWebAssemblyCodeBlock.cpp; path = js/JSWebAssemblyCodeBlock.cpp; sourceTree = "<group>"; };
    37943802                53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
    37953803                53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewPrototype.h; sourceTree = "<group>"; };
     
    62286236                                53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */,
    62296237                                ADB6F67C1E15D7500082F384 /* WasmPageCount.cpp */,
     6238                                5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */,
     6239                                5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */,
    62306240                                79B759731DFA4C600052174C /* WasmPageCount.h */,
    62316241                                53F40E8C1D5901F20099A1B6 /* WasmParser.h */,
     
    78227832                                79E423E01DEE65320078D355 /* JSWebAssemblyCallee.cpp */,
    78237833                                79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */,
     7834                                5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */,
     7835                                5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */,
    78247836                                AD2FCBA61DB58DA400B3E736 /* JSWebAssemblyCompileError.cpp */,
    78257837                                AD2FCBA71DB58DA400B3E736 /* JSWebAssemblyCompileError.h */,
     
    79627974                                0FB3878E1BFBC44D00E3AB1E /* AirBlockWorklist.h in Headers */,
    79637975                                0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */,
     7976                                5381B9401E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h in Headers */,
    79647977                                0FEC85741BDACDC70080FF74 /* AirCCallSpecial.h in Headers */,
    79657978                                0FEC85761BDACDC70080FF74 /* AirCode.h in Headers */,
     
    82818294                                0FC3CCFC19ADA410006AC72A /* DFGBlockMap.h in Headers */,
    82828295                                0FC3CCFD19ADA410006AC72A /* DFGBlockMapInlines.h in Headers */,
     8296                                5381B9391E60E97D0090F794 /* WasmFaultSignalHandler.h in Headers */,
    82838297                                0FC3CCFE19ADA410006AC72A /* DFGBlockSet.h in Headers */,
    82848298                                0FBF158D19B7A53100695DD0 /* DFGBlockSetInlines.h in Headers */,
     
    1007810092                                A704D90517A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp in Sources */,
    1007910093                                0F3BD1B71B896A0700598AA6 /* DFGInsertionSet.cpp in Sources */,
     10094                                5381B9371E60E9660090F794 /* WasmFaultSignalHandler.cpp in Sources */,
    1008010095                                0F300B7B18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp in Sources */,
    1008110096                                0F898F311B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp in Sources */,
     
    1048110496                                FEB137571BB11EF900CD5100 /* MacroAssemblerARM64.cpp in Sources */,
    1048210497                                A729009C17976C6000317298 /* MacroAssemblerARMv7.cpp in Sources */,
     10498                                5383AA301E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp in Sources */,
    1048310499                                0F6DB7EC1D617D1100CDBF8E /* MacroAssemblerCodeRef.cpp in Sources */,
    1048410500                                FE68C6381B90DE0B0042BCB3 /* MacroAssemblerPrinter.cpp in Sources */,
  • trunk/Source/JavaScriptCore/jit/JITThunks.cpp

    r212365 r213386  
    8383}
    8484
     85MacroAssemblerCodeRef JITThunks::existingCTIStub(ThunkGenerator generator)
     86{
     87    LockHolder locker(m_lock);
     88    CTIStubMap::iterator entry = m_ctiStubMap.find(generator);
     89    if (entry == m_ctiStubMap.end())
     90        return MacroAssemblerCodeRef();
     91    return entry->value;
     92}
     93
    8594void JITThunks::finalize(Handle<Unknown> handle, void*)
    8695{
  • trunk/Source/JavaScriptCore/jit/JITThunks.h

    r209764 r213386  
    5959
    6060    MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
     61    MacroAssemblerCodeRef existingCTIStub(ThunkGenerator);
    6162
    6263    NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, const String& name);
  • trunk/Source/JavaScriptCore/jsc.cpp

    r213151 r213386  
    7373#include "TestRunnerUtils.h"
    7474#include "TypeProfilerLog.h"
     75#include "WasmFaultSignalHandler.h"
    7576#include "WasmPlan.h"
    7677#include "WasmMemory.h"
     
    37743775    JSC::initializeThreading();
    37753776    startTimeoutThreadIfNeeded();
     3777#if ENABLE(WEBASSEMBLY)
     3778    JSC::Wasm::enableFastMemory();
     3779#endif
    37763780
    37773781    int result;
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r213302 r213386  
    431431    v(bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
    432432    v(bool, simulateWebAssemblyLowMemory, false, Normal, "If true, the Memory object won't mmap the full 'maximum' range and instead will allocate the minimum required amount.") \
     433    v(bool, useWebAssemblyFastMemory, true, Normal, "If true, we will try to use a 32-bit address space with a signal handler to bounds check wasm memory.")
     434
    433435
    434436enum OptionEquivalence {
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r213338 r213386  
    242242    webAssemblyCalleeStructure.set(*this, JSWebAssemblyCallee::createStructure(*this, 0, jsNull()));
    243243    webAssemblyToJSCalleeStructure.set(*this, WebAssemblyToJSCallee::createStructure(*this, 0, jsNull()));
     244    webAssemblyCodeBlockStructure.set(*this, JSWebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
    244245    webAssemblyToJSCallee.set(*this, WebAssemblyToJSCallee::create(*this, webAssemblyToJSCalleeStructure.get()));
    245246#endif
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r213338 r213386  
    335335    Strong<Structure> webAssemblyCalleeStructure;
    336336    Strong<Structure> webAssemblyToJSCalleeStructure;
     337    Strong<Structure> webAssemblyCodeBlockStructure;
    337338    Strong<JSCell> webAssemblyToJSCallee;
    338339#endif
  • trunk/Source/JavaScriptCore/wasm/JSWebAssemblyCodeBlock.h

    r213385 r213386  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "JSDestructibleObject.h"
    31 #include "JSObject.h"
     30#include "JSCell.h"
    3231#include "JSWebAssemblyCallee.h"
    3332#include "UnconditionalFinalizer.h"
     
    3837namespace JSC {
    3938
    40 class SymbolTable;
     39class JSWebAssemblyModule;
     40class JSWebAssemblyMemory;
    4141
    42 class JSWebAssemblyModule : public JSDestructibleObject {
     42class JSWebAssemblyCodeBlock : public JSCell {
    4343public:
    44     typedef JSDestructibleObject Base;
     44    typedef JSCell Base;
     45    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
    4546
    46     static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, SymbolTable*, unsigned);
    47     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
     47    static JSWebAssemblyCodeBlock* create(VM& vm, JSWebAssemblyModule* owner, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& exitStubs, Wasm::Memory::Mode mode, unsigned calleeCount)
     48    {
     49        auto* result = new (NotNull, allocateCell<JSWebAssemblyCodeBlock>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyCodeBlock(vm, owner, std::forward<Bag<CallLinkInfo>>(callLinkInfos), std::forward<Vector<Wasm::WasmExitStubs>>(exitStubs), mode, calleeCount);
     50        result->finishCreation(vm);
     51        return result;
     52    }
    4853
    49     DECLARE_INFO;
     54    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     55    {
     56        return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
     57    }
    5058
    51     const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
    52     SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
    53     Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
    54     {
    55         return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
    56     }
    5759    unsigned functionImportCount() const { return m_wasmExitStubs.size(); }
     60    Wasm::Memory::Mode mode() const { return m_mode; }
     61    JSWebAssemblyModule* module() const { return m_module.get(); }
     62    bool isSafeToRun(JSWebAssemblyMemory*);
    5863
    5964    JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
     
    9095    }
    9196
    92 protected:
    93     JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, unsigned calleeCount);
    94     void finishCreation(VM&, SymbolTable*);
     97private:
     98    JSWebAssemblyCodeBlock(VM&, JSWebAssemblyModule*, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, Wasm::Memory::Mode, unsigned calleeCount);
     99    DECLARE_EXPORT_INFO;
     100    static const bool needsDestruction = true;
    95101    static void destroy(JSCell*);
    96102    static void visitChildren(JSCell*, SlotVisitor&);
    97103
    98 private:
    99104    static size_t offsetOfCallees()
    100105    {
    101         return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSWebAssemblyCallee>)>(sizeof(JSWebAssemblyModule));
     106        return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSWebAssemblyCallee>)>(sizeof(JSWebAssemblyCodeBlock));
    102107    }
    103108
     
    107112    }
    108113
    109     class UnconditionalFinalizer : public JSC::UnconditionalFinalizer { 
     114    class UnconditionalFinalizer : public JSC::UnconditionalFinalizer {
    110115        void finalizeUnconditionally() override;
    111116    };
    112117
     118    WriteBarrier<JSWebAssemblyModule> m_module;
    113119    UnconditionalFinalizer m_unconditionalFinalizer;
    114     std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
    115120    Bag<CallLinkInfo> m_callLinkInfos;
    116     WriteBarrier<SymbolTable> m_exportSymbolTable;
    117121    Vector<Wasm::WasmExitStubs> m_wasmExitStubs;
     122    Wasm::Memory::Mode m_mode;
    118123    unsigned m_calleeCount;
    119124};
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r211195 r213386  
    208208private:
    209209    ExpressionType emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOp);
     210    B3::Kind memoryKind(B3::Opcode memoryOp);
    210211    ExpressionType emitLoadOp(LoadOpType, Origin, ExpressionType pointer, uint32_t offset);
    211212    void emitStoreOp(StoreOpType, Origin, ExpressionType pointer, ExpressionType value, uint32_t offset);
     
    260261        m_proc.pinRegister(regInfo.sizeRegister);
    261262
    262     if (info.hasMemory()) {
     263    if (info.memory) {
    263264        m_proc.setWasmBoundsCheckGenerator([=] (CCallHelpers& jit, GPRReg pinnedGPR, unsigned) {
    264265            AllowMacroScratchRegisterUsage allowScratch(jit);
     
    283284    Value* memoryObject = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), instance, JSWebAssemblyInstance::offsetOfMemory());
    284285
    285     static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory()->memory())) == sizeof(void*), "codegen relies on this size");
    286     static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory()->size())) == sizeof(uint64_t), "codegen relies on this size");
     286    static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory().memory())) == sizeof(void*), "codegen relies on this size");
     287    static_assert(sizeof(decltype(vm.topJSWebAssemblyInstance->memory()->memory().size())) == sizeof(uint64_t), "codegen relies on this size");
    287288    MemoryBaseAndSize result;
    288289    result.base = block->appendNew<MemoryValue>(proc, Load, pointerType(), Origin(), memoryObject, JSWebAssemblyMemory::offsetOfMemory());
     
    455456inline Value* B3IRGenerator::emitCheckAndPreparePointer(ExpressionType pointer, uint32_t offset, uint32_t sizeOfOperation)
    456457{
    457     ASSERT(m_memoryBaseGPR && m_memorySizeGPR);
    458     ASSERT(sizeOfOperation + offset > offset);
    459     m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, Origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1);
     458    ASSERT(m_memoryBaseGPR);
     459    if (m_info.memory.mode() == Memory::Mode::BoundsChecking) {
     460        ASSERT(m_memorySizeGPR);
     461        ASSERT(sizeOfOperation + offset > offset);
     462        m_currentBlock->appendNew<WasmBoundsCheckValue>(m_proc, Origin(), pointer, m_memorySizeGPR, sizeOfOperation + offset - 1);
     463    }
    460464    pointer = m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), pointer);
    461465    return m_currentBlock->appendNew<WasmAddressValue>(m_proc, Origin(), pointer, m_memoryBaseGPR);
     
    487491}
    488492
     493inline B3::Kind B3IRGenerator::memoryKind(B3::Opcode memoryOp)
     494{
     495    if (m_info.memory.mode() == Memory::Signaling)
     496        return trapping(memoryOp);
     497    return memoryOp;
     498}
     499
    489500inline Value* B3IRGenerator::emitLoadOp(LoadOpType op, Origin origin, ExpressionType pointer, uint32_t offset)
    490501{
    491502    switch (op) {
    492503    case LoadOpType::I32Load8S: {
    493         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
     504        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load8S), origin, pointer, offset);
    494505    }
    495506
    496507    case LoadOpType::I64Load8S: {
    497         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8S, origin, pointer, offset);
     508        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load8S), origin, pointer, offset);
    498509        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
    499510    }
    500511
    501512    case LoadOpType::I32Load8U: {
    502         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
     513        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load8Z), origin, pointer, offset);
    503514    }
    504515
    505516    case LoadOpType::I64Load8U: {
    506         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load8Z, origin, pointer, offset);
     517        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load8Z), origin, pointer, offset);
    507518        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
    508519    }
    509520
    510521    case LoadOpType::I32Load16S: {
    511         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     522        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load16S), origin, pointer, offset);
    512523    }
    513524    case LoadOpType::I64Load16S: {
    514         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     525        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load16S), origin, pointer, offset);
    515526        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
    516527    }
    517528
    518529    case LoadOpType::I32Load: {
    519         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer, offset);
     530        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Int32, origin, pointer, offset);
    520531    }
    521532
    522533    case LoadOpType::I64Load32U: {
    523         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer, offset);
     534        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Int32, origin, pointer, offset);
    524535        return m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin, value);
    525536    }
    526537
    527538    case LoadOpType::I64Load32S: {
    528         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin, pointer, offset);
     539        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Int32, origin, pointer, offset);
    529540        return m_currentBlock->appendNew<Value>(m_proc, SExt32, origin, value);
    530541    }
    531542
    532543    case LoadOpType::I64Load: {
    533         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int64, origin, pointer, offset);
     544        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Int64, origin, pointer, offset);
    534545    }
    535546
    536547    case LoadOpType::F32Load: {
    537         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Float, origin, pointer, offset);
     548        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Float, origin, pointer, offset);
    538549    }
    539550
    540551    case LoadOpType::F64Load: {
    541         return m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Double, origin, pointer, offset);
     552        return m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load), Double, origin, pointer, offset);
    542553    }
    543554
     
    545556    // it's added. https://bugs.webkit.org/show_bug.cgi?id=165884
    546557    case LoadOpType::I32Load16U: {
    547         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     558        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load16S), origin, pointer, offset);
    548559        return m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(), value,
    549560                m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), 0x0000ffff));
    550561    }
    551562    case LoadOpType::I64Load16U: {
    552         Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, Load16S, origin, pointer, offset);
     563        Value* value = m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Load16S), origin, pointer, offset);
    553564        Value* partialResult = m_currentBlock->appendNew<Value>(m_proc, BitAnd, Origin(), value,
    554565                m_currentBlock->appendNew<Const32Value>(m_proc, Origin(), 0x0000ffff));
     
    632643
    633644    case StoreOpType::I32Store8:
    634         m_currentBlock->appendNew<MemoryValue>(m_proc, Store8, origin, value, pointer, offset);
     645        m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Store8), origin, value, pointer, offset);
    635646        return;
    636647
     
    640651
    641652    case StoreOpType::I32Store16:
    642         m_currentBlock->appendNew<MemoryValue>(m_proc, Store16, origin, value, pointer, offset);
     653        m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Store16), origin, value, pointer, offset);
    643654        return;
    644655
     
    651662    case StoreOpType::F32Store:
    652663    case StoreOpType::F64Store:
    653         m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin, value, pointer, offset);
     664        m_currentBlock->appendNew<MemoryValue>(m_proc, memoryKind(Store), origin, value, pointer, offset);
    654665        return;
    655666    }
  • trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h

    r210047 r213386  
    4141#include "RegisterSet.h"
    4242#include "WasmFormat.h"
     43#include "WasmSignature.h"
    4344
    4445namespace JSC { namespace Wasm {
  • trunk/Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h

    r213385 r213386  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #include "config.h"
    27 #include "JSWebAssemblyCallee.h"
    28 
    2926#if ENABLE(WEBASSEMBLY)
    30 
    31 #include "JSCInlines.h"
    3227
    3328namespace JSC {
    3429
    35 const ClassInfo JSWebAssemblyCallee::s_info = { "WebAssemblyCallee", nullptr, 0, CREATE_METHOD_TABLE(JSWebAssemblyCallee) };
     30class VM;
    3631
    37 JSWebAssemblyCallee::JSWebAssemblyCallee(VM& vm)
    38     : Base(vm, vm.webAssemblyCalleeStructure.get())
    39 { }
     32namespace Wasm {
    4033
    41 void JSWebAssemblyCallee::finishCreation(VM& vm, Wasm::Entrypoint&& entrypoint)
    42 {
    43     Base::finishCreation(vm);
     34void registerCode(VM&, void* start, void* end);
     35void unregisterCode(VM&, void* start, void* end);
    4436
    45     m_entrypoint = WTFMove(entrypoint);
    46 }
     37bool fastMemoryEnabled();
     38JS_EXPORT_PRIVATE void enableFastMemory();
    4739
    48 void JSWebAssemblyCallee::destroy(JSCell* cell)
    49 {
    50     JSWebAssemblyCallee* thisObject = static_cast<JSWebAssemblyCallee*>(cell);
    51     thisObject->JSWebAssemblyCallee::~JSWebAssemblyCallee();
    52 }
    53 
    54 } // namespace JSC
     40} } // namespace JSC::Wasm
    5541
    5642#endif // ENABLE(WEBASSEMBLY)
  • trunk/Source/JavaScriptCore/wasm/WasmFormat.h

    r210282 r213386  
    257257
    258258    uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); }
    259     bool hasMemory() const { return !!memory; }
    260259
    261260    ~ModuleInformation();
  • trunk/Source/JavaScriptCore/wasm/WasmMemory.cpp

    r210229 r213386  
    2929#if ENABLE(WEBASSEMBLY)
    3030
     31#include "VM.h"
     32#include "WasmFaultSignalHandler.h"
     33
    3134#include <wtf/HexNumber.h>
     35#include <wtf/NeverDestroyed.h>
    3236#include <wtf/PrintStream.h>
    3337#include <wtf/text/WTFString.h>
     
    3943}
    4044
    41 void Memory::dump(PrintStream& out) const
    42 {
    43     String memoryHex;
    44     WTF::appendUnsigned64AsHex((uint64_t)(uintptr_t)m_memory, memoryHex);
    45     out.print("Memory at 0x", memoryHex, ", size ", m_size, "B capacity ", m_mappedCapacity, "B, initial ", m_initial, " maximum ", m_maximum, " mode ", makeString(m_mode));
    46 }
    47 
    48 const char* Memory::makeString(Mode mode) const
    49 {
    50     switch (mode) {
    51     case Mode::BoundsChecking: return "BoundsChecking";
    52     }
    53     RELEASE_ASSERT_NOT_REACHED();
    54     return "";
    55 }
    56 
    57 static_assert(sizeof(uint64_t) == sizeof(size_t), "We rely on allowing the maximum size of Memory we map to be 2^32 which is larger than fits in a 32-bit integer that we'd pass to mprotect if this didn't hold.");
    58 
    59 Memory::Memory(PageCount initial, PageCount maximum, bool& failed)
    60     : m_size(initial.bytes())
     45inline bool mmapBytes(size_t bytes, void*& memory)
     46{
     47    dataLogIf(verbose, "Attempting to mmap ", bytes, " bytes: ");
     48    // FIXME: It would be nice if we had a VM tag for wasm memory. https://bugs.webkit.org/show_bug.cgi?id=163600
     49    void* result = mmap(nullptr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
     50    if (result == MAP_FAILED) {
     51        dataLogLnIf(verbose, "failed");
     52        return false;
     53    }
     54    dataLogLnIf(verbose, "succeeded");
     55    memory = result;
     56    return true;
     57}
     58
     59// We use this as a heuristic to guess what mode a memory import will be. Most of the time we expect users to
     60// allocate the memory they are going to pass to all their modules right before compilation.
     61static Memory::Mode lastAllocatedMemoryMode { Memory::Mode::Signaling };
     62
     63Memory::Mode Memory::lastAllocatedMode()
     64{
     65    return lastAllocatedMemoryMode;
     66}
     67
     68static_assert(sizeof(uint64_t) == sizeof(size_t), "We rely on allowing the maximum size of Memory we map to be 2^33 which is larger than fits in a 32-bit integer that we'd pass to mprotect if this didn't hold.");
     69
     70static const size_t fastMemoryMappedBytes = (static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 1) * 2; // pointer max + offset max. This is all we need since a load straddling readable memory will trap.
     71static const unsigned maxFastMemories = 4;
     72static unsigned allocatedFastMemories { 0 };
     73static StaticLock memoryLock;
     74inline Deque<void*, maxFastMemories>& availableFastMemories(const LockHolder&)
     75{
     76    static NeverDestroyed<Deque<void*, maxFastMemories>> availableFastMemories;
     77    return availableFastMemories;
     78}
     79
     80inline bool tryGetFastMemory(VM& vm, void*& memory, size_t& mappedCapacity, Memory::Mode& mode)
     81{
     82    // We might GC here so we should be holding the API lock.
     83    // FIXME: We should be able to syncronously trigger the GC from another thread.
     84    ASSERT(vm.currentThreadIsHoldingAPILock());
     85    if (!fastMemoryEnabled())
     86        return false;
     87
     88    // We need to be sure we have a stub prior to running code.
     89    if (!vm.getCTIStub(throwExceptionFromWasmThunkGenerator).size())
     90        return false;
     91
     92    auto dequeFastMemory = [&] () -> bool {
     93        // FIXME: We should eventually return these to the OS if we go some number of GCs
     94        // without using them.
     95        LockHolder locker(memoryLock);
     96        if (!availableFastMemories(locker).isEmpty()) {
     97            memory = availableFastMemories(locker).takeFirst();
     98            mappedCapacity = fastMemoryMappedBytes;
     99            mode = Memory::Signaling;
     100            return true;
     101        }
     102        return false;
     103    };
     104
     105    ASSERT(allocatedFastMemories <= maxFastMemories);
     106    if (dequeFastMemory())
     107        return true;
     108
     109    // If we have allocated all the fast memories... too bad.
     110    if (allocatedFastMemories == maxFastMemories) {
     111        // There is a reasonable chance that another module has died but has not been collected yet. Don't lose hope yet!
     112        vm.heap.collectSync();
     113        return dequeFastMemory();
     114    }
     115
     116    if (mmapBytes(fastMemoryMappedBytes, memory)) {
     117        mappedCapacity = fastMemoryMappedBytes;
     118        mode = Memory::Signaling;
     119        allocatedFastMemories++;
     120    }
     121    return memory;
     122}
     123
     124inline void releaseFastMemory(void*& memory, size_t writableSize, size_t mappedCapacity, Memory::Mode mode)
     125{
     126    if (mode != Memory::Signaling || !memory)
     127        return;
     128
     129    RELEASE_ASSERT(memory && mappedCapacity == fastMemoryMappedBytes);
     130    ASSERT(fastMemoryEnabled());
     131
     132    memset(memory, 0, writableSize);
     133    if (mprotect(memory, writableSize, PROT_NONE))
     134        CRASH();
     135
     136    LockHolder locker(memoryLock);
     137    ASSERT(availableFastMemories(locker).size() < allocatedFastMemories);
     138    availableFastMemories(locker).append(memory);
     139    memory = nullptr;
     140}
     141
     142Memory::Memory(PageCount initial, PageCount maximum)
     143    : m_initial(initial)
     144    , m_maximum(maximum)
     145{
     146    ASSERT(!initial.bytes());
     147}
     148
     149Memory::Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, Mode mode)
     150    : m_memory(memory)
     151    , m_size(initial.bytes())
    61152    , m_initial(initial)
    62153    , m_maximum(maximum)
    63     , m_mode(Mode::BoundsChecking)
    64     // FIXME: If we add signal based bounds checking then we need extra space for overflow on load.
    65     // see: https://bugs.webkit.org/show_bug.cgi?id=162693
     154    , m_mappedCapacity(mappedCapacity)
     155    , m_mode(mode)
     156{
     157    dataLogLnIf(verbose, "Memory::Memory allocating ", *this);
     158}
     159
     160RefPtr<Memory> Memory::createImpl(VM& vm, PageCount initial, PageCount maximum, std::optional<Mode> requiredMode)
    66161{
    67162    RELEASE_ASSERT(!maximum || maximum >= initial); // This should be guaranteed by our caller.
    68163
    69     m_mappedCapacity = maximum ? maximum.bytes() : PageCount::max().bytes();
    70     if (!m_mappedCapacity) {
     164    Mode mode = requiredMode ? *requiredMode : BoundsChecking;
     165    const size_t size = initial.bytes();
     166    size_t mappedCapacity = maximum ? maximum.bytes() : PageCount::max().bytes();
     167    void* memory = nullptr;
     168
     169    auto makeEmptyMemory = [&] () -> RefPtr<Memory> {
     170        if (mode == Signaling)
     171            return nullptr;
     172
     173        lastAllocatedMemoryMode = BoundsChecking;
     174        return adoptRef(new Memory(initial, maximum));
     175    };
     176
     177    if (!mappedCapacity) {
    71178        // This means we specified a zero as maximum (which means we also have zero as initial size).
    72         RELEASE_ASSERT(m_size == 0);
    73         m_memory = nullptr;
    74         m_mappedCapacity = 0;
    75         failed = false;
    76         if (verbose)
    77             dataLogLn("Memory::Memory allocating nothing ", *this);
    78         return;
    79     }
    80 
    81     // FIXME: It would be nice if we had a VM tag for wasm memory. https://bugs.webkit.org/show_bug.cgi?id=163600
    82     void* result = Options::simulateWebAssemblyLowMemory() ? MAP_FAILED : mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
    83     if (result == MAP_FAILED) {
    84         // Try again with a different number.
    85         if (verbose)
    86             dataLogLn("Memory::Memory mmap failed once for capacity, trying again", *this);
    87         m_mappedCapacity = m_size;
    88         if (!m_mappedCapacity) {
    89             m_memory = nullptr;
    90             failed = false;
    91             if (verbose)
    92                 dataLogLn("Memory::Memory mmap not trying again because size is zero ", *this);
    93             return;
     179        RELEASE_ASSERT(!size);
     180        dataLogLnIf(verbose, "Memory::create allocating nothing");
     181        return makeEmptyMemory();
     182    }
     183
     184    bool canUseFastMemory = !requiredMode || requiredMode == Signaling;
     185    if (!canUseFastMemory || !tryGetFastMemory(vm, memory, mappedCapacity, mode)) {
     186        if (mode == Signaling)
     187            return nullptr;
     188
     189        if (Options::simulateWebAssemblyLowMemory() ? true : !mmapBytes(mappedCapacity, memory)) {
     190            // Try again with a different number.
     191            dataLogLnIf(verbose, "Memory::create mmap failed once for capacity, trying again");
     192            mappedCapacity = size;
     193            if (!mappedCapacity) {
     194                dataLogLnIf(verbose, "Memory::create mmap not trying again because size is zero");
     195                return makeEmptyMemory();
     196            }
     197
     198            if (!mmapBytes(mappedCapacity, memory)) {
     199                dataLogLnIf(verbose, "Memory::create mmap failed twice");
     200                return nullptr;
     201            }
    94202        }
    95 
    96         result = mmap(nullptr, m_mappedCapacity, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
    97         if (result == MAP_FAILED) {
    98             if (verbose)
    99                 dataLogLn("Memory::Memory mmap failed twice ", *this);
    100             failed = true;
    101             return;
     203    }
     204
     205    ASSERT(memory && size <= mappedCapacity);
     206    if (mprotect(memory, size, PROT_READ | PROT_WRITE)) {
     207        dataLogLnIf(verbose, "Memory::create mprotect failed");
     208        releaseFastMemory(memory, 0, mappedCapacity, mode);
     209        if (memory) {
     210            if (munmap(memory, mappedCapacity))
     211                CRASH();
    102212        }
    103     }
    104 
    105     ASSERT(m_size <= m_mappedCapacity);
    106     {
    107         bool success = !mprotect(result, static_cast<size_t>(m_size), PROT_READ | PROT_WRITE);
    108         RELEASE_ASSERT(success);
    109     }
    110 
    111     m_memory = result;
    112     failed = false;
    113     if (verbose)
    114         dataLogLn("Memory::Memory mmap succeeded ", *this);
     213        return nullptr;
     214    }
     215   
     216    lastAllocatedMemoryMode = mode;
     217    dataLogLnIf(verbose, "Memory::create mmap succeeded");
     218    return adoptRef(new Memory(memory, initial, maximum, mappedCapacity, mode));
     219}
     220
     221RefPtr<Memory> Memory::create(VM& vm, PageCount initial, PageCount maximum, std::optional<Mode> mode)
     222{
     223    RELEASE_ASSERT(!maximum || maximum >= initial); // This should be guaranteed by our caller.
     224    RefPtr<Memory> result = createImpl(vm, initial, maximum, mode);
     225    if (result) {
     226        if (result->mode() == Signaling)
     227            RELEASE_ASSERT(result->m_mappedCapacity == fastMemoryMappedBytes);
     228        if (mode)
     229            ASSERT(*mode == result->mode());
     230        ASSERT(lastAllocatedMemoryMode == result->mode());
     231    }
     232    return result;
    115233}
    116234
    117235Memory::~Memory()
    118236{
    119     if (verbose)
    120         dataLogLn("Memory::~Memory ", *this);
     237    dataLogLnIf(verbose, "Memory::~Memory ", *this);
     238    releaseFastMemory(m_memory, m_size, m_mappedCapacity, m_mode);
    121239    if (m_memory) {
    122240        if (munmap(m_memory, m_mappedCapacity))
     
    129247    RELEASE_ASSERT(newSize > PageCount::fromBytes(m_size));
    130248
    131     if (verbose)
    132         dataLogLn("Memory::grow to ", newSize, " from ", *this);
     249    dataLogLnIf(verbose, "Memory::grow to ", newSize, " from ", *this);
    133250
    134251    if (maximum() && newSize > maximum())
    135252        return false;
    136253
    137     uint64_t desiredSize = newSize.bytes();
     254    size_t desiredSize = newSize.bytes();
    138255
    139256    if (m_memory && desiredSize <= m_mappedCapacity) {
    140         bool success = !mprotect(static_cast<uint8_t*>(m_memory) + m_size, static_cast<size_t>(desiredSize - m_size), PROT_READ | PROT_WRITE);
    141         RELEASE_ASSERT(success);
     257        if (mprotect(static_cast<uint8_t*>(m_memory) + m_size, static_cast<size_t>(desiredSize - m_size), PROT_READ | PROT_WRITE)) {
     258            dataLogLnIf(verbose, "Memory::grow in-place failed ", *this);
     259            return false;
     260        }
     261
    142262        m_size = desiredSize;
    143         if (verbose)
    144             dataLogLn("Memory::grow in-place ", *this);
     263        dataLogLnIf(verbose, "Memory::grow in-place ", *this);
    145264        return true;
    146265    }
    147266
     267    ASSERT(mode() != Signaling);
    148268    // Otherwise, let's try to make some new memory.
    149269    void* newMemory = mmap(nullptr, desiredSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     
    160280    m_size = desiredSize;
    161281
    162     if (verbose)
    163         dataLogLn("Memory::grow ", *this);
     282    dataLogLnIf(verbose, "Memory::grow ", *this);
    164283    return true;
    165284}
    166285
     286void Memory::dump(PrintStream& out) const
     287{
     288    out.print("Memory at ", RawPointer(m_memory), ", size ", m_size, "B capacity ", m_mappedCapacity, "B, initial ", m_initial, " maximum ", m_maximum, " mode ", makeString(m_mode));
     289}
     290
     291const char* Memory::makeString(Mode mode) const
     292{
     293    switch (mode) {
     294    case Mode::BoundsChecking: return "BoundsChecking";
     295    case Mode::Signaling: return "Signaling";
     296    case Mode::NumberOfModes: break;
     297    }
     298    RELEASE_ASSERT_NOT_REACHED();
     299    return "";
     300}
     301
    167302} // namespace JSC
    168303
  • trunk/Source/JavaScriptCore/wasm/WasmMemory.h

    r210229 r213386  
    2828#if ENABLE(WEBASSEMBLY)
    2929
    30 #include "WasmCallingConvention.h"
    3130#include "WasmPageCount.h"
     31
     32#include <wtf/Optional.h>
     33#include <wtf/RefCounted.h>
     34#include <wtf/RefPtr.h>
    3235
    3336namespace WTF {
     
    3538}
    3639
    37 namespace JSC { namespace Wasm {
     40namespace JSC {
    3841
    39 class Memory {
     42class VM;
     43
     44namespace Wasm {
     45
     46class Memory : public RefCounted<Memory> {
    4047    WTF_MAKE_NONCOPYABLE(Memory);
    4148    WTF_MAKE_FAST_ALLOCATED;
     
    4451
    4552    // FIXME: We should support other modes. see: https://bugs.webkit.org/show_bug.cgi?id=162693
    46     enum class Mode {
    47         BoundsChecking
     53    enum Mode {
     54        BoundsChecking,
     55        Signaling,
     56        NumberOfModes
    4857    };
    4958    const char* makeString(Mode) const;
    5059
     60    explicit operator bool() const { return !!m_memory; }
     61
     62    static RefPtr<Memory> create(VM&, PageCount initial, PageCount maximum, std::optional<Mode> requiredMode = std::nullopt);
     63
    5164    Memory() = default;
    52     JS_EXPORT_PRIVATE Memory(PageCount initial, PageCount maximum, bool& failed);
    53     Memory(Memory&& other)
    54         : m_memory(other.m_memory)
    55         , m_size(other.m_size)
    56         , m_initial(other.m_initial)
    57         , m_maximum(other.m_maximum)
    58         , m_mappedCapacity(other.m_mappedCapacity)
    59         , m_mode(other.m_mode)
    60     {
    61         // Moving transfers ownership of the allocated memory.
    62         other.m_memory = nullptr;
    63     }
    6465    ~Memory();
    6566
    6667    void* memory() const { return m_memory; }
    67     uint64_t size() const { return m_size; }
     68    size_t size() const { return m_size; }
    6869    PageCount sizeInPages() const { return PageCount::fromBytes(m_size); }
    6970
     
    7172    PageCount maximum() const { return m_maximum; }
    7273
     74    static Mode lastAllocatedMode();
    7375    Mode mode() const { return m_mode; }
    7476
     77    // grow() should only be called from the JSWebAssemblyMemory object since that object needs to update internal
     78    // pointers with the current base and size.
    7579    bool grow(PageCount);
    7680
    77     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Memory, m_memory); }
    78     static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(Memory, m_size); }
    79    
     81    void check() {  ASSERT(!deletionHasBegun()); }
    8082private:
     83    static RefPtr<Memory> createImpl(VM&, PageCount initial, PageCount maximum, std::optional<Mode> requiredMode = std::nullopt);
     84    Memory(void* memory, PageCount initial, PageCount maximum, size_t mappedCapacity, Mode);
     85    Memory(PageCount initial, PageCount maximum);
     86
     87    // FIXME: we should move these to the instance to avoid a load on instance->instance calls.
    8188    void* m_memory { nullptr };
    82     uint64_t m_size { 0 };
     89    size_t m_size { 0 };
    8390    PageCount m_initial;
    8491    PageCount m_maximum;
    85     uint64_t m_mappedCapacity { 0 };
     92    size_t m_mappedCapacity { 0 };
    8693    Mode m_mode { Mode::BoundsChecking };
    8794};
  • trunk/Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp

    r210229 r213386  
    3030
    3131#include "WasmCallingConvention.h"
     32#include "WasmMemory.h"
    3233#include <wtf/NeverDestroyed.h>
    3334
     
    4950        unsigned remainingPinnedRegisters = pinnedSizes.size() + 1;
    5051        jscCallingConvention().m_calleeSaveRegisters.forEach([&] (Reg reg) {
     52            if (!reg.isGPR())
     53                return;
    5154            GPRReg gpr = reg.gpr();
    5255            if (!remainingPinnedRegisters || RegisterSet::stackRegisters().get(reg))
     
    7275}
    7376
    74 MemoryInformation::MemoryInformation(PageCount initial, PageCount maximum, bool isImport)
     77MemoryInformation::MemoryInformation(VM& vm, PageCount initial, PageCount maximum, std::optional<Memory::Mode> recompileMode, bool isImport)
    7578    : m_initial(initial)
    7679    , m_maximum(maximum)
     
    8083    RELEASE_ASSERT(!m_maximum || m_maximum >= m_initial);
    8184    ASSERT(!!*this);
     85
     86    if (!recompileMode) {
     87        if (!isImport) {
     88            m_reservedMemory = Memory::create(vm, initial, maximum, Memory::Signaling);
     89            if (m_reservedMemory) {
     90                ASSERT(!!*m_reservedMemory);
     91                m_mode = m_reservedMemory->mode();
     92                return;
     93            }
     94        }
     95        m_mode = Memory::lastAllocatedMode();
     96    } else
     97        m_mode = *recompileMode;
    8298}
    8399
  • trunk/Source/JavaScriptCore/wasm/WasmMemoryInformation.h

    r210229 r213386  
    2929
    3030#include "GPRInfo.h"
     31#include "WasmMemory.h"
    3132#include "WasmPageCount.h"
     33#include <wtf/Ref.h>
    3234#include <wtf/Vector.h>
    3335
     
    5355    }
    5456
    55     MemoryInformation(PageCount initial, PageCount maximum, bool isImport);
     57    MemoryInformation(VM&, PageCount initial, PageCount maximum, std::optional<Memory::Mode>, bool isImport);
    5658
    5759    PageCount initial() const { return m_initial; }
    5860    PageCount maximum() const { return m_maximum; }
     61    bool hasReservedMemory() const { return m_reservedMemory; }
     62    RefPtr<Memory> takeReservedMemory() { ASSERT(hasReservedMemory()); return m_reservedMemory.release(); }
     63    Memory::Mode mode() const { return m_mode; }
    5964    bool isImport() const { return m_isImport; }
    6065
     
    6267
    6368private:
     69    RefPtr<Memory> m_reservedMemory;
    6470    PageCount m_initial { };
    6571    PageCount m_maximum { };
     72    Memory::Mode m_mode { Memory::Mode::BoundsChecking };
    6673    bool m_isImport { false };
    6774};
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r212983 r213386  
    317317    ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
    318318
    319     m_result.module->memory = MemoryInformation(initialPageCount, maximumPageCount, isImport);
     319    m_result.module->memory = MemoryInformation(*m_vm, initialPageCount, maximumPageCount, m_mode, isImport);
    320320    return { };
    321321}
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.h

    r210282 r213386  
    3131#include "WasmOps.h"
    3232#include "WasmParser.h"
     33#include <wtf/Optional.h>
    3334#include <wtf/Vector.h>
    3435
     
    4445public:
    4546
    46     ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength)
     47    ModuleParser(VM* vm, const uint8_t* sourceBuffer, size_t sourceLength, std::optional<Memory::Mode> mode)
    4748        : Parser(vm, sourceBuffer, sourceLength)
    48     {
    49     }
    50     ModuleParser(VM* vm, const Vector<uint8_t>& sourceBuffer)
    51         : ModuleParser(vm, sourceBuffer.data(), sourceBuffer.size())
     49        , m_mode(mode)
    5250    {
    5351    }
     
    6967
    7068    ModuleParserResult m_result;
     69    std::optional<Memory::Mode> m_mode { std::nullopt };
    7170    bool m_hasTable { false };
    7271};
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.cpp

    r210229 r213386  
    3636#include "WasmBinding.h"
    3737#include "WasmCallingConvention.h"
     38#include "WasmFaultSignalHandler.h"
    3839#include "WasmMemory.h"
    3940#include "WasmModuleParser.h"
     
    6263}
    6364
    64 bool Plan::parseAndValidateModule()
     65bool Plan::parseAndValidateModule(std::optional<Memory::Mode> recompileMode)
    6566{
    6667    MonotonicTime startTime;
     
    6970
    7071    {
    71         ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
     72        ModuleParser moduleParser(m_vm, m_source, m_sourceLength, recompileMode);
    7273        auto parseResult = moduleParser.parse();
    7374        if (!parseResult) {
     
    110111// that could touch its stack are done executing.
    111112SUPPRESS_ASAN
    112 void Plan::run()
    113 {
    114     if (!parseAndValidateModule())
     113void Plan::run(std::optional<Memory::Mode> recompileMode)
     114{
     115    if (!parseAndValidateModule(recompileMode))
    115116        return;
     117    if (recompileMode)
     118        ASSERT(m_moduleInformation->memory.mode() == recompileMode);
    116119
    117120    auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
  • trunk/Source/JavaScriptCore/wasm/WasmPlan.h

    r210229 r213386  
    5050    JS_EXPORT_PRIVATE ~Plan();
    5151
    52     bool parseAndValidateModule();
     52    bool parseAndValidateModule(std::optional<Memory::Mode> = std::nullopt);
    5353
    54     JS_EXPORT_PRIVATE void run();
     54    JS_EXPORT_PRIVATE void run(std::optional<Memory::Mode> = std::nullopt);
    5555
    5656    JS_EXPORT_PRIVATE void initializeCallees(JSGlobalObject*, std::function<void(unsigned, JSWebAssemblyCallee*, JSWebAssemblyCallee*)>);
     
    9393    }
    9494
     95    Memory::Mode mode() const { return m_moduleInformation->memory.mode(); }
     96
    9597private:
    9698    std::unique_ptr<ModuleInformation> m_moduleInformation;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp

    r210829 r213386  
    3030
    3131#include "JSCInlines.h"
     32#include "WasmFaultSignalHandler.h"
    3233
    3334namespace JSC {
     
    4445
    4546    m_entrypoint = WTFMove(entrypoint);
     47    Wasm::registerCode(vm, m_entrypoint.compilation->codeRef().executableMemory()->start(), m_entrypoint.compilation->codeRef().executableMemory()->end());
    4648}
    4749
     
    4951{
    5052    JSWebAssemblyCallee* thisObject = static_cast<JSWebAssemblyCallee*>(cell);
     53    Wasm::unregisterCode(*cell->vm(), thisObject->m_entrypoint.compilation->codeRef().executableMemory()->start(), thisObject->m_entrypoint.compilation->codeRef().executableMemory()->end());
    5154    thisObject->JSWebAssemblyCallee::~JSWebAssemblyCallee();
    5255}
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r211247 r213386  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3939namespace JSC {
    4040
     41void JSWebAssemblyInstance::setMemory(VM& vm, ExecState* exec, JSWebAssemblyMemory* memory)
     42{
     43    auto scope = DECLARE_THROW_SCOPE(vm);
     44    // We create stub memories even for modules that should eventually get a memory so we want to avoid recompling there.
     45    if (memory->memory()) {
     46        auto codeBlock = m_codeBlock->module()->codeBlock(vm, exec, memory);
     47        RETURN_IF_EXCEPTION(scope,);
     48        m_codeBlock.set(vm, this, codeBlock);
     49    }
     50    m_memory.set(vm, this, memory);
     51}
     52
    4153JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, Structure* structure, JSWebAssemblyModule* module, JSModuleNamespaceObject* moduleNamespaceObject)
    4254{
     
    6880    heap()->reportExtraMemoryAllocated(extraMemorySize);
    6981
    70     m_module.set(vm, this, module);
     82    m_codeBlock.set(vm, this, module->codeBlock());
    7183    m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject);
    7284    putDirect(vm, Identifier::fromString(&vm, "exports"), moduleNamespaceObject, None);
     
    8496
    8597    Base::visitChildren(thisObject, visitor);
    86     visitor.append(thisObject->m_module);
     98    visitor.append(thisObject->m_codeBlock);
    8799    visitor.append(thisObject->m_moduleNamespaceObject);
    88100    visitor.append(thisObject->m_memory);
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

    r210229 r213386  
    3030#include "JSDestructibleObject.h"
    3131#include "JSObject.h"
     32#include "JSWebAssemblyCodeBlock.h"
    3233#include "JSWebAssemblyMemory.h"
    3334#include "JSWebAssemblyTable.h"
     
    4849    DECLARE_INFO;
    4950
    50     JSWebAssemblyModule* module()
     51    JSWebAssemblyModule* module() const
    5152    {
    52         ASSERT(m_module);
    53         return m_module.get();
     53        ASSERT(m_codeBlock);
     54        return m_codeBlock->module();
     55    }
     56
     57    JSWebAssemblyCodeBlock* codeBlock() const
     58    {
     59        ASSERT(m_codeBlock);
     60        return m_codeBlock.get();
    5461    }
    5562
     
    7178
    7279    JSWebAssemblyMemory* memory() { return m_memory.get(); }
    73     void setMemory(VM& vm, JSWebAssemblyMemory* memory) { m_memory.set(vm, this, memory); }
     80    // Calling this might trigger a recompile.
     81    void setMemory(VM&, ExecState*, JSWebAssemblyMemory*);
     82    Wasm::Memory::Mode memoryMode() { return memory()->memory().mode(); }
    7483
    7584    JSWebAssemblyTable* table() { return m_table.get(); }
     
    105114
    106115private:
    107     WriteBarrier<JSWebAssemblyModule> m_module;
     116    WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
    108117    WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
    109118    WriteBarrier<JSWebAssemblyMemory> m_memory;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp

    r211247 r213386  
    3838const ClassInfo JSWebAssemblyMemory::s_info = { "WebAssembly.Memory", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyMemory) };
    3939
    40 JSWebAssemblyMemory* JSWebAssemblyMemory::create(VM& vm, Structure* structure, Wasm::Memory&& memory)
     40JSWebAssemblyMemory* JSWebAssemblyMemory::create(VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
    4141{
    42     auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, std::forward<Wasm::Memory>(memory));
     42    auto* instance = new (NotNull, allocateCell<JSWebAssemblyMemory>(vm.heap)) JSWebAssemblyMemory(vm, structure, WTFMove(memory));
     43    instance->m_memory->check();
    4344    instance->finishCreation(vm);
    4445    return instance;
     
    5051}
    5152
    52 JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, Wasm::Memory&& memory)
     53JSWebAssemblyMemory::JSWebAssemblyMemory(VM& vm, Structure* structure, Ref<Wasm::Memory>&& memory)
    5354    : Base(vm, structure)
    5455    , m_memory(WTFMove(memory))
    5556{
     57    ASSERT(m_memory->refCount() == 1);
     58    m_memoryBase = m_memory->memory();
     59    m_memorySize = m_memory->size();
    5660}
    5761
     
    6165        return m_bufferWrapper.get();
    6266
    63     auto destructor = [] (void*) {
    64         // We don't need to do anything here to destroy the memory.
    65         // The ArrayBuffer backing the JSArrayBuffer is only owned by us,
    66         // so we guarantee its lifecycle.
    67     };
    68     m_buffer = ArrayBuffer::createFromBytes(memory()->memory(), memory()->size(), WTFMove(destructor));
     67    // We can't use a ref here since it doesn't have a copy constructor...
     68    Ref<Wasm::Memory> protectedMemory = m_memory.get();
     69    auto destructor = [protectedMemory = WTFMove(protectedMemory)] (void*) { };
     70    m_buffer = ArrayBuffer::createFromBytes(memory().memory(), memory().size(), WTFMove(destructor));
    6971    m_bufferWrapper.set(vm, this, JSArrayBuffer::create(vm, globalObject->m_arrayBufferStructure.get(), m_buffer.get()));
    7072    RELEASE_ASSERT(m_bufferWrapper);
     
    7779    auto throwScope = DECLARE_THROW_SCOPE(vm);
    7880
    79     Wasm::PageCount oldPageCount = memory()->sizeInPages();
     81    Wasm::PageCount oldPageCount = memory().sizeInPages();
    8082
    8183    if (!Wasm::PageCount::isValid(delta)) {
     
    9395
    9496    if (delta) {
    95         bool success = memory()->grow(newSize);
     97        bool success = memory().grow(newSize);
    9698        if (!success) {
     99            ASSERT(m_memoryBase == memory().memory());
     100            ASSERT(m_memorySize == memory().size());
    97101            if (shouldThrowExceptionsOnFailure)
    98102                throwException(exec, throwScope, createOutOfMemoryError(exec));
    99103            return Wasm::PageCount();
    100104        }
     105        m_memoryBase = memory().memory();
     106        m_memorySize = memory().size();
    101107    }
    102108
     
    111117    }
    112118
     119    memory().check();
    113120    return oldPageCount;
    114121}
     
    124131    auto memory = static_cast<JSWebAssemblyMemory*>(cell);
    125132    ASSERT(memory->classInfo() == info());
    126     VM& vm = *memory->vm();
    127 
    128     if (memory->m_buffer) {
    129         ArrayBufferContents dummyContents;
    130         memory->m_buffer->transferTo(vm, dummyContents);
    131         memory->m_buffer = nullptr;
    132     }
    133133
    134134    memory->JSWebAssemblyMemory::~JSWebAssemblyMemory();
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h

    r211247 r213386  
    4242    typedef JSDestructibleObject Base;
    4343
    44     static JSWebAssemblyMemory* create(VM&, Structure*, Wasm::Memory&&);
     44    static JSWebAssemblyMemory* create(VM&, Structure*, Ref<Wasm::Memory>&&);
    4545    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4646
    4747    DECLARE_INFO;
    4848
    49     Wasm::Memory* memory() { return &m_memory; }
     49    Wasm::Memory& memory() { return m_memory.get(); }
    5050    JSArrayBuffer* buffer(VM& vm, JSGlobalObject*);
    5151    Wasm::PageCount grow(ExecState*, uint32_t delta, bool shouldThrowExceptionsOnFailure);
    5252
    53     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memory) + Wasm::Memory::offsetOfMemory(); }
    54     static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memory) + Wasm::Memory::offsetOfSize(); }
     53    static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memoryBase); }
     54    static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyMemory, m_memorySize); }
    5555
    56 protected:
    57     JSWebAssemblyMemory(VM&, Structure*, Wasm::Memory&&);
     56private:
     57    JSWebAssemblyMemory(VM&, Structure*, Ref<Wasm::Memory>&&);
    5858    void finishCreation(VM&);
    5959    static void destroy(JSCell*);
    6060    static void visitChildren(JSCell*, SlotVisitor&);
    6161
    62     Wasm::Memory m_memory;
     62    void* m_memoryBase;
     63    size_t m_memorySize;
     64    Ref<Wasm::Memory> m_memory;
    6365    WriteBarrier<JSArrayBuffer> m_bufferWrapper;
    6466    RefPtr<ArrayBuffer> m_buffer;
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

    r211247 r213386  
    3131#include "JSCInlines.h"
    3232#include "JSWebAssemblyCallee.h"
     33#include "JSWebAssemblyCodeBlock.h"
     34#include "JSWebAssemblyCompileError.h"
     35#include "JSWebAssemblyMemory.h"
    3336#include "WasmFormat.h"
    3437#include "WasmMemory.h"
     38#include "WasmPlan.h"
    3539#include <wtf/StdLibExtras.h>
    3640
     
    3943const ClassInfo JSWebAssemblyModule::s_info = { "WebAssembly.Module", &Base::s_info, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyModule) };
    4044
    41 JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, SymbolTable* exportSymbolTable, unsigned calleeCount)
     45JSWebAssemblyCodeBlock* JSWebAssemblyModule::buildCodeBlock(VM& vm, ExecState* exec, Wasm::Plan& plan, std::optional<Wasm::Memory::Mode> mode)
    4246{
    43     auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap, allocationSize(calleeCount))) JSWebAssemblyModule(vm, structure, std::forward<std::unique_ptr<Wasm::ModuleInformation>>(moduleInformation), std::forward<Bag<CallLinkInfo>>(callLinkInfos), std::forward<Vector<Wasm::WasmExitStubs>>(wasmExitStubs), calleeCount);
    44     instance->finishCreation(vm, exportSymbolTable);
     47    auto scope = DECLARE_THROW_SCOPE(vm);
     48    // On failure, a new WebAssembly.CompileError is thrown.
     49    plan.run(mode);
     50    if (plan.failed()) {
     51        throwException(exec, scope, createJSWebAssemblyCompileError(exec, vm, plan.errorMessage()));
     52        return nullptr;
     53    }
     54    if (mode)
     55        ASSERT(*mode == plan.mode());
     56
     57    unsigned calleeCount = plan.internalFunctionCount();
     58    auto* codeBlock = JSWebAssemblyCodeBlock::create(vm, this, plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), plan.mode(), calleeCount);
     59
     60    plan.initializeCallees(exec->jsCallee()->globalObject(),
     61        [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
     62            codeBlock->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);
     63            codeBlock->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee);
     64        });
     65    return codeBlock;
     66}
     67
     68JSWebAssemblyModule* JSWebAssemblyModule::create(VM& vm, ExecState* exec, Structure* structure, uint8_t* source, size_t byteSize)
     69{
     70    auto* instance = new (NotNull, allocateCell<JSWebAssemblyModule>(vm.heap)) JSWebAssemblyModule(vm, structure);
     71
     72    instance->finishCreation(vm, exec, source, byteSize);
    4573    return instance;
    4674}
     
    5179}
    5280
    53 JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure, std::unique_ptr<Wasm::ModuleInformation>&& moduleInformation, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, unsigned calleeCount)
     81JSWebAssemblyModule::JSWebAssemblyModule(VM& vm, Structure* structure)
    5482    : Base(vm, structure)
    55     , m_moduleInformation(WTFMove(moduleInformation))
    56     , m_callLinkInfos(WTFMove(callLinkInfos))
    57     , m_wasmExitStubs(WTFMove(wasmExitStubs))
    58     , m_calleeCount(calleeCount)
    5983{
    60     memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>) * 2);
    6184}
    6285
    63 void JSWebAssemblyModule::finishCreation(VM& vm, SymbolTable* exportSymbolTable)
     86JSWebAssemblyCodeBlock* JSWebAssemblyModule::codeBlock(VM& vm, ExecState* exec, JSWebAssemblyMemory* memory)
     87{
     88    Wasm::Memory::Mode mode = memory->memory().mode();
     89
     90    for (unsigned i = 0; i < Wasm::Memory::NumberOfModes; ++i) {
     91        if (m_codeBlocks[i] && m_codeBlocks[i]->isSafeToRun(memory))
     92            return m_codeBlocks[i].get();
     93    }
     94
     95    ASSERT(!m_codeBlocks[mode]);
     96    auto scope = DECLARE_THROW_SCOPE(vm);
     97    // We don't have a code block for this mode, we need to recompile...
     98    Wasm::Plan plan(&vm, static_cast<uint8_t*>(m_sourceBuffer->data()), m_sourceBuffer->byteLength());
     99
     100    auto* codeBlock = buildCodeBlock(vm, exec, plan, mode);
     101    RETURN_IF_EXCEPTION(scope, nullptr);
     102
     103    ASSERT(plan.exports().size() == m_exportSymbolTable->size());
     104    if (!ASSERT_DISABLED) {
     105        for (auto& exp : plan.exports())
     106            ASSERT_UNUSED(exp, m_exportSymbolTable->contains(exp.field.impl()));
     107    }
     108
     109    ASSERT(mode == codeBlock->mode());
     110    m_codeBlocks[mode].set(vm, this, codeBlock);
     111    return codeBlock;
     112}
     113
     114void JSWebAssemblyModule::finishCreation(VM& vm, ExecState* exec, uint8_t* source, size_t byteSize)
    64115{
    65116    Base::finishCreation(vm);
    66117    ASSERT(inherits(vm, info()));
     118
     119    auto scope = DECLARE_THROW_SCOPE(vm);
     120    Wasm::Plan plan(&vm, source, byteSize);
     121
     122    auto* codeBlock = buildCodeBlock(vm, exec, plan);
     123    RETURN_IF_EXCEPTION(scope,);
     124
     125    // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module.
     126    SymbolTable* exportSymbolTable = SymbolTable::create(vm);
     127    for (auto& exp : plan.exports()) {
     128        auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary);
     129        exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset)));
     130    }
     131
     132    m_sourceBuffer = ArrayBuffer::create(source, byteSize);
     133    m_moduleInformation = plan.takeModuleInformation();
    67134    m_exportSymbolTable.set(vm, this, exportSymbolTable);
     135    m_codeBlocks[codeBlock->mode()].set(vm, this, codeBlock);
    68136}
    69137
     
    80148    Base::visitChildren(thisObject, visitor);
    81149    visitor.append(thisObject->m_exportSymbolTable);
    82     for (unsigned i = 0; i < thisObject->m_calleeCount * 2; i++)
    83         visitor.append(thisObject->callees()[i]);
    84 
    85     visitor.addUnconditionalFinalizer(&thisObject->m_unconditionalFinalizer);
    86 }
    87 
    88 void JSWebAssemblyModule::UnconditionalFinalizer::finalizeUnconditionally()
    89 {
    90     JSWebAssemblyModule* thisObject = bitwise_cast<JSWebAssemblyModule*>(
    91         bitwise_cast<char*>(this) - OBJECT_OFFSETOF(JSWebAssemblyModule, m_unconditionalFinalizer));
    92     for (auto iter = thisObject->m_callLinkInfos.begin(); !!iter; ++iter)
    93         (*iter)->visitWeak(*thisObject->vm());
     150    for (unsigned i = 0; i < Wasm::Memory::NumberOfModes; ++i)
     151        visitor.append(thisObject->m_codeBlocks[i]);
    94152}
    95153
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

    r210229 r213386  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3030#include "JSDestructibleObject.h"
    3131#include "JSObject.h"
    32 #include "JSWebAssemblyCallee.h"
     32#include "JSWebAssemblyCodeBlock.h"
    3333#include "UnconditionalFinalizer.h"
    3434#include "WasmFormat.h"
     
    3838namespace JSC {
    3939
     40namespace Wasm {
     41class Plan;
     42}
     43
    4044class SymbolTable;
     45class JSWebAssemblyMemory;
    4146
    4247class JSWebAssemblyModule : public JSDestructibleObject {
     
    4449    typedef JSDestructibleObject Base;
    4550
    46     static JSWebAssemblyModule* create(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, SymbolTable*, unsigned);
     51    static JSWebAssemblyModule* create(VM&, ExecState*, Structure*, uint8_t* source, size_t byteSize);
    4752    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
    4853
     
    5055
    5156    const Wasm::ModuleInformation& moduleInformation() const { return *m_moduleInformation.get(); }
     57    RefPtr<Wasm::Memory> takeReservedMemory() { return m_moduleInformation->memory.takeReservedMemory(); }
    5258    SymbolTable* exportSymbolTable() const { return m_exportSymbolTable.get(); }
    5359    Wasm::SignatureIndex signatureIndexFromFunctionIndexSpace(unsigned functionIndexSpace) const
     
    5561        return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
    5662    }
    57     unsigned functionImportCount() const { return m_wasmExitStubs.size(); }
    5863
    59     JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
    60     {
    61         RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
    62         unsigned calleeIndex = functionIndexSpace - functionImportCount();
    63         RELEASE_ASSERT(calleeIndex < m_calleeCount);
    64         return callees()[calleeIndex].get();
    65     }
     64    // Returns the code block that this module was originally compiled expecting to use. This won't need to recompile.
     65    JSWebAssemblyCodeBlock* codeBlock() { return m_codeBlocks[m_moduleInformation->memory.mode()].get(); }
     66    // Returns the appropriate code block for the given memory, possibly triggering a recompile.
     67    JSWebAssemblyCodeBlock* codeBlock(VM&, ExecState*, JSWebAssemblyMemory*);
    6668
    67     JSWebAssemblyCallee* wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
    68     {
    69         RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
    70         unsigned calleeIndex = functionIndexSpace - functionImportCount();
    71         RELEASE_ASSERT(calleeIndex < m_calleeCount);
    72         return callees()[calleeIndex + m_calleeCount].get();
    73     }
     69private:
     70    JSWebAssemblyCodeBlock* buildCodeBlock(VM&, ExecState*, Wasm::Plan&, std::optional<Wasm::Memory::Mode> mode = std::nullopt);
    7471
    75     void setJSEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
    76     {
    77         RELEASE_ASSERT(calleeIndex < m_calleeCount);
    78         callees()[calleeIndex].set(vm, this, callee);
    79     }
    80 
    81     void setWasmEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
    82     {
    83         RELEASE_ASSERT(calleeIndex < m_calleeCount);
    84         callees()[calleeIndex + m_calleeCount].set(vm, this, callee);
    85     }
    86 
    87     WriteBarrier<JSWebAssemblyCallee>* callees()
    88     {
    89         return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
    90     }
    91 
    92 protected:
    93     JSWebAssemblyModule(VM&, Structure*, std::unique_ptr<Wasm::ModuleInformation>&&, Bag<CallLinkInfo>&&, Vector<Wasm::WasmExitStubs>&&, unsigned calleeCount);
    94     void finishCreation(VM&, SymbolTable*);
     72    JSWebAssemblyModule(VM&, Structure*);
     73    void finishCreation(VM&, ExecState*, uint8_t* source, size_t byteSize);
    9574    static void destroy(JSCell*);
    9675    static void visitChildren(JSCell*, SlotVisitor&);
    9776
    98 private:
    99     static size_t offsetOfCallees()
    100     {
    101         return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSWebAssemblyCallee>)>(sizeof(JSWebAssemblyModule));
    102     }
    103 
    104     static size_t allocationSize(unsigned numCallees)
    105     {
    106         return offsetOfCallees() + sizeof(WriteBarrier<JSWebAssemblyCallee>) * numCallees * 2;
    107     }
    108 
    109     class UnconditionalFinalizer : public JSC::UnconditionalFinalizer {
    110         void finalizeUnconditionally() override;
    111     };
    112 
    113     UnconditionalFinalizer m_unconditionalFinalizer;
     77    RefPtr<ArrayBuffer> m_sourceBuffer;
    11478    std::unique_ptr<Wasm::ModuleInformation> m_moduleInformation;
    115     Bag<CallLinkInfo> m_callLinkInfos;
    11679    WriteBarrier<SymbolTable> m_exportSymbolTable;
    117     Vector<Wasm::WasmExitStubs> m_wasmExitStubs;
    118     unsigned m_calleeCount;
     80    WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlocks[Wasm::Memory::NumberOfModes];
    11981};
    12082
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

    r211247 r213386  
    5757    const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
    5858
     59    // Make sure that the memory we think we are going to run with matches the one we expect.
     60    ASSERT(wasmFunction->instance()->codeBlock()->isSafeToRun(wasmFunction->instance()->memory()));
    5961    {
    6062        // Check if we have a disallowed I64 use.
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

    r212983 r213386  
    8585    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, instanceStructure, jsModule, moduleRecord->getModuleNamespace(exec));
    8686    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    87     {
    88         // Always start with a dummy Memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
    89         Wasm::Memory memory;
    90         instance->setMemory(vm, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
    91     }
     87
    9288
    9389    // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
     
    179175
    180176            Wasm::PageCount expectedInitial = moduleInformation.memory.initial();
    181             Wasm::PageCount actualInitial = memory->memory()->initial();
     177            Wasm::PageCount actualInitial = memory->memory().initial();
    182178            if (actualInitial < expectedInitial)
    183179                return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided an 'initial' that is too small"))));
    184180
    185181            if (Wasm::PageCount expectedMaximum = moduleInformation.memory.maximum()) {
    186                 Wasm::PageCount actualMaximum = memory->memory()->maximum();
     182                Wasm::PageCount actualMaximum = memory->memory().maximum();
    187183                if (!actualMaximum) {
    188184                    return JSValue::encode(
     
    195191                }
    196192            }
     193
    197194            // ii. Append v to memories.
    198195            // iii. Append v.[[Memory]] to imports.
    199             instance->setMemory(vm, memory);
     196            instance->setMemory(vm, exec, memory);
     197            RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    200198            break;
    201199        }
     
    238236            RELEASE_ASSERT(!moduleInformation.memory.isImport());
    239237            // We create a memory when it's a memory definition.
    240             bool failed;
    241             Wasm::Memory memory(moduleInformation.memory.initial(), moduleInformation.memory.maximum(), failed);
    242             if (failed)
    243                 return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
    244             instance->setMemory(vm,
    245                JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
     238            RefPtr<Wasm::Memory> memory;
     239            if (moduleInformation.memory.hasReservedMemory())
     240                memory = jsModule->takeReservedMemory();
     241            else {
     242                memory = Wasm::Memory::create(vm, moduleInformation.memory.initial(), moduleInformation.memory.maximum());
     243                if (!memory)
     244                    return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
     245            }
     246            instance->setMemory(vm, exec,
     247                JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), memory.releaseNonNull()));
     248            RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
    246249        }
    247250    }
     
    264267            instance->setTable(vm, table);
    265268        }
     269    }
     270
     271    if (!instance->memory()) {
     272        // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
     273        instance->setMemory(vm, exec, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*(new Wasm::Memory()))));
    266274    }
    267275
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp

    r210229 r213386  
    9797    }
    9898
    99     bool failed;
    100     Wasm::Memory memory(initialPageCount, maximumPageCount, failed);
    101     if (failed)
     99    RefPtr<Wasm::Memory> memory = Wasm::Memory::create(vm, initialPageCount, maximumPageCount);
     100    if (!memory)
    102101        return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
    103102
    104     return JSValue::encode(JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
     103    return JSValue::encode(JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*memory.leakRef())));
    105104}
    106105
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

    r210229 r213386  
    8181    RETURN_IF_EXCEPTION(scope, { });
    8282
    83     Wasm::Plan plan(&vm, base + byteOffset, byteSize);
    84     // On failure, a new WebAssembly.CompileError is thrown.
    85     plan.run();
    86     if (plan.failed())
    87         return throwException(state, scope, createJSWebAssemblyCompileError(state, vm, plan.errorMessage()));
    88 
    89     // On success, a new WebAssembly.Module object is returned with [[Module]] set to the validated Ast.module.
    90 
    91     // The export symbol table is the same for all Instances of a Module.
    92     SymbolTable* exportSymbolTable = SymbolTable::create(vm);
    93     for (auto& exp : plan.exports()) {
    94         auto offset = exportSymbolTable->takeNextScopeOffset(NoLockingNecessary);
    95         exportSymbolTable->set(NoLockingNecessary, exp.field.impl(), SymbolTableEntry(VarOffset(offset)));
    96     }
    97 
    98     // Only wasm-internal functions have a callee, stubs to JS do not.
    99     unsigned calleeCount = plan.internalFunctionCount();
    100     JSWebAssemblyModule* result = JSWebAssemblyModule::create(vm, structure, plan.takeModuleInformation(), plan.takeCallLinkInfos(), plan.takeWasmExitStubs(), exportSymbolTable, calleeCount);
    101     plan.initializeCallees(state->jsCallee()->globalObject(),
    102         [&] (unsigned calleeIndex, JSWebAssemblyCallee* jsEntrypointCallee, JSWebAssemblyCallee* wasmEntrypointCallee) {
    103             result->setJSEntrypointCallee(vm, calleeIndex, jsEntrypointCallee);
    104             result->setWasmEntrypointCallee(vm, calleeIndex, wasmEntrypointCallee);
    105         });
    106 
    107     return result;
     83    scope.release();
     84    return JSWebAssemblyModule::create(vm, state, structure, base + byteOffset, byteSize);
    10885}
    10986
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r212983 r213386  
    9393
    9494    JSWebAssemblyModule* module = instance->module();
     95    JSWebAssemblyCodeBlock* codeBlock = instance->codeBlock();
    9596    const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
    9697
    9798    SymbolTable* exportSymbolTable = module->exportSymbolTable();
    98     unsigned functionImportCount = module->functionImportCount();
     99    unsigned functionImportCount = codeBlock->functionImportCount();
    99100
    100101    // FIXME wire up the imports. https://bugs.webkit.org/show_bug.cgi?id=165118
     
    117118            //     b. Append func to funcs.
    118119            //     c. Return func.
    119             JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
    120             JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
     120            JSWebAssemblyCallee* jsEntrypointCallee = codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
     121            JSWebAssemblyCallee* wasmEntrypointCallee = codeBlock->wasmEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
    121122            Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
    122123            const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
     
    183184        ASSERT(!signature->argumentCount());
    184185        ASSERT(signature->returnType() == Wasm::Void);
    185         if (startFunctionIndexSpace < module->functionImportCount()) {
     186        if (startFunctionIndexSpace < codeBlock->functionImportCount()) {
    186187            JSCell* startFunction = instance->importFunction(startFunctionIndexSpace)->get();
    187188            m_startFunction.set(vm, this, startFunction);
    188189        } else {
    189             JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
    190             JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
     190            JSWebAssemblyCallee* jsEntrypointCallee = codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
     191            JSWebAssemblyCallee* wasmEntrypointCallee = codeBlock->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
    191192            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
    192193            m_startFunction.set(vm, this, function);
     
    212213    {
    213214        JSWebAssemblyModule* module = m_instance->module();
     215        JSWebAssemblyCodeBlock* codeBlock = m_instance->codeBlock();
    214216        const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
    215217        JSWebAssemblyTable* table = m_instance->table();
     
    234236                // https://bugs.webkit.org/show_bug.cgi?id=165510
    235237                uint32_t functionIndex = element.functionIndices[i];
    236                 if (functionIndex < module->functionImportCount()) {
     238                if (functionIndex < codeBlock->functionImportCount()) {
    237239                    return JSValue::decode(
    238240                        throwVMRangeError(state, scope, ASCIILiteral("Element is setting the table value with an import. This is not yet implemented. FIXME.")));
    239241                }
    240242
    241                 JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
    242                 JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
     243                JSWebAssemblyCallee* jsEntrypointCallee = codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
     244                JSWebAssemblyCallee* wasmEntrypointCallee = codeBlock->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
    243245                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
    244246                const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
     
    260262        JSWebAssemblyMemory* jsMemory = m_instance->memory();
    261263        if (!data.isEmpty()) {
    262             uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory());
    263             uint64_t sizeInBytes = jsMemory->memory()->size();
     264            uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory().memory());
     265            uint64_t sizeInBytes = jsMemory->memory().size();
    264266            for (auto& segment : data) {
    265267                if (segment->sizeInBytes) {
  • trunk/Source/WTF/ChangeLog

    r213324 r213386  
     12017-03-03  Keith Miller  <keith_miller@apple.com>
     2
     3        WASM should support faster loads.
     4        https://bugs.webkit.org/show_bug.cgi?id=162693
     5
     6        Reviewed by Saam Barati.
     7
     8        Add new forms of dataLog that take a boolean which describes if the log should happen. This makes cases where we have a static const bool for printing nicer since you can do:
     9
     10        dataLogIf(verbose, things, to, print);
     11
     12        instead of:
     13
     14        if (verbose)
     15            dataLog(things, to, print);
     16
     17        Also, add a operator! to Ref that has the same semantics as C++ refs.
     18
     19        * wtf/DataLog.h:
     20        (WTF::dataLogLn):
     21        (WTF::dataLogIf):
     22        (WTF::dataLogLnIf):
     23        * wtf/Ref.h:
     24        (WTF::Ref::operator!):
     25
    1262017-03-02  Jer Noble  <jer.noble@apple.com>
    227
  • trunk/Source/WTF/wtf/DataLog.h

    r213151 r213386  
    5050void dataLogLn(const Types&... values)
    5151{
    52     dataFile().print(values..., "\n");
     52    dataLog(values..., "\n");
     53}
     54
     55template<typename... Types>
     56void dataLogIf(bool shouldLog, const Types&... values)
     57{
     58    if (shouldLog)
     59        dataLog(values...);
     60}
     61
     62template<typename... Types>
     63void dataLogLnIf(bool shouldLog, const Types&... values)
     64{
     65    if (shouldLog)
     66        dataLogLn(values...);
    5367}
    5468
     
    5771using WTF::dataLog;
    5872using WTF::dataLogLn;
     73using WTF::dataLogIf;
     74using WTF::dataLogLnIf;
    5975using WTF::dataLogF;
    6076using WTF::dataLogFString;
  • trunk/Source/WTF/wtf/Ref.h

    r212817 r213386  
    138138    T& get() const { ASSERT(m_ptr); return *m_ptr; }
    139139    operator T&() const { ASSERT(m_ptr); return *m_ptr; }
     140    bool operator!() const { ASSERT(m_ptr); return !*m_ptr; }
    140141
    141142    template<typename U> Ref<T> replace(Ref<U>&&) WARN_UNUSED_RETURN;
Note: See TracChangeset for help on using the changeset viewer.