1/* 2 * Copyright (C) 2011, 2013 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#ifndef DFGGenerationInfo_h 27#define DFGGenerationInfo_h 28 29#if ENABLE(DFG_JIT) 30 31#include "DFGJITCompiler.h" 32#include "DFGMinifiedID.h" 33#include "DFGVariableEvent.h" 34#include "DFGVariableEventStream.h" 35#include "DataFormat.h" 36 37namespace JSC { namespace DFG { 38 39// === GenerationInfo === 40// 41// This class is used to track the current status of a live values during code generation. 42// Can provide information as to whether a value is in machine registers, and if so which, 43// whether a value has been spilled to the RegsiterFile, and if so may be able to provide 44// details of the format in memory (all values are spilled in a boxed form, but we may be 45// able to track the type of box), and tracks how many outstanding uses of a value remain, 46// so that we know when the value is dead and the machine registers associated with it 47// may be released. 48class GenerationInfo { 49public: 50 GenerationInfo() 51 : m_node(0) 52 , m_useCount(0) 53 , m_registerFormat(DataFormatNone) 54 , m_spillFormat(DataFormatNone) 55 , m_canFill(false) 56 , m_bornForOSR(false) 57 , m_isConstant(false) 58 { 59 } 60 61 void initConstant(Node* node, uint32_t useCount) 62 { 63 m_node = node; 64 m_useCount = useCount; 65 m_registerFormat = DataFormatNone; 66 m_spillFormat = DataFormatNone; 67 m_canFill = true; 68 m_bornForOSR = false; 69 m_isConstant = true; 70 ASSERT(m_useCount); 71 } 72 void initGPR(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format) 73 { 74 ASSERT(gpr != InvalidGPRReg); 75 m_node = node; 76 m_useCount = useCount; 77 m_registerFormat = format; 78 m_spillFormat = DataFormatNone; 79 m_canFill = false; 80 u.gpr = gpr; 81 m_bornForOSR = false; 82 m_isConstant = false; 83 ASSERT(m_useCount); 84 } 85 void initInt32(Node* node, uint32_t useCount, GPRReg gpr) 86 { 87 initGPR(node, useCount, gpr, DataFormatInt32); 88 } 89 void initInt52(Node* node, uint32_t useCount, GPRReg reg, DataFormat format) 90 { 91 ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52); 92 initGPR(node, useCount, reg, format); 93 } 94 void initInt52(Node* node, uint32_t useCount, GPRReg reg) 95 { 96 initGPR(node, useCount, reg, DataFormatInt52); 97 } 98 void initStrictInt52(Node* node, uint32_t useCount, GPRReg reg) 99 { 100 initGPR(node, useCount, reg, DataFormatStrictInt52); 101 } 102#if USE(JSVALUE64) 103 void initJSValue(Node* node, uint32_t useCount, GPRReg gpr, DataFormat format = DataFormatJS) 104 { 105 ASSERT(format & DataFormatJS); 106 initGPR(node, useCount, gpr, format); 107 } 108#elif USE(JSVALUE32_64) 109 void initJSValue(Node* node, uint32_t useCount, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS) 110 { 111 ASSERT(format & DataFormatJS); 112 113 m_node = node; 114 m_useCount = useCount; 115 m_registerFormat = format; 116 m_spillFormat = DataFormatNone; 117 m_canFill = false; 118 u.v.tagGPR = tagGPR; 119 u.v.payloadGPR = payloadGPR; 120 m_bornForOSR = false; 121 m_isConstant = false; 122 ASSERT(m_useCount); 123 } 124#endif 125 void initCell(Node* node, uint32_t useCount, GPRReg gpr) 126 { 127 initGPR(node, useCount, gpr, DataFormatCell); 128 } 129 void initBoolean(Node* node, uint32_t useCount, GPRReg gpr) 130 { 131 initGPR(node, useCount, gpr, DataFormatBoolean); 132 } 133 void initDouble(Node* node, uint32_t useCount, FPRReg fpr) 134 { 135 ASSERT(fpr != InvalidFPRReg); 136 m_node = node; 137 m_useCount = useCount; 138 m_registerFormat = DataFormatDouble; 139 m_spillFormat = DataFormatNone; 140 m_canFill = false; 141 u.fpr = fpr; 142 m_bornForOSR = false; 143 m_isConstant = false; 144 ASSERT(m_useCount); 145 } 146 void initStorage(Node* node, uint32_t useCount, GPRReg gpr) 147 { 148 initGPR(node, useCount, gpr, DataFormatStorage); 149 } 150 151 // Get the node that produced this value. 152 Node* node() { return m_node; } 153 154 void noticeOSRBirth(VariableEventStream& stream, Node* node, VirtualRegister virtualRegister) 155 { 156 if (m_isConstant) 157 return; 158 if (m_node != node) 159 return; 160 if (!alive()) 161 return; 162 if (m_bornForOSR) 163 return; 164 165 m_bornForOSR = true; 166 167 if (m_registerFormat != DataFormatNone) 168 appendFill(BirthToFill, stream); 169 else if (m_spillFormat != DataFormatNone) 170 appendSpill(BirthToSpill, stream, virtualRegister); 171 } 172 173 // Mark the value as having been used (decrement the useCount). 174 // Returns true if this was the last use of the value, and any 175 // associated machine registers may be freed. 176 bool use(VariableEventStream& stream) 177 { 178 ASSERT(m_useCount); 179 bool result = !--m_useCount; 180 181 if (result && m_bornForOSR) { 182 ASSERT(m_node); 183 stream.appendAndLog(VariableEvent::death(MinifiedID(m_node))); 184 } 185 186 return result; 187 } 188 189 // Used to check the operands of operations to see if they are on 190 // their last use; in some cases it may be safe to reuse the same 191 // machine register for the result of the operation. 192 bool canReuse() 193 { 194 ASSERT(m_useCount); 195 return m_useCount == 1; 196 } 197 198 // Get the format of the value in machine registers (or 'none'). 199 DataFormat registerFormat() { return m_registerFormat; } 200 // Get the format of the value as it is spilled in the JSStack (or 'none'). 201 DataFormat spillFormat() { return m_spillFormat; } 202 203 bool isFormat(DataFormat expectedFormat) 204 { 205 return registerFormat() == expectedFormat || spillFormat() == expectedFormat; 206 } 207 208 bool isJSFormat(DataFormat expectedFormat) 209 { 210 return JSC::isJSFormat(registerFormat(), expectedFormat) || JSC::isJSFormat(spillFormat(), expectedFormat); 211 } 212 213 bool isJSInt32() 214 { 215 return isJSFormat(DataFormatJSInt32); 216 } 217 218 bool isInt52() 219 { 220 return isFormat(DataFormatInt52); 221 } 222 223 bool isStrictInt52() 224 { 225 return isFormat(DataFormatStrictInt52); 226 } 227 228 bool isJSDouble() 229 { 230 return isJSFormat(DataFormatJSDouble); 231 } 232 233 bool isJSCell() 234 { 235 return isJSFormat(DataFormatJSCell); 236 } 237 238 bool isJSBoolean() 239 { 240 return isJSFormat(DataFormatJSBoolean); 241 } 242 243 bool isUnknownJS() 244 { 245 return spillFormat() == DataFormatNone 246 ? registerFormat() == DataFormatJS || registerFormat() == DataFormatNone 247 : spillFormat() == DataFormatJS; 248 } 249 250 // Get the machine resister currently holding the value. 251#if USE(JSVALUE64) 252 GPRReg gpr() { ASSERT(m_registerFormat && m_registerFormat != DataFormatDouble); return u.gpr; } 253 FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble); return u.fpr; } 254 JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.gpr); } 255#elif USE(JSVALUE32_64) 256 GPRReg gpr() { ASSERT(!(m_registerFormat & DataFormatJS) && m_registerFormat != DataFormatDouble); return u.gpr; } 257 GPRReg tagGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.tagGPR; } 258 GPRReg payloadGPR() { ASSERT(m_registerFormat & DataFormatJS); return u.v.payloadGPR; } 259 FPRReg fpr() { ASSERT(m_registerFormat == DataFormatDouble || m_registerFormat == DataFormatJSDouble); return u.fpr; } 260 JSValueRegs jsValueRegs() { ASSERT(m_registerFormat & DataFormatJS); return JSValueRegs(u.v.tagGPR, u.v.payloadGPR); } 261#endif 262 263 // Check whether a value needs spilling in order to free up any associated machine registers. 264 bool needsSpill() 265 { 266 // This should only be called on values that are currently in a register. 267 ASSERT(m_registerFormat != DataFormatNone); 268 // Constants do not need spilling, nor do values that have already been 269 // spilled to the JSStack. 270 return !m_canFill; 271 } 272 273 // Called when a VirtualRegister is being spilled to the JSStack for the first time. 274 void spill(VariableEventStream& stream, VirtualRegister virtualRegister, DataFormat spillFormat) 275 { 276 // We shouldn't be spill values that don't need spilling. 277 ASSERT(!m_canFill); 278 ASSERT(m_spillFormat == DataFormatNone); 279 // We should only be spilling values that are currently in machine registers. 280 ASSERT(m_registerFormat != DataFormatNone); 281 282 m_registerFormat = DataFormatNone; 283 m_spillFormat = spillFormat; 284 m_canFill = true; 285 286 if (m_bornForOSR) 287 appendSpill(Spill, stream, virtualRegister); 288 } 289 290 // Called on values that don't need spilling (constants and values that have 291 // already been spilled), to mark them as no longer being in machine registers. 292 void setSpilled(VariableEventStream& stream, VirtualRegister virtualRegister) 293 { 294 // Should only be called on values that don't need spilling, and are currently in registers. 295 ASSERT(m_canFill && m_registerFormat != DataFormatNone); 296 m_registerFormat = DataFormatNone; 297 298 if (m_bornForOSR) 299 appendSpill(Spill, stream, virtualRegister); 300 } 301 302 void killSpilled() 303 { 304 m_spillFormat = DataFormatNone; 305 m_canFill = false; 306 } 307 308 void fillGPR(VariableEventStream& stream, GPRReg gpr, DataFormat format) 309 { 310 ASSERT(gpr != InvalidGPRReg); 311 m_registerFormat = format; 312 u.gpr = gpr; 313 if (m_bornForOSR) 314 appendFill(Fill, stream); 315 } 316 317 // Record that this value is filled into machine registers, 318 // tracking which registers, and what format the value has. 319#if USE(JSVALUE64) 320 void fillJSValue(VariableEventStream& stream, GPRReg gpr, DataFormat format = DataFormatJS) 321 { 322 ASSERT(format & DataFormatJS); 323 fillGPR(stream, gpr, format); 324 } 325#elif USE(JSVALUE32_64) 326 void fillJSValue(VariableEventStream& stream, GPRReg tagGPR, GPRReg payloadGPR, DataFormat format = DataFormatJS) 327 { 328 ASSERT(format & DataFormatJS); 329 m_registerFormat = format; 330 u.v.tagGPR = tagGPR; // FIXME: for JSValues with known type (boolean, integer, cell etc.) no tagGPR is needed? 331 u.v.payloadGPR = payloadGPR; 332 333 if (m_bornForOSR) 334 appendFill(Fill, stream); 335 } 336 void fillCell(VariableEventStream& stream, GPRReg gpr) 337 { 338 fillGPR(stream, gpr, DataFormatCell); 339 } 340#endif 341 void fillInt32(VariableEventStream& stream, GPRReg gpr) 342 { 343 fillGPR(stream, gpr, DataFormatInt32); 344 } 345 void fillInt52(VariableEventStream& stream, GPRReg gpr, DataFormat format) 346 { 347 ASSERT(format == DataFormatInt52 || format == DataFormatStrictInt52); 348 fillGPR(stream, gpr, format); 349 } 350 void fillInt52(VariableEventStream& stream, GPRReg gpr) 351 { 352 fillGPR(stream, gpr, DataFormatInt52); 353 } 354 void fillStrictInt52(VariableEventStream& stream, GPRReg gpr) 355 { 356 fillGPR(stream, gpr, DataFormatStrictInt52); 357 } 358 void fillBoolean(VariableEventStream& stream, GPRReg gpr) 359 { 360 fillGPR(stream, gpr, DataFormatBoolean); 361 } 362 void fillDouble(VariableEventStream& stream, FPRReg fpr) 363 { 364 ASSERT(fpr != InvalidFPRReg); 365 m_registerFormat = DataFormatDouble; 366 u.fpr = fpr; 367 368 if (m_bornForOSR) 369 appendFill(Fill, stream); 370 } 371 void fillStorage(VariableEventStream& stream, GPRReg gpr) 372 { 373 fillGPR(stream, gpr, DataFormatStorage); 374 } 375 376 bool alive() 377 { 378 return m_useCount; 379 } 380 381private: 382 void appendFill(VariableEventKind kind, VariableEventStream& stream) 383 { 384 ASSERT(m_bornForOSR); 385 386 if (m_registerFormat == DataFormatDouble) { 387 stream.appendAndLog(VariableEvent::fillFPR(kind, MinifiedID(m_node), u.fpr)); 388 return; 389 } 390#if USE(JSVALUE32_64) 391 if (m_registerFormat & DataFormatJS) { 392 stream.appendAndLog(VariableEvent::fillPair(kind, MinifiedID(m_node), u.v.tagGPR, u.v.payloadGPR)); 393 return; 394 } 395#endif 396 stream.appendAndLog(VariableEvent::fillGPR(kind, MinifiedID(m_node), u.gpr, m_registerFormat)); 397 } 398 399 void appendSpill(VariableEventKind kind, VariableEventStream& stream, VirtualRegister virtualRegister) 400 { 401 stream.appendAndLog(VariableEvent::spill(kind, MinifiedID(m_node), virtualRegister, m_spillFormat)); 402 } 403 404 // The node whose result is stored in this virtual register. 405 Node* m_node; 406 uint32_t m_useCount; 407 DataFormat m_registerFormat; 408 DataFormat m_spillFormat; 409 bool m_canFill; 410 bool m_bornForOSR; 411 bool m_isConstant; 412 union { 413 GPRReg gpr; 414 FPRReg fpr; 415#if USE(JSVALUE32_64) 416 struct { 417 GPRReg tagGPR; 418 GPRReg payloadGPR; 419 } v; 420#endif 421 } u; 422}; 423 424} } // namespace JSC::DFG 425 426#endif 427#endif 428