CodeOrigin.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 "CodeOrigin.h" 28 29 #include "CodeBlock.h" 30 #include "InlineCallFrame.h" 31 32 namespace JSC { 33 34 unsigned CodeOrigin::inlineDepth() const 35 { 36 unsigned result = 1; 37 for (InlineCallFrame* current = inlineCallFrame(); current; current = current->directCaller.inlineCallFrame()) 38 result++; 39 return result; 40 } 41 42 bool CodeOrigin::isApproximatelyEqualTo(const CodeOrigin& other, InlineCallFrame* terminal) const 43 { 44 CodeOrigin a = *this; 45 CodeOrigin b = other; 46 47 if (!a.isSet()) 48 return !b.isSet(); 49 if (!b.isSet()) 50 return false; 51 52 if (a.isHashTableDeletedValue()) 53 return b.isHashTableDeletedValue(); 54 if (b.isHashTableDeletedValue()) 55 return false; 56 57 for (;;) { 58 ASSERT(a.isSet()); 59 ASSERT(b.isSet()); 60 61 if (a.bytecodeIndex() != b.bytecodeIndex()) 62 return false; 63 64 auto* aInlineCallFrame = a.inlineCallFrame(); 65 auto* bInlineCallFrame = b.inlineCallFrame(); 66 bool aHasInlineCallFrame = !!aInlineCallFrame && aInlineCallFrame != terminal; 67 bool bHasInlineCallFrame = !!bInlineCallFrame; 68 if (aHasInlineCallFrame != bHasInlineCallFrame) 69 return false; 70 71 if (!aHasInlineCallFrame) 72 return true; 73 74 if (aInlineCallFrame->baselineCodeBlock.get() != bInlineCallFrame->baselineCodeBlock.get()) 75 return false; 76 77 a = aInlineCallFrame->directCaller; 78 b = bInlineCallFrame->directCaller; 79 } 80 } 81 82 unsigned CodeOrigin::approximateHash(InlineCallFrame* terminal) const 83 { 84 if (!isSet()) 85 return 0; 86 if (isHashTableDeletedValue()) 87 return 1; 88 89 unsigned result = 2; 90 CodeOrigin codeOrigin = *this; 91 for (;;) { 92 result += codeOrigin.bytecodeIndex().asBits(); 93 94 auto* inlineCallFrame = codeOrigin.inlineCallFrame(); 95 96 if (!inlineCallFrame) 97 return result; 98 99 if (inlineCallFrame == terminal) 100 return result; 101 102 result += WTF::PtrHash<JSCell*>::hash(inlineCallFrame->baselineCodeBlock.get()); 103 104 codeOrigin = inlineCallFrame->directCaller; 105 } 106 } 107 108 Vector<CodeOrigin> CodeOrigin::inlineStack() const 109 { 110 Vector<CodeOrigin> result(inlineDepth()); 111 result.last() = *this; 112 unsigned index = result.size() - 2; 113 for (InlineCallFrame* current = inlineCallFrame(); current; current = current->directCaller.inlineCallFrame()) 114 result[index--] = current->directCaller; 115 RELEASE_ASSERT(!result[0].inlineCallFrame()); 116 return result; 117 } 118 119 CodeBlock* CodeOrigin::codeOriginOwner() const 120 { 121 auto* inlineCallFrame = this->inlineCallFrame(); 122 if (!inlineCallFrame) 123 return nullptr; 124 return inlineCallFrame->baselineCodeBlock.get(); 125 } 126 127 int CodeOrigin::stackOffset() const 128 { 129 auto* inlineCallFrame = this->inlineCallFrame(); 130 if (!inlineCallFrame) 131 return 0; 132 return inlineCallFrame->stackOffset; 133 } 134 135 void CodeOrigin::dump(PrintStream& out) const 136 { 137 if (!isSet()) { 138 out.print("<none>"); 139 return; 140 } 141 142 Vector<CodeOrigin> stack = inlineStack(); 143 for (unsigned i = 0; i < stack.size(); ++i) { 144 if (i) 145 out.print(" --> "); 146 147 if (InlineCallFrame* frame = stack[i].inlineCallFrame()) { 148 out.print(frame->briefFunctionInformation(), ":<", RawPointer(frame->baselineCodeBlock.get()), "> "); 149 if (frame->isClosureCall) 150 out.print("(closure) "); 151 } 152 153 out.print(stack[i].bytecodeIndex()); 154 } 155 } 156 157 void CodeOrigin::dumpInContext(PrintStream& out, DumpContext*) const 158 { 159 dump(out); 160 } 161 162 } // namespace JSC