Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / runtime / TypeProfiler.cpp
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  * 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 "TypeProfiler.h"
28
29 #include "InspectorProtocolObjects.h"
30 #include "TypeLocation.h"
31 #include <wtf/text/StringBuilder.h>
32
33 namespace JSC {
34
35 static const bool verbose = false;
36
37 TypeProfiler::TypeProfiler()
38     : m_nextUniqueVariableID(1)
39
40 }
41
42 void TypeProfiler::logTypesForTypeLocation(TypeLocation* location, VM& vm)
43 {
44     TypeProfilerSearchDescriptor descriptor = location->m_globalVariableID == TypeProfilerReturnStatement ? TypeProfilerSearchDescriptorFunctionReturn : TypeProfilerSearchDescriptorNormal;
45
46     dataLogF("[Start, End]::[%u, %u]\n", location->m_divotStart, location->m_divotEnd);
47
48     if (findLocation(location->m_divotStart, location->m_sourceID, descriptor, vm))
49         dataLog("\t\t[Entry IS in System]\n");
50     else
51         dataLog("\t\t[Entry IS NOT in system]\n");
52
53     dataLog("\t\t", location->m_globalVariableID == TypeProfilerReturnStatement ? "[Return Statement]" : "[Normal Statement]", "\n");
54
55     dataLog("\t\t#Local#\n\t\t", location->m_instructionTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
56     if (location->m_globalTypeSet)
57         dataLog("\t\t#Global#\n\t\t", location->m_globalTypeSet->dumpTypes().replace("\n", "\n\t\t"), "\n");
58 }
59
60 void TypeProfiler::insertNewLocation(TypeLocation* location)
61 {
62     if (verbose)
63         dataLogF("Registering location:: divotStart:%u, divotEnd:%u\n", location->m_divotStart, location->m_divotEnd);
64
65     if (!m_bucketMap.contains(location->m_sourceID)) {
66         Vector<TypeLocation*> bucket;
67         m_bucketMap.set(location->m_sourceID, bucket);
68     }
69
70     Vector<TypeLocation*>& bucket = m_bucketMap.find(location->m_sourceID)->value;
71     bucket.append(location);
72 }
73
74 String TypeProfiler::typeInformationForExpressionAtOffset(TypeProfilerSearchDescriptor descriptor, unsigned offset, intptr_t sourceID, VM& vm)
75 {
76     // This returns a JSON string representing an Object with the following properties:
77     //     globalTypeSet: 'JSON<TypeSet> | null'
78     //     instructionTypeSet: 'JSON<TypeSet>'
79
80     TypeLocation* location = findLocation(offset, sourceID, descriptor, vm);
81     ASSERT(location);
82
83     StringBuilder json;  
84
85     json.append('{');
86
87     json.appendLiteral("\"globalTypeSet\":");
88     if (location->m_globalTypeSet && location->m_globalVariableID != TypeProfilerNoGlobalIDExists)
89         json.append(location->m_globalTypeSet->toJSONString());
90     else
91         json.appendLiteral("null");
92     json.append(',');
93
94     json.appendLiteral("\"instructionTypeSet\":");
95     json.append(location->m_instructionTypeSet->toJSONString());
96     json.append(',');
97
98     json.appendLiteral("\"isOverflown\":");
99     if (location->m_instructionTypeSet->isOverflown() || (location->m_globalTypeSet && location->m_globalTypeSet->isOverflown()))
100         json.appendLiteral("true");
101     else
102         json.appendLiteral("false");
103
104     json.append('}');
105     
106     return json.toString();
107 }
108
109 TypeLocation* TypeProfiler::findLocation(unsigned divot, intptr_t sourceID, TypeProfilerSearchDescriptor descriptor, VM& vm)
110 {
111     QueryKey queryKey(sourceID, divot, descriptor);
112     auto iter = m_queryCache.find(queryKey);
113     if (iter != m_queryCache.end())
114         return iter->value;
115
116     if (!vm.functionHasExecutedCache()->hasExecutedAtOffset(sourceID, divot))
117         return nullptr;
118
119     if (!m_bucketMap.contains(sourceID))
120         return nullptr;
121
122     Vector<TypeLocation*>& bucket = m_bucketMap.find(sourceID)->value;
123     TypeLocation* bestMatch = nullptr;
124     unsigned distance = UINT_MAX; // Because assignments may be nested, make sure we find the closest enclosing assignment to this character offset.
125     for (auto* location : bucket) {
126         // We found the type location that correlates to the convergence of all return statements in a function.
127         // This text offset is the offset of the opening brace in a function declaration.
128         if (descriptor == TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID == TypeProfilerReturnStatement && location->m_divotForFunctionOffsetIfReturnStatement == divot)
129             return location;
130
131         if (descriptor != TypeProfilerSearchDescriptorFunctionReturn && location->m_globalVariableID != TypeProfilerReturnStatement && location->m_divotStart <= divot && divot <= location->m_divotEnd && location->m_divotEnd - location->m_divotStart <= distance) {
132             distance = location->m_divotEnd - location->m_divotStart;
133             bestMatch = location;
134         }
135     }
136
137     if (bestMatch)
138         m_queryCache.set(queryKey, bestMatch);
139     // FIXME: BestMatch should never be null past this point. This doesn't hold currently because we ignore var assignments when code contains eval/With (VarInjection). 
140     // https://bugs.webkit.org/show_bug.cgi?id=135184
141     return bestMatch;
142 }
143
144 TypeLocation* TypeProfiler::nextTypeLocation() 
145
146     return m_typeLocationInfo.add(); 
147 }
148
149 void TypeProfiler::invalidateTypeSetCache()
150 {
151     for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
152         TypeLocation* location = *iter;
153         location->m_instructionTypeSet->invalidateCache();
154         if (location->m_globalTypeSet)
155             location->m_globalTypeSet->invalidateCache();
156     }
157 }
158
159 void TypeProfiler::dumpTypeProfilerData(VM& vm)
160 {
161     for (Bag<TypeLocation>::iterator iter = m_typeLocationInfo.begin(); !!iter; ++iter) {
162         TypeLocation* location = *iter;
163         logTypesForTypeLocation(location, vm);
164     }
165 }
166
167 } // namespace JSC