blob: e3af5f2fc056d90832867410bc4f443681657d17 [file] [log] [blame]
fpizlo@apple.comc8eca232012-12-25 21:07:53 +00001/*
mark.lam@apple.com5ba07792019-08-27 22:14:52 +00002 * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
fpizlo@apple.comc8eca232012-12-25 21:07:53 +00003 *
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 "JITThunks.h"
28
29#if ENABLE(JIT)
30
fpizlo@apple.comc8eca232012-12-25 21:07:53 +000031#include "JIT.h"
fpizlo@apple.com595eebd2016-08-24 19:00:37 +000032#include "JSCInlines.h"
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +000033#include "LLIntData.h"
annulen@yandex.ru6712c2d2017-06-25 17:40:30 +000034#include "ThunkGenerators.h"
fpizlo@apple.combc16ddb2016-09-06 01:02:22 +000035#include "VM.h"
fpizlo@apple.comc8eca232012-12-25 21:07:53 +000036
37namespace JSC {
38
fpizlo@apple.com536df7c2013-01-07 23:49:29 +000039JITThunks::JITThunks()
fpizlo@apple.comc8eca232012-12-25 21:07:53 +000040{
fpizlo@apple.comc8eca232012-12-25 21:07:53 +000041}
42
43JITThunks::~JITThunks()
44{
45}
46
ysuzuki@apple.com5ae1a2c2020-02-17 22:58:49 +000047static inline NativeExecutable& getMayBeDyingNativeExecutable(const Weak<NativeExecutable>& weak)
48{
49 // This never gets Deleted / Empty slots.
50 WeakImpl* impl = weak.unsafeImpl();
51 ASSERT(impl);
52 // We have a callback removing entry when finalizing. This means that we never hold Deallocated entry in HashSet.
53 ASSERT(impl->state() != WeakImpl::State::Deallocated);
54 // Never use jsCast here. This is possible that this value is "Dead" but not "Finalized" yet. In this case,
55 // we can still access to non-JS data, as we are doing in a finalize callback.
56 auto* executable = static_cast<NativeExecutable*>(impl->jsValue().asCell());
57 ASSERT(executable);
58 return *executable;
59}
60
61inline unsigned JITThunks::WeakNativeExecutableHash::hash(NativeExecutable* executable)
62{
63 return hash(executable->function(), executable->constructor(), executable->name());
64}
65
66inline unsigned JITThunks::WeakNativeExecutableHash::hash(const Weak<NativeExecutable>& key)
67{
68 return hash(&getMayBeDyingNativeExecutable(key));
69}
70
71inline bool JITThunks::WeakNativeExecutableHash::equal(NativeExecutable& a, NativeExecutable& b)
72{
73 if (&a == &b)
74 return true;
75 return a.function() == b.function() && a.constructor() == b.constructor() && a.name() == b.name();
76}
77
78inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutable>& a, const Weak<NativeExecutable>& b)
79{
80 return equal(getMayBeDyingNativeExecutable(a), getMayBeDyingNativeExecutable(b));
81}
82
83inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutable>& a, NativeExecutable* bExecutable)
84{
85 return equal(getMayBeDyingNativeExecutable(a), *bExecutable);
86}
87
88inline bool JITThunks::WeakNativeExecutableHash::equal(const Weak<NativeExecutable>& a, const HostFunctionKey& b)
89{
90 auto& aExecutable = getMayBeDyingNativeExecutable(a);
91 return aExecutable.function() == std::get<0>(b) && aExecutable.constructor() == std::get<1>(b) && aExecutable.name() == std::get<2>(b);
92}
93
mark.lam@apple.com5ba07792019-08-27 22:14:52 +000094MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiNativeCall(VM& vm)
fpizlo@apple.com2ac511c2012-12-27 23:12:27 +000095{
mark.lam@apple.com2e81af72018-03-06 03:03:01 +000096 ASSERT(VM::canUseJIT());
commit-queue@webkit.org2cb9c252016-12-13 19:38:13 +000097 return ctiStub(vm, nativeCallGenerator).code();
fpizlo@apple.com2ac511c2012-12-27 23:12:27 +000098}
msaboff@apple.com95894332014-01-29 19:18:54 +000099
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000100MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiNativeConstruct(VM& vm)
fpizlo@apple.com2ac511c2012-12-27 23:12:27 +0000101{
mark.lam@apple.com2e81af72018-03-06 03:03:01 +0000102 ASSERT(VM::canUseJIT());
commit-queue@webkit.org2cb9c252016-12-13 19:38:13 +0000103 return ctiStub(vm, nativeConstructGenerator).code();
fpizlo@apple.com2ac511c2012-12-27 23:12:27 +0000104}
105
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000106MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiNativeTailCall(VM& vm)
msaboff@apple.com95894332014-01-29 19:18:54 +0000107{
utatane.tea@gmail.com6863b232017-12-17 19:35:38 +0000108 ASSERT(VM::canUseJIT());
msaboff@apple.com95894332014-01-29 19:18:54 +0000109 return ctiStub(vm, nativeTailCallGenerator).code();
110}
111
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000112MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiNativeTailCallWithoutSavedTags(VM& vm)
fpizlo@apple.comf41fc902016-04-23 02:00:38 +0000113{
utatane.tea@gmail.com6863b232017-12-17 19:35:38 +0000114 ASSERT(VM::canUseJIT());
fpizlo@apple.comf41fc902016-04-23 02:00:38 +0000115 return ctiStub(vm, nativeTailCallWithoutSavedTagsGenerator).code();
116}
117
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000118MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiInternalFunctionCall(VM& vm)
utatane.tea@gmail.com7ab015d2017-11-06 14:40:08 +0000119{
mark.lam@apple.com2e81af72018-03-06 03:03:01 +0000120 ASSERT(VM::canUseJIT());
utatane.tea@gmail.com7ab015d2017-11-06 14:40:08 +0000121 return ctiStub(vm, internalFunctionCallGenerator).code();
122}
123
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000124MacroAssemblerCodePtr<JITThunkPtrTag> JITThunks::ctiInternalFunctionConstruct(VM& vm)
utatane.tea@gmail.com7ab015d2017-11-06 14:40:08 +0000125{
mark.lam@apple.com2e81af72018-03-06 03:03:01 +0000126 ASSERT(VM::canUseJIT());
utatane.tea@gmail.com7ab015d2017-11-06 14:40:08 +0000127 return ctiStub(vm, internalFunctionConstructGenerator).code();
128}
129
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000130MacroAssemblerCodeRef<JITThunkPtrTag> JITThunks::ctiStub(VM& vm, ThunkGenerator generator)
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000131{
fpizlo@apple.comaa671292015-08-15 00:14:52 +0000132 LockHolder locker(m_lock);
mark.lam@apple.comde0dba72018-04-18 03:31:09 +0000133 CTIStubMap::AddResult entry = m_ctiStubMap.add(generator, MacroAssemblerCodeRef<JITThunkPtrTag>());
oliver@apple.comf5a934a2013-07-25 04:00:24 +0000134 if (entry.isNewEntry) {
135 // Compilation thread can only retrieve existing entries.
136 ASSERT(!isCompilationThread());
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +0000137 entry.iterator->value = generator(vm);
oliver@apple.comf5a934a2013-07-25 04:00:24 +0000138 }
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000139 return entry.iterator->value;
140}
141
mark.lam@apple.comde0dba72018-04-18 03:31:09 +0000142MacroAssemblerCodeRef<JITThunkPtrTag> JITThunks::existingCTIStub(ThunkGenerator generator)
keith_miller@apple.come3ecd6a2017-03-03 22:24:21 +0000143{
144 LockHolder locker(m_lock);
145 CTIStubMap::iterator entry = m_ctiStubMap.find(generator);
146 if (entry == m_ctiStubMap.end())
mark.lam@apple.comde0dba72018-04-18 03:31:09 +0000147 return MacroAssemblerCodeRef<JITThunkPtrTag>();
keith_miller@apple.come3ecd6a2017-03-03 22:24:21 +0000148 return entry->value;
149}
150
ysuzuki@apple.com5ae1a2c2020-02-17 22:58:49 +0000151struct JITThunks::HostKeySearcher {
152 static unsigned hash(const HostFunctionKey& key) { return WeakNativeExecutableHash::hash(key); }
153 static bool equal(const Weak<NativeExecutable>& a, const HostFunctionKey& b) { return WeakNativeExecutableHash::equal(a, b); }
154};
155
156struct JITThunks::NativeExecutableTranslator {
157 static unsigned hash(NativeExecutable* key) { return WeakNativeExecutableHash::hash(key); }
158 static bool equal(const Weak<NativeExecutable>& a, NativeExecutable* b) { return WeakNativeExecutableHash::equal(a, b); }
159 static void translate(Weak<NativeExecutable>& location, NativeExecutable* executable, unsigned)
160 {
161 location = Weak<NativeExecutable>(executable, executable->vm().jitStubs.get());
162 }
163};
164
commit-queue@webkit.orgd5d496b2015-09-22 12:21:31 +0000165void JITThunks::finalize(Handle<Unknown> handle, void*)
akling@apple.com47a5bfa2015-03-08 23:58:40 +0000166{
fpizlo@apple.come88e5982017-01-17 23:52:55 +0000167 auto* nativeExecutable = static_cast<NativeExecutable*>(handle.get().asCell());
ysuzuki@apple.com5ae1a2c2020-02-17 22:58:49 +0000168 auto hostFunctionKey = std::make_tuple(nativeExecutable->function(), nativeExecutable->constructor(), nativeExecutable->name());
169 {
170 DisallowGC disallowGC;
171 auto iterator = m_nativeExecutableSet.find<HostKeySearcher>(hostFunctionKey);
172 // Because this finalizer is called, this means that we still have dead Weak<> in m_nativeExecutableSet.
173 ASSERT(iterator != m_nativeExecutableSet.end());
174 ASSERT(iterator->unsafeImpl()->state() == WeakImpl::State::Finalized);
175 m_nativeExecutableSet.remove(iterator);
176 }
akling@apple.com47a5bfa2015-03-08 23:58:40 +0000177}
178
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000179NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, const String& name)
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000180{
utatane.tea@gmail.com0d74c7c2016-11-03 03:20:53 +0000181 return hostFunctionStub(vm, function, constructor, nullptr, NoIntrinsic, nullptr, name);
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000182}
183
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000184NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, TaggedNativeFunction constructor, ThunkGenerator generator, Intrinsic intrinsic, const DOMJIT::Signature* signature, const String& name)
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000185{
oliver@apple.comf5a934a2013-07-25 04:00:24 +0000186 ASSERT(!isCompilationThread());
utatane.tea@gmail.com6863b232017-12-17 19:35:38 +0000187 ASSERT(VM::canUseJIT());
oliver@apple.comf5a934a2013-07-25 04:00:24 +0000188
ysuzuki@apple.com5ae1a2c2020-02-17 22:58:49 +0000189 auto hostFunctionKey = std::make_tuple(function, constructor, name);
190 {
191 DisallowGC disallowGC;
192 auto iterator = m_nativeExecutableSet.find<HostKeySearcher>(hostFunctionKey);
193 if (iterator != m_nativeExecutableSet.end()) {
194 // It is possible that this returns Weak<> which is Dead, but not finalized.
195 // We should not use this reference to store value created in the subsequent sequence, since allocating NativeExecutable can cause GC, which changes this Set.
196 if (auto* executable = iterator->get())
197 return executable;
198 }
199 }
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000200
msaboff@apple.com95894332014-01-29 19:18:54 +0000201 RefPtr<JITCode> forCall;
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000202 if (generator) {
mark.lam@apple.comde0dba72018-04-18 03:31:09 +0000203 MacroAssemblerCodeRef<JSEntryPtrTag> entry = generator(vm).retagged<JSEntryPtrTag>();
sbarati@apple.com9777f7c2019-04-30 03:27:39 +0000204 forCall = adoptRef(new DirectJITCode(entry, entry.code(), JITType::HostCallThunk, intrinsic));
ysuzuki@apple.com6189a492019-02-06 19:49:04 +0000205 } else if (signature)
sbarati@apple.com9777f7c2019-04-30 03:27:39 +0000206 forCall = adoptRef(new NativeDOMJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeCall(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, intrinsic, signature));
ysuzuki@apple.com6189a492019-02-06 19:49:04 +0000207 else
sbarati@apple.com9777f7c2019-04-30 03:27:39 +0000208 forCall = adoptRef(new NativeJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeCall(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, intrinsic));
msaboff@apple.com95894332014-01-29 19:18:54 +0000209
sbarati@apple.com9777f7c2019-04-30 03:27:39 +0000210 Ref<JITCode> forConstruct = adoptRef(*new NativeJITCode(MacroAssemblerCodeRef<JSEntryPtrTag>::createSelfManagedCodeRef(ctiNativeConstruct(vm).retagged<JSEntryPtrTag>()), JITType::HostCallThunk, NoIntrinsic));
msaboff@apple.com95894332014-01-29 19:18:54 +0000211
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000212 NativeExecutable* nativeExecutable = NativeExecutable::create(vm, forCall.releaseNonNull(), function, WTFMove(forConstruct), constructor, name);
ysuzuki@apple.com5ae1a2c2020-02-17 22:58:49 +0000213 {
214 DisallowGC disallowGC;
215 auto addResult = m_nativeExecutableSet.add<NativeExecutableTranslator>(nativeExecutable);
216 if (!addResult.isNewEntry) {
217 // Override the existing Weak<NativeExecutable> with the new one since it is dead.
218 ASSERT(!*addResult.iterator);
219 *addResult.iterator = Weak<NativeExecutable>(nativeExecutable, this);
220 ASSERT(*addResult.iterator);
221#if ASSERT_ENABLED
222 auto iterator = m_nativeExecutableSet.find<HostKeySearcher>(hostFunctionKey);
223 ASSERT(iterator != m_nativeExecutableSet.end());
224 ASSERT(iterator->get() == nativeExecutable);
225 ASSERT(iterator->unsafeImpl()->state() == WeakImpl::State::Live);
226#endif
227 }
228 }
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000229 return nativeExecutable;
230}
231
mark.lam@apple.com5ba07792019-08-27 22:14:52 +0000232NativeExecutable* JITThunks::hostFunctionStub(VM& vm, TaggedNativeFunction function, ThunkGenerator generator, Intrinsic intrinsic, const String& name)
fpizlo@apple.comf41fc902016-04-23 02:00:38 +0000233{
utatane.tea@gmail.com0d74c7c2016-11-03 03:20:53 +0000234 return hostFunctionStub(vm, function, callHostFunctionAsConstructor, generator, intrinsic, nullptr, name);
fpizlo@apple.comf41fc902016-04-23 02:00:38 +0000235}
236
fpizlo@apple.comc8eca232012-12-25 21:07:53 +0000237} // namespace JSC
238
239#endif // ENABLE(JIT)