Source/JavaScriptCore/ChangeLog

 12017-03-02 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-02-24 Keith Miller <keith_miller@apple.com>
2171
3172 We should be able to use std::tuples as keys in HashMap

Source/WTF/ChangeLog

 12017-03-02 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-02-24 Keith Miller <keith_miller@apple.com>
227
328 We should be able to use std::tuples as keys in HashMap

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

13201320 535557161D9DFA32006D583B /* WasmMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 535557151D9DFA32006D583B /* WasmMemory.cpp */; };
13211321 5370B4F51BF26202005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */; };
13221322 5370B4F61BF26205005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */; };
 1323 5381B9371E60E9660090F794 /* WasmFaultSignalHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */; };
 1324 5381B9391E60E97D0090F794 /* WasmFaultSignalHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */; };
 1325 5381B9401E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */; };
 1326 5383AA301E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */; };
13231327 53917E7B1B7906FA000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */; };
13241328 539FB8BA1C99DA7C00940FA1 /* JSArrayInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 539FB8B91C99DA7C00940FA1 /* JSArrayInlines.h */; };
13251329 53B0BE341E561AC900A8FC29 /* GetterSetterAccessCase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53B0BE331E561AC900A8FC29 /* GetterSetterAccessCase.cpp */; };

37763780 535557151D9DFA32006D583B /* WasmMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmMemory.cpp; sourceTree = "<group>"; };
37773781 5370B4F31BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdaptiveInferredPropertyValueWatchpointBase.cpp; sourceTree = "<group>"; };
37783782 5370B4F41BF25EA2005C40FC /* AdaptiveInferredPropertyValueWatchpointBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdaptiveInferredPropertyValueWatchpointBase.h; sourceTree = "<group>"; };
 3783 5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WasmFaultSignalHandler.cpp; sourceTree = "<group>"; };
 3784 5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WasmFaultSignalHandler.h; sourceTree = "<group>"; };
 3785 5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebAssemblyCodeBlock.h; sourceTree = "<group>"; };
 3786 5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSWebAssemblyCodeBlock.cpp; path = js/JSWebAssemblyCodeBlock.cpp; sourceTree = "<group>"; };
37793787 53917E7A1B7906E4000EBD33 /* JSGenericTypedArrayViewPrototypeFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGenericTypedArrayViewPrototypeFunctions.h; sourceTree = "<group>"; };
37803788 53917E7C1B791106000EBD33 /* JSTypedArrayViewPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypedArrayViewPrototype.h; sourceTree = "<group>"; };
37813789 53917E831B791CB8000EBD33 /* TypedArrayPrototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = TypedArrayPrototype.js; path = builtins/TypedArrayPrototype.js; sourceTree = SOURCE_ROOT; };

62016209 53F40E961D5A7BEC0099A1B6 /* WasmModuleParser.cpp */,
62026210 53F40E941D5A7AEF0099A1B6 /* WasmModuleParser.h */,
62036211 ADB6F67C1E15D7500082F384 /* WasmPageCount.cpp */,
 6212 5381B9361E60E9660090F794 /* WasmFaultSignalHandler.cpp */,
 6213 5381B9381E60E97D0090F794 /* WasmFaultSignalHandler.h */,
62046214 79B759731DFA4C600052174C /* WasmPageCount.h */,
62056215 53F40E8C1D5901F20099A1B6 /* WasmParser.h */,
62066216 531374BE1D5CE95000AF7A0B /* WasmPlan.cpp */,

77887798 children = (
77897799 79E423E01DEE65320078D355 /* JSWebAssemblyCallee.cpp */,
77907800 79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */,
 7801 5383AA2F1E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp */,
 7802 5381B93F1E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h */,
77917803 AD2FCBA61DB58DA400B3E736 /* JSWebAssemblyCompileError.cpp */,
77927804 AD2FCBA71DB58DA400B3E736 /* JSWebAssemblyCompileError.h */,
77937805 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */,

79277939 0FEC85721BDACDC70080FF74 /* AirBasicBlock.h in Headers */,
79287940 0FB3878E1BFBC44D00E3AB1E /* AirBlockWorklist.h in Headers */,
79297941 0F61832A1C45BF070072450B /* AirCCallingConvention.h in Headers */,
 7942 5381B9401E65DFEB0090F794 /* JSWebAssemblyCodeBlock.h in Headers */,
79307943 0FEC85741BDACDC70080FF74 /* AirCCallSpecial.h in Headers */,
79317944 0FEC85761BDACDC70080FF74 /* AirCode.h in Headers */,
79327945 0F10F1A31C420BF0001C07D2 /* AirCustom.h in Headers */,

82468259 A7D89CF417A0B8CC00773AD8 /* DFGBlockInsertionSet.h in Headers */,
82478260 0FC3CCFC19ADA410006AC72A /* DFGBlockMap.h in Headers */,
82488261 0FC3CCFD19ADA410006AC72A /* DFGBlockMapInlines.h in Headers */,
 8262 5381B9391E60E97D0090F794 /* WasmFaultSignalHandler.h in Headers */,
82498263 0FC3CCFE19ADA410006AC72A /* DFGBlockSet.h in Headers */,
82508264 0FBF158D19B7A53100695DD0 /* DFGBlockSetInlines.h in Headers */,
82518265 0FC3CD0019ADA410006AC72A /* DFGBlockWorklist.h in Headers */,

1003610050 0FC841681BA8C3210061837D /* DFGInferredTypeCheck.cpp in Sources */,
1003710051 A704D90517A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp in Sources */,
1003810052 0F3BD1B71B896A0700598AA6 /* DFGInsertionSet.cpp in Sources */,
 10053 5381B9371E60E9660090F794 /* WasmFaultSignalHandler.cpp in Sources */,
1003910054 0F300B7B18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp in Sources */,
1004010055 0F898F311B27689F0083A33C /* DFGIntegerRangeOptimizationPhase.cpp in Sources */,
1004110056 0FC97F3D18202119002C9B26 /* DFGInvalidationPointInjectionPhase.cpp in Sources */,

1043710452 86C568E011A213EE0007F7F0 /* MacroAssemblerARM.cpp in Sources */,
1043810453 FEB137571BB11EF900CD5100 /* MacroAssemblerARM64.cpp in Sources */,
1043910454 A729009C17976C6000317298 /* MacroAssemblerARMv7.cpp in Sources */,
 10455 5383AA301E65E8A100A532FC /* JSWebAssemblyCodeBlock.cpp in Sources */,
1044010456 0F6DB7EC1D617D1100CDBF8E /* MacroAssemblerCodeRef.cpp in Sources */,
1044110457 FE68C6381B90DE0B0042BCB3 /* MacroAssemblerPrinter.cpp in Sources */,
1044210458 A7A4AE0817973B26005612B1 /* MacroAssemblerX86Common.cpp in Sources */,

Source/JavaScriptCore/jit/JITThunks.cpp

@@MacroAssemblerCodeRef JITThunks::ctiStub(VM* vm, ThunkGenerator generator)
8282 return entry.iterator->value;
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{
8796 auto* nativeExecutable = static_cast<NativeExecutable*>(handle.get().asCell());

Source/JavaScriptCore/jit/JITThunks.h

@@public:
5858 MacroAssemblerCodePtr ctiNativeTailCallWithoutSavedTags(VM*);
5959
6060 MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
 61 MacroAssemblerCodeRef existingCTIStub(ThunkGenerator);
6162
6263 NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, const String& name);
6364 NativeExecutable* hostFunctionStub(VM*, NativeFunction, NativeFunction constructor, ThunkGenerator, Intrinsic, const DOMJIT::Signature*, const String& name);

Source/JavaScriptCore/jsc.cpp

7171#include "SuperSampler.h"
7272#include "TestRunnerUtils.h"
7373#include "TypeProfilerLog.h"
 74#include "WasmFaultSignalHandler.h"
7475#include "WasmPlan.h"
7576#include "WasmMemory.h"
7677#include <locale.h>

@@int jscmain(int argc, char** argv)
37663767 WTF::initializeMainThread();
37673768 JSC::initializeThreading();
37683769 startTimeoutThreadIfNeeded();
 3770#if ENABLE(WEBASSEMBLY)
 3771 JSC::Wasm::enableFastMemory();
 3772#endif
37693773
37703774 int result;
37713775 result = runJSC(

Source/JavaScriptCore/runtime/Options.h

@@typedef const char* optionString;
426426 \
427427 v(bool, useWebAssembly, true, Normal, "Expose the WebAssembly global object.") \
428428 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.") \
 429 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.")
 430
429431
430432enum OptionEquivalence {
431433 SameOption,

Source/JavaScriptCore/runtime/VM.cpp

@@VM::VM(VMType vmType, HeapType heapType)
240240#if ENABLE(WEBASSEMBLY)
241241 webAssemblyCalleeStructure.set(*this, JSWebAssemblyCallee::createStructure(*this, 0, jsNull()));
242242 webAssemblyToJSCalleeStructure.set(*this, WebAssemblyToJSCallee::createStructure(*this, 0, jsNull()));
 243 webAssemblyCodeBlockStructure.set(*this, JSWebAssemblyCodeBlock::createStructure(*this, 0, jsNull()));
243244 webAssemblyToJSCallee.set(*this, WebAssemblyToJSCallee::create(*this, webAssemblyToJSCalleeStructure.get()));
244245#endif
245246 moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));

Source/JavaScriptCore/runtime/VM.h

@@public:
333333#if ENABLE(WEBASSEMBLY)
334334 Strong<Structure> webAssemblyCalleeStructure;
335335 Strong<Structure> webAssemblyToJSCalleeStructure;
 336 Strong<Structure> webAssemblyCodeBlockStructure;
336337 Strong<JSCell> webAssemblyToJSCallee;
337338#endif
338339 Strong<Structure> moduleProgramExecutableStructure;

Source/JavaScriptCore/wasm/JSWebAssemblyCodeBlock.h

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(WEBASSEMBLY)
 29
 30#include "JSCell.h"
 31#include "JSWebAssemblyCallee.h"
 32#include "UnconditionalFinalizer.h"
 33#include "WasmFormat.h"
 34#include <wtf/Bag.h>
 35#include <wtf/Vector.h>
 36
 37namespace JSC {
 38
 39class JSWebAssemblyModule;
 40class JSWebAssemblyMemory;
 41
 42class JSWebAssemblyCodeBlock : public JSCell {
 43public:
 44 typedef JSCell Base;
 45 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
 46
 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 }
 53
 54 static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
 55 {
 56 return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
 57 }
 58
 59 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*);
 63
 64 JSWebAssemblyCallee* jsEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
 65 {
 66 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
 67 unsigned calleeIndex = functionIndexSpace - functionImportCount();
 68 RELEASE_ASSERT(calleeIndex < m_calleeCount);
 69 return callees()[calleeIndex].get();
 70 }
 71
 72 JSWebAssemblyCallee* wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
 73 {
 74 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
 75 unsigned calleeIndex = functionIndexSpace - functionImportCount();
 76 RELEASE_ASSERT(calleeIndex < m_calleeCount);
 77 return callees()[calleeIndex + m_calleeCount].get();
 78 }
 79
 80 void setJSEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
 81 {
 82 RELEASE_ASSERT(calleeIndex < m_calleeCount);
 83 callees()[calleeIndex].set(vm, this, callee);
 84 }
 85
 86 void setWasmEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
 87 {
 88 RELEASE_ASSERT(calleeIndex < m_calleeCount);
 89 callees()[calleeIndex + m_calleeCount].set(vm, this, callee);
 90 }
 91
 92 WriteBarrier<JSWebAssemblyCallee>* callees()
 93 {
 94 return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
 95 }
 96
 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;
 101 static void destroy(JSCell*);
 102 static void visitChildren(JSCell*, SlotVisitor&);
 103
 104 static size_t offsetOfCallees()
 105 {
 106 return WTF::roundUpToMultipleOf<sizeof(WriteBarrier<JSWebAssemblyCallee>)>(sizeof(JSWebAssemblyCodeBlock));
 107 }
 108
 109 static size_t allocationSize(unsigned numCallees)
 110 {
 111 return offsetOfCallees() + sizeof(WriteBarrier<JSWebAssemblyCallee>) * numCallees * 2;
 112 }
 113
 114 class UnconditionalFinalizer : public JSC::UnconditionalFinalizer {
 115 void finalizeUnconditionally() override;
 116 };
 117
 118 WriteBarrier<JSWebAssemblyModule> m_module;
 119 UnconditionalFinalizer m_unconditionalFinalizer;
 120 Bag<CallLinkInfo> m_callLinkInfos;
 121 Vector<Wasm::WasmExitStubs> m_wasmExitStubs;
 122 Wasm::Memory::Mode m_mode;
 123 unsigned m_calleeCount;
 124};
 125
 126} // namespace JSC
 127
 128#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

@@public:
207207
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);
212213

@@B3IRGenerator::B3IRGenerator(VM& vm, const ModuleInformation& info, Procedure& p
259260 for (const PinnedSizeRegisterInfo& regInfo : pinnedRegs.sizeRegisters)
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);
265266 ASSERT_UNUSED(pinnedGPR, m_memorySizeGPR == pinnedGPR);

@@static MemoryBaseAndSize getMemoryBaseAndSize(VM& vm, Value* instance, Procedure
282283{
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());
289290 result.size = block->appendNew<MemoryValue>(proc, Load, Int64, Origin(), memoryObject, JSWebAssemblyMemory::offsetOfSize());

@@auto B3IRGenerator::setGlobal(uint32_t index, ExpressionType value) -> PartialRe
454455
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);
462466}

@@inline uint32_t sizeOfLoadOp(LoadOpType op)
486490 RELEASE_ASSERT_NOT_REACHED();
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
544555 // FIXME: B3 doesn't support Load16Z yet. We should lower to that value when
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));
555566

@@inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, Expression
631642 FALLTHROUGH;
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
637648 case StoreOpType::I64Store16:

@@inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, Expression
639650 FALLTHROUGH;
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
645656 case StoreOpType::I64Store32:

@@inline void B3IRGenerator::emitStoreOp(StoreOpType op, Origin origin, Expression
650661 case StoreOpType::I32Store:
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 }
656667 RELEASE_ASSERT_NOT_REACHED();

Source/JavaScriptCore/wasm/WasmCallingConvention.h

4040#include "LinkBuffer.h"
4141#include "RegisterSet.h"
4242#include "WasmFormat.h"
 43#include "WasmSignature.h"
4344
4445namespace JSC { namespace Wasm {
4546

Source/JavaScriptCore/wasm/WasmFaultSignalHandler.cpp

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "WasmFaultSignalHandler.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "ExecutableAllocator.h"
 32#include "VM.h"
 33#include "WasmExceptionType.h"
 34
 35#include <wtf/Lock.h>
 36#include <wtf/NeverDestroyed.h>
 37
 38namespace JSC { namespace Wasm {
 39
 40
 41namespace {
 42static const bool verbose = false;
 43}
 44
 45static struct sigaction oldSigBusHandler;
 46static bool fastHandlerInstalled { false };
 47static StaticLock codeLocationsLock;
 48static LazyNeverDestroyed<HashSet<std::tuple<VM*, void*, void*>>> codeLocations; // (vm, start, end)
 49
 50#if CPU(X86_64)
 51#define InstructionPointerGPR context->__ss.__rip
 52#define FirstArgumentGPR context->__ss.__rsi
 53#else
 54#define InstructionPointerGPR context->__ss.__pc
 55#define FirstArgumentGPR context->__ss.__x[1]
 56#endif
 57
 58static void trapHandler(int signal, siginfo_t*, void* ucontext)
 59{
 60 mcontext_t context = static_cast<ucontext_t*>(ucontext)->uc_mcontext;
 61 void* faultingInstruction = reinterpret_cast<void*>(InstructionPointerGPR);
 62 dataLogLnIf(verbose, "starting handler for fault at: ", RawPointer(faultingInstruction));
 63
 64 dataLogLnIf(verbose, "JIT memory start: ", RawPointer(reinterpret_cast<void*>(startOfFixedExecutableMemoryPool)), " end: ", RawPointer(reinterpret_cast<void*>(endOfFixedExecutableMemoryPool)));
 65 // First we need to make sure we are in JIT code before we can aquire any locks. Otherwise,
 66 // we might have crashed in code that is already holding one of the locks we want to aquire.
 67 if (reinterpret_cast<void*>(startOfFixedExecutableMemoryPool) <= faultingInstruction
 68 && faultingInstruction < reinterpret_cast<void*>(endOfFixedExecutableMemoryPool)) {
 69
 70 LockHolder locker(codeLocationsLock);
 71 for (auto range : codeLocations.get()) {
 72 VM* vm;
 73 void* start;
 74 void* end;
 75 std::tie(vm, start, end) = range;
 76 dataLogLnIf(verbose, "function start: ", RawPointer(start), " end: ", RawPointer(end));
 77 if (start <= faultingInstruction && faultingInstruction < end) {
 78 dataLogLnIf(verbose, "found match");
 79 MacroAssemblerCodeRef exceptionStub = vm->jitStubs->existingCTIStub(throwExceptionFromWasmThunkGenerator);
 80 // If for whatever reason we don't have a stub then we should just treat this like a regular crash.
 81 if (!exceptionStub)
 82 break;
 83 dataLogLnIf(verbose, "found stub: ", RawPointer(exceptionStub.code().executableAddress()));
 84 FirstArgumentGPR = static_cast<uint64_t>(ExceptionType::OutOfBoundsMemoryAccess);
 85 InstructionPointerGPR = reinterpret_cast<uint64_t>(exceptionStub.code().executableAddress());
 86 return;
 87 }
 88 }
 89 }
 90
 91 // Since we only use fast memory in processes we control, if we restore we will just fall back to the default handler.
 92 sigaction(signal, &oldSigBusHandler, nullptr);
 93}
 94
 95void registerCode(VM& vm, void* start, void* end)
 96{
 97 if (!fastMemoryEnabled())
 98 return;
 99 LockHolder locker(codeLocationsLock);
 100 codeLocations->add(std::make_tuple(&vm, start, end));
 101}
 102
 103void unregisterCode(VM& vm, void* start, void* end)
 104{
 105 if (!fastMemoryEnabled())
 106 return;
 107 LockHolder locker(codeLocationsLock);
 108 codeLocations->remove(std::make_tuple(&vm, start, end));
 109}
 110
 111bool fastMemoryEnabled()
 112{
 113 return fastHandlerInstalled;
 114}
 115
 116void enableFastMemory()
 117{
 118 static std::once_flag once;
 119 std::call_once(once, [] {
 120 if (!Options::useWebAssemblyFastMemory())
 121 return;
 122
 123 struct sigaction action;
 124
 125 action.sa_sigaction = trapHandler;
 126 sigfillset(&action.sa_mask);
 127 action.sa_flags = SA_SIGINFO;
 128
 129 if (!sigaction(SIGBUS, &action, &oldSigBusHandler)) {
 130 fastHandlerInstalled = true;
 131 codeLocations.construct();
 132 }
 133
 134 });
 135}
 136
 137} } // namespace JSC::Wasm
 138
 139#endif // ENABLE(WEBASSEMBLY)
 140

Source/JavaScriptCore/wasm/WasmFaultSignalHandler.h

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#if ENABLE(WEBASSEMBLY)
 27
 28namespace JSC {
 29
 30class VM;
 31
 32namespace Wasm {
 33
 34void registerCode(VM&, void* start, void* end);
 35void unregisterCode(VM&, void* start, void* end);
 36
 37bool fastMemoryEnabled();
 38JS_EXPORT_PRIVATE void enableFastMemory();
 39
 40} } // namespace JSC::Wasm
 41
 42#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/WasmFormat.h

@@struct ModuleInformation {
256256 }
257257
258258 uint32_t importFunctionCount() const { return importFunctionSignatureIndices.size(); }
259  bool hasMemory() const { return !!memory; }
260259
261260 ~ModuleInformation();
262261};

Source/JavaScriptCore/wasm/WasmMemory.cpp

2828
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>
3438

@@namespace {
3842const bool verbose = false;
3943}
4044
41 void Memory::dump(PrintStream& out) const
 45inline bool mmapBytes(size_t bytes, void*& memory)
4246{
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));
 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;
4657}
4758
48 const char* Memory::makeString(Mode mode) const
 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()
4964{
50  switch (mode) {
51  case Mode::BoundsChecking: return "BoundsChecking";
 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();
52114 }
53  RELEASE_ASSERT_NOT_REACHED();
54  return "";
 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;
55140}
56141
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.");
 142Memory::Memory(PageCount initial, PageCount maximum)
 143 : m_initial(initial)
 144 , m_maximum(maximum)
 145{
 146 ASSERT(!initial.bytes());
 147}
58148
59 Memory::Memory(PageCount initial, PageCount maximum, bool& failed)
60  : m_size(initial.bytes())
 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;
 179 RELEASE_ASSERT(!size);
 180 dataLogLnIf(verbose, "Memory::create allocating nothing");
 181 return makeEmptyMemory();
79182 }
80183
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;
94  }
 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 }
95197
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;
 198 if (!mmapBytes(mappedCapacity, memory)) {
 199 dataLogLnIf(verbose, "Memory::create mmap failed twice");
 200 return nullptr;
 201 }
102202 }
103203 }
104204
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);
 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();
 212 }
 213 return nullptr;
109214 }
 215
 216 lastAllocatedMemoryMode = mode;
 217 dataLogLnIf(verbose, "Memory::create mmap succeeded");
 218 return adoptRef(new Memory(memory, initial, maximum, mappedCapacity, mode));
 219}
110220
111  m_memory = result;
112  failed = false;
113  if (verbose)
114  dataLogLn("Memory::Memory mmap succeeded ", *this);
 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))
123241 CRASH();

@@bool Memory::grow(PageCount newSize)
128246{
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);
150270 if (newMemory == MAP_FAILED)

@@bool Memory::grow(PageCount newSize)
159279 m_mappedCapacity = desiredSize;
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
169304} // namespace Wasm

Source/JavaScriptCore/wasm/WasmMemory.h

2727
2828#if ENABLE(WEBASSEMBLY)
2929
30 #include "WasmCallingConvention.h"
3130#include "WasmPageCount.h"
3231
 32#include <wtf/Optional.h>
 33#include <wtf/RefCounted.h>
 34#include <wtf/RefPtr.h>
 35
3336namespace WTF {
3437class PrintStream;
3538}
3639
37 namespace JSC { namespace Wasm {
 40namespace JSC {
 41
 42class VM;
 43
 44namespace Wasm {
3845
39 class Memory {
 46class Memory : public RefCounted<Memory> {
4047 WTF_MAKE_NONCOPYABLE(Memory);
4148 WTF_MAKE_FAST_ALLOCATED;
4249public:
4350 void dump(WTF::PrintStream&) const;
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
7071 PageCount initial() const { return m_initial; }
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};
8895

Source/JavaScriptCore/wasm/WasmMemoryInformation.cpp

2929#if ENABLE(WEBASSEMBLY)
3030
3131#include "WasmCallingConvention.h"
 32#include "WasmMemory.h"
3233#include <wtf/NeverDestroyed.h>
3334
3435namespace JSC { namespace Wasm {

@@const PinnedRegisterInfo& PinnedRegisterInfo::get()
4849 Vector<unsigned> pinnedSizes = { 0 };
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))
5356 return;

@@PinnedRegisterInfo::PinnedRegisterInfo(Vector<PinnedSizeRegisterInfo>&& sizeRegi
7174{
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)
7780 , m_isImport(isImport)

@@MemoryInformation::MemoryInformation(PageCount initial, PageCount maximum, bool
7982 RELEASE_ASSERT(!!m_initial);
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
84100} } // namespace JSC::Wasm

Source/JavaScriptCore/wasm/WasmMemoryInformation.h

2828#if ENABLE(WEBASSEMBLY)
2929
3030#include "GPRInfo.h"
 31#include "WasmMemory.h"
3132#include "WasmPageCount.h"
 33#include <wtf/Ref.h>
3234#include <wtf/Vector.h>
3335
3436namespace JSC { namespace Wasm {

@@public:
5254 ASSERT(!*this);
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
6166 explicit operator bool() const { return !!m_initial; }
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};
6875

Source/JavaScriptCore/wasm/WasmModuleParser.cpp

@@auto ModuleParser::parseMemoryHelper(bool isImport) -> PartialResult
316316 ASSERT(initialPageCount);
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}
322322

Source/JavaScriptCore/wasm/WasmModuleParser.h

3030#include "WasmFormat.h"
3131#include "WasmOps.h"
3232#include "WasmParser.h"
 33#include <wtf/Optional.h>
3334#include <wtf/Vector.h>
3435
3536namespace JSC { namespace Wasm {

@@struct ModuleParserResult {
4344class ModuleParser : public Parser<ModuleParserResult> {
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 }
5452

@@private:
6866 PartialResult WARN_UNUSED_RETURN parseInitExpr(uint8_t&, uint64_t&, Type& initExprType);
6967
7068 ModuleParserResult m_result;
 69 std::optional<Memory::Mode> m_mode { std::nullopt };
7170 bool m_hasTable { false };
7271};
7372

Source/JavaScriptCore/wasm/WasmPlan.cpp

3535#include "WasmB3IRGenerator.h"
3636#include "WasmBinding.h"
3737#include "WasmCallingConvention.h"
 38#include "WasmFaultSignalHandler.h"
3839#include "WasmMemory.h"
3940#include "WasmModuleParser.h"
4041#include "WasmValidate.h"

@@Plan::Plan(VM* vm, const uint8_t* source, size_t sourceLength)
6162{
6263}
6364
64 bool Plan::parseAndValidateModule()
 65bool Plan::parseAndValidateModule(std::optional<Memory::Mode> recompileMode)
6566{
6667 MonotonicTime startTime;
6768 if (verbose || Options::reportCompileTimes())
6869 startTime = MonotonicTime::now();
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) {
7475 m_errorMessage = parseResult.error();

@@bool Plan::parseAndValidateModule()
109110// The reason this is OK is that we guarantee that the main thread doesn't continue until all threads
110111// that could touch its stack are done executing.
111112SUPPRESS_ASAN
112 void Plan::run()
 113void Plan::run(std::optional<Memory::Mode> recompileMode)
113114{
114  if (!parseAndValidateModule())
 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) {
118121 if (UNLIKELY(!vector.tryReserveCapacity(size))) {

Source/JavaScriptCore/wasm/WasmPlan.h

@@public:
4949 JS_EXPORT_PRIVATE Plan(VM*, const uint8_t*, size_t);
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*)>);
5757

@@public:
9292 return WTFMove(m_wasmExitStubs);
9393 }
9494
 95 Memory::Mode mode() const { return m_moduleInformation->memory.mode(); }
 96
9597private:
9698 std::unique_ptr<ModuleInformation> m_moduleInformation;
9799 Vector<FunctionLocationInBinary> m_functionLocationInBinary;

Source/JavaScriptCore/wasm/js/JSWebAssemblyCallee.cpp

2929#if ENABLE(WEBASSEMBLY)
3030
3131#include "JSCInlines.h"
 32#include "WasmFaultSignalHandler.h"
3233
3334namespace JSC {
3435

@@void JSWebAssemblyCallee::finishCreation(VM& vm, Wasm::Entrypoint&& entrypoint)
4344 Base::finishCreation(vm);
4445
4546 m_entrypoint = WTFMove(entrypoint);
 47 Wasm::registerCode(vm, m_entrypoint.compilation->codeRef().executableMemory()->start(), m_entrypoint.compilation->codeRef().executableMemory()->end());
4648}
4749
4850void JSWebAssemblyCallee::destroy(JSCell* cell)
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}
5356

Source/JavaScriptCore/wasm/js/JSWebAssemblyCodeBlock.cpp

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "JSWebAssemblyCodeBlock.h"
 28
 29#if ENABLE(WEBASSEMBLY)
 30
 31#include "JSCInlines.h"
 32#include "JSWebAssemblyMemory.h"
 33#include "JSWebAssemblyModule.h"
 34
 35namespace JSC {
 36
 37const ClassInfo JSWebAssemblyCodeBlock::s_info = { "WebAssemblyCodeBlock", nullptr, 0, CREATE_METHOD_TABLE(JSWebAssemblyCodeBlock) };
 38
 39JSWebAssemblyCodeBlock::JSWebAssemblyCodeBlock(VM& vm, JSWebAssemblyModule* owner, Bag<CallLinkInfo>&& callLinkInfos, Vector<Wasm::WasmExitStubs>&& wasmExitStubs, Wasm::Memory::Mode mode, unsigned calleeCount)
 40 : Base(vm, vm.webAssemblyCodeBlockStructure.get())
 41 , m_callLinkInfos(WTFMove(callLinkInfos))
 42 , m_wasmExitStubs(WTFMove(wasmExitStubs))
 43 , m_mode(mode)
 44 , m_calleeCount(calleeCount)
 45{
 46 m_module.set(vm, this, owner);
 47 memset(callees(), 0, m_calleeCount * sizeof(WriteBarrier<JSWebAssemblyCallee>) * 2);
 48}
 49
 50void JSWebAssemblyCodeBlock::destroy(JSCell* cell)
 51{
 52 static_cast<JSWebAssemblyCodeBlock*>(cell)->JSWebAssemblyCodeBlock::~JSWebAssemblyCodeBlock();
 53}
 54
 55bool JSWebAssemblyCodeBlock::isSafeToRun(JSWebAssemblyMemory* memory)
 56{
 57 if (mode() == Wasm::Memory::Signaling)
 58 return memory->memory().mode() == mode();
 59 return true;
 60}
 61
 62void JSWebAssemblyCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
 63{
 64 JSWebAssemblyCodeBlock* thisObject = jsCast<JSWebAssemblyCodeBlock*>(cell);
 65 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
 66
 67 Base::visitChildren(thisObject, visitor);
 68 visitor.append(thisObject->m_module);
 69 for (unsigned i = 0; i < thisObject->m_calleeCount * 2; i++)
 70 visitor.append(thisObject->callees()[i]);
 71
 72 visitor.addUnconditionalFinalizer(&thisObject->m_unconditionalFinalizer);
 73}
 74
 75void JSWebAssemblyCodeBlock::UnconditionalFinalizer::finalizeUnconditionally()
 76{
 77 JSWebAssemblyCodeBlock* thisObject = bitwise_cast<JSWebAssemblyCodeBlock*>(
 78 bitwise_cast<char*>(this) - OBJECT_OFFSETOF(JSWebAssemblyCodeBlock, m_unconditionalFinalizer));
 79 for (auto iter = thisObject->m_callLinkInfos.begin(); !!iter; ++iter)
 80 (*iter)->visitWeak(*thisObject->vm());
 81}
 82
 83} // namespace JSC
 84
 85#endif // ENABLE(WEBASSEMBLY)

Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

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
55 * modification, are permitted provided that the following conditions

3838
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{
4355 // FIXME: These objects could be pretty big we should try to throw OOM here.

@@void JSWebAssemblyInstance::finishCreation(VM& vm, JSWebAssemblyModule* module,
6779 m_globals = MallocPtr<uint64_t>::malloc(extraMemorySize);
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);
7385}

@@void JSWebAssemblyInstance::visitChildren(JSCell* cell, SlotVisitor& visitor)
8395 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
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);
89101 visitor.append(thisObject->m_table);

Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h

2929
3030#include "JSDestructibleObject.h"
3131#include "JSObject.h"
 32#include "JSWebAssemblyCodeBlock.h"
3233#include "JSWebAssemblyMemory.h"
3334#include "JSWebAssemblyTable.h"
3435

@@public:
4748
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
5663 WriteBarrier<JSCell>* importFunction(unsigned idx)

@@public:
7077 }
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(); }
7685 void setTable(VM& vm, JSWebAssemblyTable* table) { m_table.set(vm, this, table); }

@@protected:
104113 }
105114
106115private:
107  WriteBarrier<JSWebAssemblyModule> m_module;
 116 WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
108117 WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
109118 WriteBarrier<JSWebAssemblyMemory> m_memory;
110119 WriteBarrier<JSWebAssemblyTable> m_table;

Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.cpp

@@namespace JSC {
3737
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;
4546}

@@Structure* JSWebAssemblyMemory::createStructure(VM& vm, JSGlobalObject* globalOb
4950 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
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
5862JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)

@@JSArrayBuffer* JSWebAssemblyMemory::buffer(VM& vm, JSGlobalObject* globalObject)
6064 if (m_bufferWrapper)
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);
7173 return m_bufferWrapper.get();

@@Wasm::PageCount JSWebAssemblyMemory::grow(ExecState* exec, uint32_t delta, bool
7678 VM& vm = exec->vm();
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)) {
8284 if (shouldThrowExceptionsOnFailure)

@@Wasm::PageCount JSWebAssemblyMemory::grow(ExecState* exec, uint32_t delta, bool
9294 }
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
103109 // We need to clear out the old array buffer because it might now be pointing

@@Wasm::PageCount JSWebAssemblyMemory::grow(ExecState* exec, uint32_t delta, bool
110116 m_bufferWrapper.clear();
111117 }
112118
 119 memory().check();
113120 return oldPageCount;
114121}
115122

@@void JSWebAssemblyMemory::destroy(JSCell* cell)
123130{
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();
135135}

Source/JavaScriptCore/wasm/js/JSWebAssemblyMemory.h

@@class JSWebAssemblyMemory : public JSDestructibleObject {
4141public:
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;
6567};

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.cpp

3030
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
3741namespace JSC {
3842
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}
4775

@@Structure* JSWebAssemblyModule::createStructure(VM& vm, JSGlobalObject* globalOb
5078 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
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
70138void JSWebAssemblyModule::destroy(JSCell* cell)

@@void JSWebAssemblyModule::visitChildren(JSCell* cell, SlotVisitor& visitor)
79147
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
96154} // namespace JSC

Source/JavaScriptCore/wasm/js/JSWebAssemblyModule.h

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
55 * modification, are permitted provided that the following conditions

2929
3030#include "JSDestructibleObject.h"
3131#include "JSObject.h"
32 #include "JSWebAssemblyCallee.h"
 32#include "JSWebAssemblyCodeBlock.h"
3333#include "UnconditionalFinalizer.h"
3434#include "WasmFormat.h"
3535#include <wtf/Bag.h>

3737
3838namespace JSC {
3939
 40namespace Wasm {
 41class Plan;
 42}
 43
4044class SymbolTable;
 45class JSWebAssemblyMemory;
4146
4247class JSWebAssemblyModule : public JSDestructibleObject {
4348public:
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
4954 DECLARE_INFO;
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
5460 {
5561 return m_moduleInformation->signatureIndexFromFunctionIndexSpace(functionIndexSpace);
5662 }
57  unsigned functionImportCount() const { return m_wasmExitStubs.size(); }
58 
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  }
66 
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  }
74 
75  void setJSEntrypointCallee(VM& vm, unsigned calleeIndex, JSWebAssemblyCallee* callee)
76  {
77  RELEASE_ASSERT(calleeIndex < m_calleeCount);
78  callees()[calleeIndex].set(vm, this, callee);
79  }
8063
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  }
 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*);
8668
87  WriteBarrier<JSWebAssemblyCallee>* callees()
88  {
89  return bitwise_cast<WriteBarrier<JSWebAssemblyCallee>*>(bitwise_cast<char*>(this) + offsetOfCallees());
90  }
 69private:
 70 JSWebAssemblyCodeBlock* buildCodeBlock(VM&, ExecState*, Wasm::Plan&, std::optional<Wasm::Memory::Mode> mode = std::nullopt);
9171
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
12183} // namespace JSC

Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp

@@static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
5656 Wasm::SignatureIndex signatureIndex = wasmFunction->signatureIndex();
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.
6163

Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
8484
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.
9490 // Let imports be an initially-empty list of external values.

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
178174 return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import is not an instance of WebAssembly.Memory"))));
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(
189185 throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import did not have a 'maximum' but the module requires that it does"))));

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
194190 throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory imports 'maximum' is larger than the module's expected 'maximum'"))));
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 }
202200 case Wasm::ExternalKind::Global: {

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
235233 if (moduleInformation.memory && !hasMemoryImport) {
236234 RELEASE_ASSERT(!moduleInformation.memory.isImport());
237235 // We create a memory when it's a memory definition.
238  bool failed;
239  Wasm::Memory memory(moduleInformation.memory.initial(), moduleInformation.memory.maximum(), failed);
240  if (failed)
241  return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
242  instance->setMemory(vm,
243  JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory)));
 236 RefPtr<Wasm::Memory> memory;
 237 if (moduleInformation.memory.hasReservedMemory())
 238 memory = jsModule->takeReservedMemory();
 239 else {
 240 memory = Wasm::Memory::create(vm, moduleInformation.memory.initial(), moduleInformation.memory.maximum());
 241 if (!memory)
 242 return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec)));
 243 }
 244 instance->setMemory(vm, exec,
 245 JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), memory.releaseNonNull()));
 246 RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
244247 }
245248 }
246249

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
263266 }
264267 }
265268
 269 if (!instance->memory()) {
 270 // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
 271 instance->setMemory(vm, exec, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), adoptRef(*(new Wasm::Memory()))));
 272 }
 273
266274 // Globals
267275 {
268276 ASSERT(numImportGlobals == moduleInformation.firstInternalGlobal);

Source/JavaScriptCore/wasm/js/WebAssemblyMemoryConstructor.cpp

@@static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyMemory(ExecState* exec
9696 }
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
107106static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyMemory(ExecState* state)

Source/JavaScriptCore/wasm/js/WebAssemblyModuleConstructor.cpp

@@JSValue WebAssemblyModuleConstructor::createModule(ExecState* state, Structure*
8080 uint8_t* base = getWasmBufferFromValue(state, state->argument(0), byteOffset, byteSize);
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
11087WebAssemblyModuleConstructor* WebAssemblyModuleConstructor::create(VM& vm, Structure* structure, WebAssemblyModulePrototype* thisPrototype)

Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

@@void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
9292 auto* globalObject = state->lexicalGlobalObject();
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
101102

@@void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
116117 // a. Let func be an Exported Function Exotic Object created from c.
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);
123124 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);

@@void WebAssemblyModuleRecord::link(ExecState* state, JSWebAssemblyInstance* inst
178179 // The start function must not take any arguments or return anything. This is enforced by the parser.
179180 ASSERT(!signature->argumentCount());
180181 ASSERT(signature->returnType() == Wasm::Void);
181  if (startFunctionIndexSpace < module->functionImportCount()) {
 182 if (startFunctionIndexSpace < codeBlock->functionImportCount()) {
182183 JSCell* startFunction = instance->importFunction(startFunctionIndexSpace)->get();
183184 m_startFunction.set(vm, this, startFunction);
184185 } else {
185  JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
186  JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
 186 JSWebAssemblyCallee* jsEntrypointCallee = codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
 187 JSWebAssemblyCallee* wasmEntrypointCallee = codeBlock->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
187188 WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->argumentCount(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signatureIndex);
188189 m_startFunction.set(vm, this, function);
189190 }

@@JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
207208
208209 {
209210 JSWebAssemblyModule* module = m_instance->module();
 211 JSWebAssemblyCodeBlock* codeBlock = m_instance->codeBlock();
210212 const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
211213 JSWebAssemblyTable* table = m_instance->table();
212214 for (const Wasm::Element& element : moduleInformation.elements) {

@@JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
229231 // for the import.
230232 // https://bugs.webkit.org/show_bug.cgi?id=165510
231233 uint32_t functionIndex = element.functionIndices[i];
232  if (functionIndex < module->functionImportCount()) {
 234 if (functionIndex < codeBlock->functionImportCount()) {
233235 return JSValue::decode(
234236 throwVMRangeError(state, scope, ASCIILiteral("Element is setting the table value with an import. This is not yet implemented. FIXME.")));
235237 }
236238
237  JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
238  JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
 239 JSWebAssemblyCallee* jsEntrypointCallee = codeBlock->jsEntrypointCalleeFromFunctionIndexSpace(functionIndex);
 240 JSWebAssemblyCallee* wasmEntrypointCallee = codeBlock->wasmEntrypointCalleeFromFunctionIndexSpace(functionIndex);
239241 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
240242 const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, signatureIndex);
241243 // FIXME: Say we export local function "foo" at funciton index 0.

@@JSValue WebAssemblyModuleRecord::evaluate(ExecState* state)
255257 const Vector<Wasm::Segment::Ptr>& data = m_instance->module()->moduleInformation().data;
256258 JSWebAssemblyMemory* jsMemory = m_instance->memory();
257259 if (!data.isEmpty()) {
258  uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory()->memory());
259  uint64_t sizeInBytes = jsMemory->memory()->size();
 260 uint8_t* memory = reinterpret_cast<uint8_t*>(jsMemory->memory().memory());
 261 uint64_t sizeInBytes = jsMemory->memory().size();
260262 for (auto& segment : data) {
261263 if (segment->sizeInBytes) {
262264 uint32_t offset;

Source/WTF/wtf/DataLog.h

@@void dataLog(const Types&... values)
4848template<typename... Types>
4949void dataLogLn(const Types&... values)
5050{
51  dataFile().print(values..., "\n");
 51 dataLog(values..., "\n");
 52}
 53
 54template<typename... Types>
 55void dataLogIf(bool shouldLog, const Types&... values)
 56{
 57 if (shouldLog)
 58 dataLog(values...);
 59}
 60
 61template<typename... Types>
 62void dataLogLnIf(bool shouldLog, const Types&... values)
 63{
 64 if (shouldLog)
 65 dataLogLn(values...);
5266}
5367
5468} // namespace WTF
5569
5670using WTF::dataLog;
5771using WTF::dataLogLn;
 72using WTF::dataLogIf;
 73using WTF::dataLogLnIf;
5874using WTF::dataLogF;
5975using WTF::dataLogFString;
6076

Source/WTF/wtf/Ref.h

@@public:
137137 T* ptr() const { ASSERT(m_ptr); return m_ptr; }
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;
142143