2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #if ENABLE(WEBASSEMBLY)
31 #include "B3Compilation.h"
32 #include "JSCInlines.h"
33 #include "JSGlobalObject.h"
34 #include "JSWebAssemblyCallee.h"
35 #include "WasmB3IRGenerator.h"
36 #include "WasmBinding.h"
37 #include "WasmCallingConvention.h"
38 #include "WasmMemory.h"
39 #include "WasmModuleParser.h"
40 #include "WasmValidate.h"
41 #include <wtf/DataLog.h>
42 #include <wtf/StdLibExtras.h>
43 #include <wtf/text/StringBuilder.h>
45 namespace JSC { namespace Wasm {
47 static const bool verbose = false;
49 Plan::Plan(VM* vm, Vector<uint8_t> source)
50 : Plan(vm, source.data(), source.size())
54 Plan::Plan(VM* vm, const uint8_t* source, size_t sourceLength)
57 , m_sourceLength(sourceLength)
64 dataLogLn("Starting plan.");
66 ModuleParser moduleParser(m_vm, m_source, m_sourceLength);
67 if (!moduleParser.parse()) {
69 dataLogLn("Parsing module failed: ", moduleParser.errorMessage());
70 m_errorMessage = moduleParser.errorMessage();
73 m_moduleInformation = WTFMove(moduleParser.moduleInformation());
74 m_functionLocationInBinary = WTFMove(moduleParser.functionLocationInBinary());
75 m_functionIndexSpace.size = moduleParser.functionIndexSpace().size();
76 m_functionIndexSpace.buffer = moduleParser.functionIndexSpace().releaseBuffer();
79 dataLogLn("Parsed module.");
81 auto tryReserveCapacity = [this] (auto& vector, size_t size, const char* what) {
82 if (UNLIKELY(!vector.tryReserveCapacity(size))) {
83 StringBuilder builder;
84 builder.appendLiteral("Failed allocating enough space for ");
85 builder.appendNumber(size);
87 m_errorMessage = builder.toString();
92 Vector<Vector<UnlinkedWasmToWasmCall>> unlinkedWasmToWasmCalls;
93 if (!tryReserveCapacity(m_wasmToJSStubs, m_moduleInformation->importFunctions.size(), " WebAssembly to JavaScript stubs")
94 || !tryReserveCapacity(unlinkedWasmToWasmCalls, m_functionLocationInBinary.size(), " unlinked WebAssembly to WebAssembly calls")
95 || !tryReserveCapacity(m_wasmInternalFunctions, m_functionLocationInBinary.size(), " WebAssembly functions"))
98 for (unsigned importIndex = 0; importIndex < m_moduleInformation->imports.size(); ++importIndex) {
99 Import* import = &m_moduleInformation->imports[importIndex];
100 if (import->kind != External::Function)
102 unsigned importFunctionIndex = m_wasmToJSStubs.size();
104 dataLogLn("Processing import function number ", importFunctionIndex, ": ", import->module, ": ", import->field);
105 Signature* signature = m_moduleInformation->importFunctions.at(import->kindIndex);
106 m_wasmToJSStubs.uncheckedAppend(importStubGenerator(m_vm, m_callLinkInfos, signature, importFunctionIndex));
107 m_functionIndexSpace.buffer.get()[importFunctionIndex].code = m_wasmToJSStubs[importFunctionIndex].code().executableAddress();
110 for (unsigned functionIndex = 0; functionIndex < m_functionLocationInBinary.size(); ++functionIndex) {
112 dataLogLn("Processing function starting at: ", m_functionLocationInBinary[functionIndex].start, " and ending at: ", m_functionLocationInBinary[functionIndex].end);
113 const uint8_t* functionStart = m_source + m_functionLocationInBinary[functionIndex].start;
114 size_t functionLength = m_functionLocationInBinary[functionIndex].end - m_functionLocationInBinary[functionIndex].start;
115 ASSERT(functionLength <= m_sourceLength);
116 Signature* signature = m_moduleInformation->internalFunctionSignatures[functionIndex];
117 unsigned functionIndexSpace = m_wasmToJSStubs.size() + functionIndex;
118 ASSERT(m_functionIndexSpace.buffer.get()[functionIndexSpace].signature == signature);
120 String error = validateFunction(functionStart, functionLength, signature, m_functionIndexSpace, *m_moduleInformation);
121 if (!error.isNull()) {
123 for (unsigned i = 0; i < functionLength; ++i)
124 dataLog(RawPointer(reinterpret_cast<void*>(functionStart[i])), ", ");
127 m_errorMessage = error;
131 unlinkedWasmToWasmCalls.uncheckedAppend(Vector<UnlinkedWasmToWasmCall>());
132 m_wasmInternalFunctions.uncheckedAppend(parseAndCompile(*m_vm, functionStart, functionLength, signature, unlinkedWasmToWasmCalls.at(functionIndex), m_functionIndexSpace, *m_moduleInformation));
133 m_functionIndexSpace.buffer.get()[functionIndexSpace].code = m_wasmInternalFunctions[functionIndex]->code->code().executableAddress();
136 // Patch the call sites for each WebAssembly function.
137 for (auto& unlinked : unlinkedWasmToWasmCalls) {
138 for (auto& call : unlinked)
139 MacroAssembler::repatchCall(call.callLocation, CodeLocationLabel(m_functionIndexSpace.buffer.get()[call.functionIndex].code));
145 void Plan::initializeCallees(JSGlobalObject* globalObject, std::function<void(unsigned, JSWebAssemblyCallee*)> callback)
148 for (unsigned internalFunctionIndex = 0; internalFunctionIndex < m_wasmInternalFunctions.size(); ++internalFunctionIndex) {
149 WasmInternalFunction* function = m_wasmInternalFunctions[internalFunctionIndex].get();
150 CodeLocationDataLabelPtr calleeMoveLocation = function->calleeMoveLocation;
151 JSWebAssemblyCallee* callee = JSWebAssemblyCallee::create(globalObject->vm(), WTFMove(function->code), WTFMove(function->jsToWasmEntryPoint));
153 MacroAssembler::repatchPointer(calleeMoveLocation, callee);
156 dataLogLn("Made Wasm callee: ", RawPointer(callee));
158 callback(internalFunctionIndex, callee);
164 } } // namespace JSC::Wasm
166 #endif // ENABLE(WEBASSEMBLY)