]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLStackMaps.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / ftl / FTLStackMaps.cpp
1 /*
2 * Copyright (C) 2013, 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 "FTLStackMaps.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "FTLLocation.h"
32 #include <wtf/CommaPrinter.h>
33 #include <wtf/DataLog.h>
34 #include <wtf/ListDump.h>
35
36 namespace JSC { namespace FTL {
37
38 template<typename T>
39 T readObject(StackMaps::ParseContext& context)
40 {
41 T result;
42 result.parse(context);
43 return result;
44 }
45
46 void StackMaps::Constant::parse(StackMaps::ParseContext& context)
47 {
48 integer = context.view->read<int64_t>(context.offset, true);
49 }
50
51 void StackMaps::Constant::dump(PrintStream& out) const
52 {
53 out.printf("0x%016llx", static_cast<unsigned long long>(integer));
54 }
55
56 void StackMaps::StackSize::parse(StackMaps::ParseContext& context)
57 {
58 switch (context.version) {
59 case 0:
60 functionOffset = context.view->read<uint32_t>(context.offset, true);
61 size = context.view->read<uint32_t>(context.offset, true);
62 break;
63
64 default:
65 functionOffset = context.view->read<uint64_t>(context.offset, true);
66 size = context.view->read<uint64_t>(context.offset, true);
67 break;
68 }
69 }
70
71 void StackMaps::StackSize::dump(PrintStream& out) const
72 {
73 out.print("(off:", functionOffset, ", size:", size, ")");
74 }
75
76 void StackMaps::Location::parse(StackMaps::ParseContext& context)
77 {
78 kind = static_cast<Kind>(context.view->read<uint8_t>(context.offset, true));
79 size = context.view->read<uint8_t>(context.offset, true);
80 dwarfReg = DWARFRegister(context.view->read<uint16_t>(context.offset, true));
81 this->offset = context.view->read<int32_t>(context.offset, true);
82 }
83
84 void StackMaps::Location::dump(PrintStream& out) const
85 {
86 out.print("(", kind, ", ", dwarfReg, ", off:", offset, ", size:", size, ")");
87 }
88
89 GPRReg StackMaps::Location::directGPR() const
90 {
91 return FTL::Location::forStackmaps(nullptr, *this).directGPR();
92 }
93
94 void StackMaps::Location::restoreInto(
95 MacroAssembler& jit, StackMaps& stackmaps, char* savedRegisters, GPRReg result) const
96 {
97 FTL::Location::forStackmaps(&stackmaps, *this).restoreInto(jit, savedRegisters, result);
98 }
99
100 void StackMaps::LiveOut::parse(StackMaps::ParseContext& context)
101 {
102 dwarfReg = DWARFRegister(context.view->read<uint16_t>(context.offset, true)); // regnum
103 context.view->read<uint8_t>(context.offset, true); // reserved
104 size = context.view->read<uint8_t>(context.offset, true); // size in bytes
105 }
106
107 void StackMaps::LiveOut::dump(PrintStream& out) const
108 {
109 out.print("(", dwarfReg, ", ", size, ")");
110 }
111
112 bool StackMaps::Record::parse(StackMaps::ParseContext& context)
113 {
114 int64_t id = context.view->read<int64_t>(context.offset, true);
115 ASSERT(static_cast<int32_t>(id) == id);
116 patchpointID = static_cast<uint32_t>(id);
117 if (static_cast<int32_t>(patchpointID) < 0)
118 return false;
119
120 instructionOffset = context.view->read<uint32_t>(context.offset, true);
121 flags = context.view->read<uint16_t>(context.offset, true);
122
123 unsigned length = context.view->read<uint16_t>(context.offset, true);
124 while (length--)
125 locations.append(readObject<Location>(context));
126
127 if (context.version >= 1)
128 context.view->read<uint16_t>(context.offset, true); // padding
129
130 unsigned numLiveOuts = context.view->read<uint16_t>(context.offset, true);
131 while (numLiveOuts--)
132 liveOuts.append(readObject<LiveOut>(context));
133
134 if (context.version >= 1) {
135 if (context.offset & 7) {
136 ASSERT(!(context.offset & 3));
137 context.view->read<uint32_t>(context.offset, true); // padding
138 }
139 }
140
141 return true;
142 }
143
144 void StackMaps::Record::dump(PrintStream& out) const
145 {
146 out.print(
147 "(#", patchpointID, ", offset = ", instructionOffset, ", flags = ", flags,
148 ", locations = [", listDump(locations), "], liveOuts = [",
149 listDump(liveOuts), "])");
150 }
151
152 RegisterSet StackMaps::Record::locationSet() const
153 {
154 RegisterSet result;
155 for (unsigned i = locations.size(); i--;) {
156 Reg reg = locations[i].dwarfReg.reg();
157 if (!reg)
158 continue;
159 result.set(reg);
160 }
161 return result;
162 }
163
164 RegisterSet StackMaps::Record::liveOutsSet() const
165 {
166 RegisterSet result;
167 for (unsigned i = liveOuts.size(); i--;) {
168 LiveOut liveOut = liveOuts[i];
169 Reg reg = liveOut.dwarfReg.reg();
170 // FIXME: Either assert that size is not greater than sizeof(pointer), or actually
171 // save the high bits of registers.
172 // https://bugs.webkit.org/show_bug.cgi?id=130885
173 if (!reg) {
174 dataLog("Invalid liveOuts entry in: ", *this, "\n");
175 RELEASE_ASSERT_NOT_REACHED();
176 }
177 result.set(reg);
178 }
179 return result;
180 }
181
182 RegisterSet StackMaps::Record::usedRegisterSet() const
183 {
184 RegisterSet result;
185 result.merge(locationSet());
186 result.merge(liveOutsSet());
187 return result;
188 }
189
190 bool StackMaps::parse(DataView* view)
191 {
192 ParseContext context;
193 context.offset = 0;
194 context.view = view;
195
196 version = context.version = context.view->read<uint8_t>(context.offset, true);
197
198 context.view->read<uint8_t>(context.offset, true); // Reserved
199 context.view->read<uint8_t>(context.offset, true); // Reserved
200 context.view->read<uint8_t>(context.offset, true); // Reserved
201
202 uint32_t numFunctions;
203 uint32_t numConstants;
204 uint32_t numRecords;
205
206 numFunctions = context.view->read<uint32_t>(context.offset, true);
207 if (context.version >= 1) {
208 numConstants = context.view->read<uint32_t>(context.offset, true);
209 numRecords = context.view->read<uint32_t>(context.offset, true);
210 }
211 while (numFunctions--)
212 stackSizes.append(readObject<StackSize>(context));
213
214 if (!context.version)
215 numConstants = context.view->read<uint32_t>(context.offset, true);
216 while (numConstants--)
217 constants.append(readObject<Constant>(context));
218
219 if (!context.version)
220 numRecords = context.view->read<uint32_t>(context.offset, true);
221 while (numRecords--) {
222 Record record;
223 if (!record.parse(context))
224 return false;
225 records.append(record);
226 }
227
228 return true;
229 }
230
231 void StackMaps::dump(PrintStream& out) const
232 {
233 out.print("Version:", version, ", StackSizes[", listDump(stackSizes), "], Constants:[", listDump(constants), "], Records:[", listDump(records), "]");
234 }
235
236 void StackMaps::dumpMultiline(PrintStream& out, const char* prefix) const
237 {
238 out.print(prefix, "Version: ", version, "\n");
239 out.print(prefix, "StackSizes:\n");
240 for (unsigned i = 0; i < stackSizes.size(); ++i)
241 out.print(prefix, " ", stackSizes[i], "\n");
242 out.print(prefix, "Constants:\n");
243 for (unsigned i = 0; i < constants.size(); ++i)
244 out.print(prefix, " ", constants[i], "\n");
245 out.print(prefix, "Records:\n");
246 for (unsigned i = 0; i < records.size(); ++i)
247 out.print(prefix, " ", records[i], "\n");
248 }
249
250 StackMaps::RecordMap StackMaps::computeRecordMap() const
251 {
252 RecordMap result;
253 for (unsigned i = records.size(); i--;)
254 result.add(records[i].patchpointID, Vector<Record>()).iterator->value.append(records[i]);
255 return result;
256 }
257
258 unsigned StackMaps::stackSize() const
259 {
260 RELEASE_ASSERT(stackSizes.size() == 1);
261
262 return stackSizes[0].size;
263 }
264
265 } } // namespace JSC::FTL
266
267 namespace WTF {
268
269 using namespace JSC::FTL;
270
271 void printInternal(PrintStream& out, StackMaps::Location::Kind kind)
272 {
273 switch (kind) {
274 case StackMaps::Location::Unprocessed:
275 out.print("Unprocessed");
276 return;
277 case StackMaps::Location::Register:
278 out.print("Register");
279 return;
280 case StackMaps::Location::Direct:
281 out.print("Direct");
282 return;
283 case StackMaps::Location::Indirect:
284 out.print("Indirect");
285 return;
286 case StackMaps::Location::Constant:
287 out.print("Constant");
288 return;
289 case StackMaps::Location::ConstantIndex:
290 out.print("ConstantIndex");
291 return;
292 }
293 dataLog("Unrecognized kind: ", static_cast<int>(kind), "\n");
294 RELEASE_ASSERT_NOT_REACHED();
295 }
296
297 } // namespace WTF
298
299 #endif // ENABLE(FTL_JIT)
300