CallLinkInfo.cpp
1 /* 2 * Copyright (C) 2012-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 #include "config.h" 27 #include "CallLinkInfo.h" 28 29 #include "CallFrameShuffleData.h" 30 #include "FunctionCodeBlock.h" 31 #include "JSCellInlines.h" 32 #include "Opcode.h" 33 #include "Repatch.h" 34 #include <wtf/ListDump.h> 35 36 #if ENABLE(JIT) 37 namespace JSC { 38 39 CallLinkInfo::CallType CallLinkInfo::callTypeFor(OpcodeID opcodeID) 40 { 41 switch (opcodeID) { 42 case op_tail_call_varargs: 43 case op_tail_call_forward_arguments: 44 return TailCallVarargs; 45 46 case op_call: 47 case op_call_eval: 48 case op_iterator_open: 49 case op_iterator_next: 50 return Call; 51 52 case op_call_varargs: 53 return CallVarargs; 54 55 case op_construct: 56 return Construct; 57 58 case op_construct_varargs: 59 return ConstructVarargs; 60 61 case op_tail_call: 62 return TailCall; 63 64 default: 65 break; 66 } 67 RELEASE_ASSERT_NOT_REACHED(); 68 return Call; 69 } 70 71 CallLinkInfo::CallLinkInfo(CodeOrigin codeOrigin) 72 : m_codeOrigin(codeOrigin) 73 , m_hasSeenShouldRepatch(false) 74 , m_hasSeenClosure(false) 75 , m_clearedByGC(false) 76 , m_clearedByVirtual(false) 77 , m_allowStubs(true) 78 , m_clearedByJettison(false) 79 , m_callType(None) 80 { 81 } 82 83 CallLinkInfo::~CallLinkInfo() 84 { 85 clearStub(); 86 87 if (isOnList()) 88 remove(); 89 } 90 91 void CallLinkInfo::clearStub() 92 { 93 if (!stub()) 94 return; 95 96 m_stub->clearCallNodesFor(this); 97 m_stub = nullptr; 98 } 99 100 void CallLinkInfo::unlink(VM& vm) 101 { 102 // We could be called even if we're not linked anymore because of how polymorphic calls 103 // work. Each callsite within the polymorphic call stub may separately ask us to unlink(). 104 if (isLinked()) 105 unlinkFor(vm, *this); 106 107 // Either we were unlinked, in which case we should not have been on any list, or we unlinked 108 // ourselves so that we're not on any list anymore. 109 RELEASE_ASSERT(!isOnList()); 110 } 111 112 CodeLocationNearCall<JSInternalPtrTag> CallLinkInfo::callReturnLocation() 113 { 114 RELEASE_ASSERT(!isDirect()); 115 return CodeLocationNearCall<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump, NearCallMode::Regular); 116 } 117 118 CodeLocationJump<JSInternalPtrTag> CallLinkInfo::patchableJump() 119 { 120 RELEASE_ASSERT(callType() == DirectTailCall); 121 return CodeLocationJump<JSInternalPtrTag>(m_callReturnLocationOrPatchableJump); 122 } 123 124 CodeLocationDataLabelPtr<JSInternalPtrTag> CallLinkInfo::hotPathBegin() 125 { 126 RELEASE_ASSERT(!isDirect()); 127 return CodeLocationDataLabelPtr<JSInternalPtrTag>(m_hotPathBeginOrSlowPathStart); 128 } 129 130 CodeLocationLabel<JSInternalPtrTag> CallLinkInfo::slowPathStart() 131 { 132 RELEASE_ASSERT(isDirect()); 133 return m_hotPathBeginOrSlowPathStart; 134 } 135 136 void CallLinkInfo::setCallee(VM& vm, JSCell* owner, JSObject* callee) 137 { 138 RELEASE_ASSERT(!isDirect()); 139 m_calleeOrCodeBlock.set(vm, owner, callee); 140 } 141 142 void CallLinkInfo::clearCallee() 143 { 144 RELEASE_ASSERT(!isDirect()); 145 m_calleeOrCodeBlock.clear(); 146 } 147 148 JSObject* CallLinkInfo::callee() 149 { 150 RELEASE_ASSERT(!isDirect()); 151 return jsCast<JSObject*>(m_calleeOrCodeBlock.get()); 152 } 153 154 void CallLinkInfo::setCodeBlock(VM& vm, JSCell* owner, FunctionCodeBlock* codeBlock) 155 { 156 RELEASE_ASSERT(isDirect()); 157 m_calleeOrCodeBlock.setMayBeNull(vm, owner, codeBlock); 158 } 159 160 void CallLinkInfo::clearCodeBlock() 161 { 162 RELEASE_ASSERT(isDirect()); 163 m_calleeOrCodeBlock.clear(); 164 } 165 166 FunctionCodeBlock* CallLinkInfo::codeBlock() 167 { 168 RELEASE_ASSERT(isDirect()); 169 return jsCast<FunctionCodeBlock*>(m_calleeOrCodeBlock.get()); 170 } 171 172 void CallLinkInfo::setLastSeenCallee(VM& vm, const JSCell* owner, JSObject* callee) 173 { 174 RELEASE_ASSERT(!isDirect()); 175 m_lastSeenCalleeOrExecutable.set(vm, owner, callee); 176 } 177 178 void CallLinkInfo::clearLastSeenCallee() 179 { 180 RELEASE_ASSERT(!isDirect()); 181 m_lastSeenCalleeOrExecutable.clear(); 182 } 183 184 JSObject* CallLinkInfo::lastSeenCallee() const 185 { 186 RELEASE_ASSERT(!isDirect()); 187 return jsCast<JSObject*>(m_lastSeenCalleeOrExecutable.get()); 188 } 189 190 bool CallLinkInfo::haveLastSeenCallee() const 191 { 192 RELEASE_ASSERT(!isDirect()); 193 return !!m_lastSeenCalleeOrExecutable; 194 } 195 196 void CallLinkInfo::setExecutableDuringCompilation(ExecutableBase* executable) 197 { 198 RELEASE_ASSERT(isDirect()); 199 m_lastSeenCalleeOrExecutable.setWithoutWriteBarrier(executable); 200 } 201 202 ExecutableBase* CallLinkInfo::executable() 203 { 204 RELEASE_ASSERT(isDirect()); 205 return jsCast<ExecutableBase*>(m_lastSeenCalleeOrExecutable.get()); 206 } 207 208 void CallLinkInfo::setMaxArgumentCountIncludingThis(unsigned value) 209 { 210 RELEASE_ASSERT(isDirect()); 211 RELEASE_ASSERT(value); 212 m_maxArgumentCountIncludingThis = value; 213 } 214 215 void CallLinkInfo::visitWeak(VM& vm) 216 { 217 auto handleSpecificCallee = [&] (JSFunction* callee) { 218 if (vm.heap.isMarked(callee->executable())) 219 m_hasSeenClosure = true; 220 else 221 m_clearedByGC = true; 222 }; 223 224 if (isLinked()) { 225 if (stub()) { 226 if (!stub()->visitWeak(vm)) { 227 if (UNLIKELY(Options::verboseOSR())) { 228 dataLog( 229 "At ", m_codeOrigin, ", ", RawPointer(this), ": clearing call stub to ", 230 listDump(stub()->variants()), ", stub routine ", RawPointer(stub()), 231 ".\n"); 232 } 233 unlink(vm); 234 m_clearedByGC = true; 235 } 236 } else if (!vm.heap.isMarked(m_calleeOrCodeBlock.get())) { 237 if (isDirect()) { 238 if (UNLIKELY(Options::verboseOSR())) { 239 dataLog( 240 "Clearing call to ", RawPointer(codeBlock()), " (", 241 pointerDump(codeBlock()), ").\n"); 242 } 243 } else { 244 if (callee()->type() == JSFunctionType) { 245 if (UNLIKELY(Options::verboseOSR())) { 246 dataLog( 247 "Clearing call to ", 248 RawPointer(callee()), " (", 249 static_cast<JSFunction*>(callee())->executable()->hashFor(specializationKind()), 250 ").\n"); 251 } 252 handleSpecificCallee(static_cast<JSFunction*>(callee())); 253 } else { 254 if (UNLIKELY(Options::verboseOSR())) 255 dataLog("Clearing call to ", RawPointer(callee()), ".\n"); 256 m_clearedByGC = true; 257 } 258 } 259 unlink(vm); 260 } else if (isDirect() && !vm.heap.isMarked(m_lastSeenCalleeOrExecutable.get())) { 261 if (UNLIKELY(Options::verboseOSR())) { 262 dataLog( 263 "Clearing call to ", RawPointer(executable()), 264 " because the executable is dead.\n"); 265 } 266 unlink(vm); 267 // We should only get here once the owning CodeBlock is dying, since the executable must 268 // already be in the owner's weak references. 269 m_lastSeenCalleeOrExecutable.clear(); 270 } 271 } 272 if (!isDirect() && haveLastSeenCallee() && !vm.heap.isMarked(lastSeenCallee())) { 273 if (lastSeenCallee()->type() == JSFunctionType) 274 handleSpecificCallee(jsCast<JSFunction*>(lastSeenCallee())); 275 else 276 m_clearedByGC = true; 277 clearLastSeenCallee(); 278 } 279 } 280 281 void CallLinkInfo::setFrameShuffleData(const CallFrameShuffleData& shuffleData) 282 { 283 m_frameShuffleData = makeUnique<CallFrameShuffleData>(shuffleData); 284 } 285 286 } // namespace JSC 287 #endif // ENABLE(JIT) 288