ValueRecovery.h
1 /* 2 * Copyright (C) 2011-2019 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 #pragma once 27 28 #include "DFGMinifiedID.h" 29 #include "DataFormat.h" 30 #if ENABLE(JIT) 31 #include "GPRInfo.h" 32 #include "FPRInfo.h" 33 #include "Reg.h" 34 #endif 35 #include "JSCJSValue.h" 36 #include "MacroAssembler.h" 37 #include "VirtualRegister.h" 38 39 namespace JSC { 40 41 struct DumpContext; 42 struct InlineCallFrame; 43 44 // Describes how to recover a given bytecode virtual register at a given 45 // code point. 46 enum ValueRecoveryTechnique : uint8_t { 47 // It's in a register. 48 InGPR, 49 UnboxedInt32InGPR, 50 UnboxedInt52InGPR, 51 UnboxedStrictInt52InGPR, 52 UnboxedBooleanInGPR, 53 UnboxedCellInGPR, 54 #if USE(JSVALUE32_64) 55 InPair, 56 #endif 57 InFPR, 58 UnboxedDoubleInFPR, 59 // It's in the stack, but at a different location. 60 DisplacedInJSStack, 61 // It's in the stack, at a different location, and it's unboxed. 62 Int32DisplacedInJSStack, 63 Int52DisplacedInJSStack, 64 StrictInt52DisplacedInJSStack, 65 DoubleDisplacedInJSStack, 66 CellDisplacedInJSStack, 67 BooleanDisplacedInJSStack, 68 // It's an Arguments object. This arises because of the simplified arguments simplification done by the DFG. 69 DirectArgumentsThatWereNotCreated, 70 ClonedArgumentsThatWereNotCreated, 71 // It's a constant. 72 Constant, 73 // Don't know how to recover it. 74 DontKnow 75 }; 76 77 class ValueRecovery { 78 public: 79 ValueRecovery() 80 : m_technique(DontKnow) 81 { 82 } 83 84 bool isSet() const { return m_technique != DontKnow; } 85 bool operator!() const { return !isSet(); } 86 87 #if ENABLE(JIT) 88 static ValueRecovery inRegister(Reg reg, DataFormat dataFormat) 89 { 90 if (reg.isGPR()) 91 return inGPR(reg.gpr(), dataFormat); 92 93 ASSERT(reg.isFPR()); 94 return inFPR(reg.fpr(), dataFormat); 95 } 96 #endif 97 98 explicit operator bool() const { return isSet(); } 99 100 static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat) 101 { 102 ASSERT(dataFormat != DataFormatNone); 103 #if USE(JSVALUE32_64) 104 ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean); 105 #endif 106 ValueRecovery result; 107 if (dataFormat == DataFormatInt32) 108 result.m_technique = UnboxedInt32InGPR; 109 else if (dataFormat == DataFormatInt52) 110 result.m_technique = UnboxedInt52InGPR; 111 else if (dataFormat == DataFormatStrictInt52) 112 result.m_technique = UnboxedStrictInt52InGPR; 113 else if (dataFormat == DataFormatBoolean) 114 result.m_technique = UnboxedBooleanInGPR; 115 else if (dataFormat == DataFormatCell) 116 result.m_technique = UnboxedCellInGPR; 117 else 118 result.m_technique = InGPR; 119 UnionType u; 120 u.gpr = gpr; 121 result.m_source = WTFMove(u); 122 return result; 123 } 124 125 #if USE(JSVALUE32_64) 126 static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR) 127 { 128 ValueRecovery result; 129 result.m_technique = InPair; 130 UnionType u; 131 u.pair.tagGPR = tagGPR; 132 u.pair.payloadGPR = payloadGPR; 133 result.m_source = WTFMove(u); 134 return result; 135 } 136 #endif 137 138 static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat) 139 { 140 ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS); 141 ValueRecovery result; 142 if (dataFormat == DataFormatDouble) 143 result.m_technique = UnboxedDoubleInFPR; 144 else 145 result.m_technique = InFPR; 146 UnionType u; 147 u.fpr = fpr; 148 result.m_source = WTFMove(u); 149 return result; 150 } 151 152 static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat) 153 { 154 ValueRecovery result; 155 switch (dataFormat) { 156 case DataFormatInt32: 157 result.m_technique = Int32DisplacedInJSStack; 158 break; 159 160 case DataFormatInt52: 161 result.m_technique = Int52DisplacedInJSStack; 162 break; 163 164 case DataFormatStrictInt52: 165 result.m_technique = StrictInt52DisplacedInJSStack; 166 break; 167 168 case DataFormatDouble: 169 result.m_technique = DoubleDisplacedInJSStack; 170 break; 171 172 case DataFormatCell: 173 result.m_technique = CellDisplacedInJSStack; 174 break; 175 176 case DataFormatBoolean: 177 result.m_technique = BooleanDisplacedInJSStack; 178 break; 179 180 default: 181 ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage); 182 result.m_technique = DisplacedInJSStack; 183 break; 184 } 185 UnionType u; 186 u.virtualReg = virtualReg.offset(); 187 result.m_source = WTFMove(u); 188 return result; 189 } 190 191 static ValueRecovery constant(JSValue value) 192 { 193 ValueRecovery result; 194 result.m_technique = Constant; 195 UnionType u; 196 u.constant = JSValue::encode(value); 197 result.m_source = WTFMove(u); 198 return result; 199 } 200 201 static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id) 202 { 203 ValueRecovery result; 204 result.m_technique = DirectArgumentsThatWereNotCreated; 205 UnionType u; 206 u.nodeID = id.bits(); 207 result.m_source = WTFMove(u); 208 return result; 209 } 210 211 static ValueRecovery clonedArgumentsThatWereNotCreated(DFG::MinifiedID id) 212 { 213 ValueRecovery result; 214 result.m_technique = ClonedArgumentsThatWereNotCreated; 215 UnionType u; 216 u.nodeID = id.bits(); 217 result.m_source = WTFMove(u); 218 return result; 219 } 220 221 ValueRecoveryTechnique technique() const { return m_technique; } 222 223 bool isConstant() const { return m_technique == Constant; } 224 225 bool isInGPR() const 226 { 227 switch (m_technique) { 228 case InGPR: 229 case UnboxedInt32InGPR: 230 case UnboxedBooleanInGPR: 231 case UnboxedCellInGPR: 232 case UnboxedInt52InGPR: 233 case UnboxedStrictInt52InGPR: 234 return true; 235 default: 236 return false; 237 } 238 } 239 240 bool isInFPR() const 241 { 242 switch (m_technique) { 243 case InFPR: 244 case UnboxedDoubleInFPR: 245 return true; 246 default: 247 return false; 248 } 249 } 250 251 bool isInRegisters() const 252 { 253 return isInJSValueRegs() || isInGPR() || isInFPR(); 254 } 255 256 bool isInJSStack() const 257 { 258 switch (m_technique) { 259 case DisplacedInJSStack: 260 case Int32DisplacedInJSStack: 261 case Int52DisplacedInJSStack: 262 case StrictInt52DisplacedInJSStack: 263 case DoubleDisplacedInJSStack: 264 case CellDisplacedInJSStack: 265 case BooleanDisplacedInJSStack: 266 return true; 267 default: 268 return false; 269 } 270 } 271 272 DataFormat dataFormat() const 273 { 274 switch (m_technique) { 275 case InGPR: 276 case InFPR: 277 case DisplacedInJSStack: 278 case Constant: 279 #if USE(JSVALUE32_64) 280 case InPair: 281 #endif 282 return DataFormatJS; 283 case UnboxedInt32InGPR: 284 case Int32DisplacedInJSStack: 285 return DataFormatInt32; 286 case UnboxedInt52InGPR: 287 case Int52DisplacedInJSStack: 288 return DataFormatInt52; 289 case UnboxedStrictInt52InGPR: 290 case StrictInt52DisplacedInJSStack: 291 return DataFormatStrictInt52; 292 case UnboxedBooleanInGPR: 293 case BooleanDisplacedInJSStack: 294 return DataFormatBoolean; 295 case UnboxedCellInGPR: 296 case CellDisplacedInJSStack: 297 return DataFormatCell; 298 case UnboxedDoubleInFPR: 299 case DoubleDisplacedInJSStack: 300 return DataFormatDouble; 301 default: 302 return DataFormatNone; 303 } 304 } 305 306 MacroAssembler::RegisterID gpr() const 307 { 308 ASSERT(isInGPR()); 309 return m_source.get().gpr; 310 } 311 312 #if USE(JSVALUE32_64) 313 MacroAssembler::RegisterID tagGPR() const 314 { 315 ASSERT(m_technique == InPair); 316 return m_source.get().pair.tagGPR; 317 } 318 319 MacroAssembler::RegisterID payloadGPR() const 320 { 321 ASSERT(m_technique == InPair); 322 return m_source.get().pair.payloadGPR; 323 } 324 325 bool isInJSValueRegs() const 326 { 327 return m_technique == InPair; 328 } 329 330 #if ENABLE(JIT) 331 JSValueRegs jsValueRegs() const 332 { 333 ASSERT(isInJSValueRegs()); 334 return JSValueRegs(tagGPR(), payloadGPR()); 335 } 336 #endif // ENABLE(JIT) 337 #else 338 bool isInJSValueRegs() const 339 { 340 return isInGPR(); 341 } 342 #endif // USE(JSVALUE32_64) 343 344 MacroAssembler::FPRegisterID fpr() const 345 { 346 ASSERT(isInFPR()); 347 return m_source.get().fpr; 348 } 349 350 VirtualRegister virtualRegister() const 351 { 352 ASSERT(isInJSStack()); 353 return VirtualRegister(m_source.get().virtualReg); 354 } 355 356 ValueRecovery withLocalsOffset(int offset) const 357 { 358 switch (m_technique) { 359 case DisplacedInJSStack: 360 case Int32DisplacedInJSStack: 361 case DoubleDisplacedInJSStack: 362 case CellDisplacedInJSStack: 363 case BooleanDisplacedInJSStack: 364 case Int52DisplacedInJSStack: 365 case StrictInt52DisplacedInJSStack: { 366 ValueRecovery result; 367 result.m_technique = m_technique; 368 UnionType u; 369 u.virtualReg = m_source.get().virtualReg + offset; 370 result.m_source = WTFMove(u); 371 return result; 372 } 373 374 default: 375 return *this; 376 } 377 } 378 379 JSValue constant() const 380 { 381 ASSERT(isConstant()); 382 return JSValue::decode(m_source.get().constant); 383 } 384 385 DFG::MinifiedID nodeID() const 386 { 387 ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated); 388 return DFG::MinifiedID::fromBits(m_source.get().nodeID); 389 } 390 391 JSValue recover(CallFrame*) const; 392 393 #if ENABLE(JIT) 394 template<typename Func> 395 void forEachReg(const Func& func) 396 { 397 switch (m_technique) { 398 case InGPR: 399 case UnboxedInt32InGPR: 400 case UnboxedBooleanInGPR: 401 case UnboxedCellInGPR: 402 case UnboxedInt52InGPR: 403 case UnboxedStrictInt52InGPR: 404 func(gpr()); 405 return; 406 case InFPR: 407 case UnboxedDoubleInFPR: 408 func(fpr()); 409 return; 410 #if USE(JSVALUE32_64) 411 case InPair: 412 func(jsValueRegs().payloadGPR()); 413 func(jsValueRegs().tagGPR()); 414 return; 415 #endif 416 default: 417 return; 418 } 419 } 420 421 void dumpInContext(PrintStream& out, DumpContext* context) const; 422 void dump(PrintStream& out) const; 423 #endif 424 425 private: 426 ValueRecoveryTechnique m_technique; 427 union UnionType { 428 MacroAssembler::RegisterID gpr; 429 MacroAssembler::FPRegisterID fpr; 430 #if USE(JSVALUE32_64) 431 struct { 432 MacroAssembler::RegisterID tagGPR; 433 MacroAssembler::RegisterID payloadGPR; 434 } pair; 435 #endif 436 int virtualReg; 437 EncodedJSValue constant; 438 unsigned nodeID; 439 }; 440 Packed<UnionType> m_source; 441 }; 442 static_assert(alignof(ValueRecovery) == 1); 443 444 } // namespace JSC