1 | /* |
2 | * Copyright (C) 2014 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 | * |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
14 | * its contributors may be used to endorse or promote products derived |
15 | * from this software without specific prior written permission. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include "config.h" |
30 | #include "TypeProfilerLog.h" |
31 | |
32 | #include "JSCInlines.h" |
33 | #include "SlotVisitor.h" |
34 | #include "TypeLocation.h" |
35 | |
36 | |
37 | namespace JSC { |
38 | |
39 | namespace TypeProfilerLogInternal { |
40 | static const bool verbose = false; |
41 | } |
42 | |
43 | TypeProfilerLog::TypeProfilerLog(VM& vm) |
44 | : m_vm(vm) |
45 | , m_logSize(50000) |
46 | , m_logStartPtr(new LogEntry[m_logSize]) |
47 | , m_currentLogEntryPtr(m_logStartPtr) |
48 | , m_logEndPtr(m_logStartPtr + m_logSize) |
49 | { |
50 | ASSERT(m_logStartPtr); |
51 | } |
52 | |
53 | TypeProfilerLog::~TypeProfilerLog() |
54 | { |
55 | delete[] m_logStartPtr; |
56 | } |
57 | |
58 | void TypeProfilerLog::processLogEntries(VM& vm, const String& reason) |
59 | { |
60 | // We need to do this because this code will call into calculatedDisplayName. |
61 | // calculatedDisplayName will clear any exception it sees (because it thinks |
62 | // it's a stack overflow). We may be called when an exception was already |
63 | // thrown, so we don't want calcualtedDisplayName to clear that exception that |
64 | // was thrown before we even got here. |
65 | VM::DeferExceptionScope deferExceptionScope(vm); |
66 | |
67 | MonotonicTime before { }; |
68 | if (TypeProfilerLogInternal::verbose) { |
69 | dataLog("Process caller:'" , reason, "'" ); |
70 | before = MonotonicTime::now(); |
71 | } |
72 | |
73 | HashMap<Structure*, RefPtr<StructureShape>> cachedMonoProtoShapes; |
74 | HashMap<std::pair<Structure*, JSCell*>, RefPtr<StructureShape>> cachedPolyProtoShapes; |
75 | |
76 | LogEntry* entry = m_logStartPtr; |
77 | |
78 | while (entry != m_currentLogEntryPtr) { |
79 | StructureID id = entry->structureID; |
80 | RefPtr<StructureShape> shape; |
81 | JSValue value = entry->value; |
82 | Structure* structure = nullptr; |
83 | bool sawPolyProtoStructure = false; |
84 | if (id) { |
85 | structure = Heap::heap(value.asCell())->structureIDTable().get(id); |
86 | auto iter = cachedMonoProtoShapes.find(structure); |
87 | if (iter == cachedMonoProtoShapes.end()) { |
88 | auto key = std::make_pair(structure, value.asCell()); |
89 | auto iter = cachedPolyProtoShapes.find(key); |
90 | if (iter != cachedPolyProtoShapes.end()) { |
91 | shape = iter->value; |
92 | sawPolyProtoStructure = true; |
93 | } |
94 | |
95 | if (!shape) { |
96 | shape = structure->toStructureShape(value, sawPolyProtoStructure); |
97 | if (sawPolyProtoStructure) |
98 | cachedPolyProtoShapes.set(key, shape); |
99 | else |
100 | cachedMonoProtoShapes.set(structure, shape); |
101 | } |
102 | } else |
103 | shape = iter->value; |
104 | } |
105 | |
106 | RuntimeType type = runtimeTypeForValue(m_vm, value); |
107 | TypeLocation* location = entry->location; |
108 | location->m_lastSeenType = type; |
109 | if (location->m_globalTypeSet) |
110 | location->m_globalTypeSet->addTypeInformation(type, shape.copyRef(), structure, sawPolyProtoStructure); |
111 | location->m_instructionTypeSet->addTypeInformation(type, WTFMove(shape), structure, sawPolyProtoStructure); |
112 | |
113 | entry++; |
114 | } |
115 | |
116 | // Note that we don't update this cursor until we're done processing the log. |
117 | // This allows us to have a sane story in case we have to mark the log |
118 | // while processing through it. We won't be iterating over the log while |
119 | // marking it, but we may be in the middle of iterating over when the mutator |
120 | // pauses and causes the collector to mark the log. |
121 | m_currentLogEntryPtr = m_logStartPtr; |
122 | |
123 | if (TypeProfilerLogInternal::verbose) { |
124 | MonotonicTime after = MonotonicTime::now(); |
125 | dataLogF(" Processing the log took: '%f' ms\n" , (after - before).milliseconds()); |
126 | } |
127 | } |
128 | |
129 | void TypeProfilerLog::visit(SlotVisitor& visitor) |
130 | { |
131 | for (LogEntry* entry = m_logStartPtr; entry != m_currentLogEntryPtr; ++entry) { |
132 | visitor.appendUnbarriered(entry->value); |
133 | if (StructureID id = entry->structureID) { |
134 | Structure* structure = visitor.heap()->structureIDTable().get(id); |
135 | visitor.appendUnbarriered(structure); |
136 | } |
137 | } |
138 | } |
139 | |
140 | } // namespace JSC |
141 | |