1/*
2 * Copyright (C) 2017-2018 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 "MacroAssemblerCodeRef.h"
31#include "WasmEmbedder.h"
32#include "WasmTierUpCount.h"
33#include <wtf/Lock.h>
34#include <wtf/RefPtr.h>
35#include <wtf/SharedTask.h>
36#include <wtf/ThreadSafeRefCounted.h>
37#include <wtf/text/WTFString.h>
38
39namespace JSC {
40
41namespace Wasm {
42
43class Callee;
44struct Context;
45class BBQPlan;
46class OMGPlan;
47struct ModuleInformation;
48struct UnlinkedWasmToWasmCall;
49enum class MemoryMode : uint8_t;
50
51class CodeBlock : public ThreadSafeRefCounted<CodeBlock> {
52public:
53 typedef void CallbackType(Ref<CodeBlock>&&);
54 using AsyncCompilationCallback = RefPtr<WTF::SharedTask<CallbackType>>;
55 static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
56
57 void waitUntilFinished();
58 void compileAsync(Context*, AsyncCompilationCallback&&);
59
60 bool compilationFinished()
61 {
62 return m_compilationFinished.load();
63 }
64 bool runnable() { return compilationFinished() && !m_errorMessage; }
65
66 // Note, we do this copy to ensure it's thread safe to have this
67 // called from multiple threads simultaneously.
68 String errorMessage()
69 {
70 ASSERT(!runnable());
71 CString cString = m_errorMessage.ascii();
72 return String(cString.data());
73 }
74
75 unsigned functionImportCount() const { return m_wasmToWasmExitStubs.size(); }
76
77 // These two callee getters are only valid once the callees have been populated.
78
79 Callee& embedderEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
80 {
81 ASSERT(runnable());
82 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
83 unsigned calleeIndex = functionIndexSpace - functionImportCount();
84
85 auto callee = m_embedderCallees.get(calleeIndex);
86 RELEASE_ASSERT(callee);
87 return *callee;
88 }
89 Callee& wasmEntrypointCalleeFromFunctionIndexSpace(unsigned functionIndexSpace)
90 {
91 ASSERT(runnable());
92 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
93 unsigned calleeIndex = functionIndexSpace - functionImportCount();
94 if (m_optimizedCallees[calleeIndex])
95 return *m_optimizedCallees[calleeIndex].get();
96 return *m_callees[calleeIndex].get();
97 }
98
99 MacroAssemblerCodePtr<WasmEntryPtrTag>* entrypointLoadLocationFromFunctionIndexSpace(unsigned functionIndexSpace)
100 {
101 RELEASE_ASSERT(functionIndexSpace >= functionImportCount());
102 unsigned calleeIndex = functionIndexSpace - functionImportCount();
103 return &m_wasmIndirectCallEntryPoints[calleeIndex];
104 }
105
106 TierUpCount& tierUpCount(uint32_t functionIndex)
107 {
108 return m_tierUpCounts[functionIndex];
109 }
110
111 bool isSafeToRun(MemoryMode);
112
113 MemoryMode mode() const { return m_mode; }
114
115 ~CodeBlock();
116private:
117 friend class OMGPlan;
118
119 CodeBlock(Context*, MemoryMode, ModuleInformation&, CreateEmbedderWrapper&&, ThrowWasmException);
120 void setCompilationFinished();
121 unsigned m_calleeCount;
122 MemoryMode m_mode;
123 Vector<RefPtr<Callee>> m_callees;
124 Vector<RefPtr<Callee>> m_optimizedCallees;
125 HashMap<uint32_t, RefPtr<Callee>, typename DefaultHash<uint32_t>::Hash, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>> m_embedderCallees;
126 Vector<MacroAssemblerCodePtr<WasmEntryPtrTag>> m_wasmIndirectCallEntryPoints;
127 Vector<TierUpCount> m_tierUpCounts;
128 Vector<Vector<UnlinkedWasmToWasmCall>> m_wasmToWasmCallsites;
129 Vector<MacroAssemblerCodeRef<WasmEntryPtrTag>> m_wasmToWasmExitStubs;
130 RefPtr<BBQPlan> m_plan;
131 std::atomic<bool> m_compilationFinished { false };
132 String m_errorMessage;
133 Lock m_lock;
134};
135
136} } // namespace JSC::Wasm
137
138#endif // ENABLE(WEBASSEMBLY)
139