1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_IonIC_h 8 #define jit_IonIC_h 9 10 #include "jit/CacheIR.h" 11 12 namespace js { 13 namespace jit { 14 15 class CacheIRStubInfo; 16 17 // An optimized stub attached to an IonIC. 18 class IonICStub { 19 // Code to jump to when this stub fails. This is either the next optimized 20 // stub or the OOL fallback path. 21 uint8_t* nextCodeRaw_; 22 23 // The next optimized stub in this chain, or nullptr if this is the last 24 // one. 25 IonICStub* next_; 26 27 // Info about this stub. 28 CacheIRStubInfo* stubInfo_; 29 30 public: IonICStub(uint8_t * fallbackCode,CacheIRStubInfo * stubInfo)31 IonICStub(uint8_t* fallbackCode, CacheIRStubInfo* stubInfo) 32 : nextCodeRaw_(fallbackCode), next_(nullptr), stubInfo_(stubInfo) {} 33 nextCodeRaw()34 uint8_t* nextCodeRaw() const { return nextCodeRaw_; } nextCodeRawPtr()35 uint8_t** nextCodeRawPtr() { return &nextCodeRaw_; } stubInfo()36 CacheIRStubInfo* stubInfo() const { return stubInfo_; } next()37 IonICStub* next() const { return next_; } 38 39 uint8_t* stubDataStart(); 40 setNext(IonICStub * next,uint8_t * nextCodeRaw)41 void setNext(IonICStub* next, uint8_t* nextCodeRaw) { 42 MOZ_ASSERT(!next_); 43 MOZ_ASSERT(next && nextCodeRaw); 44 next_ = next; 45 nextCodeRaw_ = nextCodeRaw; 46 } 47 48 // Null out pointers when we unlink stubs, to ensure we never use 49 // discarded stubs. poison()50 void poison() { 51 nextCodeRaw_ = nullptr; 52 next_ = nullptr; 53 stubInfo_ = nullptr; 54 } 55 }; 56 57 class IonGetPropertyIC; 58 class IonSetPropertyIC; 59 class IonGetPropSuperIC; 60 class IonGetNameIC; 61 class IonBindNameIC; 62 class IonGetIteratorIC; 63 class IonHasOwnIC; 64 class IonInIC; 65 class IonInstanceOfIC; 66 class IonCompareIC; 67 class IonUnaryArithIC; 68 class IonBinaryArithIC; 69 70 class IonIC { 71 // This either points at the OOL path for the fallback path, or the code for 72 // the first stub. 73 uint8_t* codeRaw_; 74 75 // The first optimized stub, or nullptr. 76 IonICStub* firstStub_; 77 78 // Location of this IC, nullptr for idempotent caches. 79 JSScript* script_; 80 jsbytecode* pc_; 81 82 // The offset of the rejoin location in the IonScript's code (stubs jump to 83 // this location). 84 uint32_t rejoinOffset_; 85 86 // The offset of the OOL path in the IonScript's code that calls the IC's 87 // update function. 88 uint32_t fallbackOffset_; 89 90 CacheKind kind_; 91 bool idempotent_ : 1; 92 ICState state_; 93 94 protected: IonIC(CacheKind kind)95 explicit IonIC(CacheKind kind) 96 : codeRaw_(nullptr), 97 firstStub_(nullptr), 98 script_(nullptr), 99 pc_(nullptr), 100 rejoinOffset_(0), 101 fallbackOffset_(0), 102 kind_(kind), 103 idempotent_(false), 104 state_() {} 105 106 void attachStub(IonICStub* newStub, JitCode* code); 107 108 public: setScriptedLocation(JSScript * script,jsbytecode * pc)109 void setScriptedLocation(JSScript* script, jsbytecode* pc) { 110 MOZ_ASSERT(!script_ && !pc_); 111 MOZ_ASSERT(script && pc); 112 script_ = script; 113 pc_ = pc; 114 } 115 script()116 JSScript* script() const { 117 MOZ_ASSERT(script_); 118 return script_; 119 } pc()120 jsbytecode* pc() const { 121 MOZ_ASSERT(pc_); 122 return pc_; 123 } 124 125 // Discard all stubs. 126 void discardStubs(Zone* zone, IonScript* ionScript); 127 128 // Discard all stubs and reset the ICState. 129 void reset(Zone* zone, IonScript* ionScript); 130 state()131 ICState& state() { return state_; } 132 kind()133 CacheKind kind() const { return kind_; } codeRawPtr()134 uint8_t** codeRawPtr() { return &codeRaw_; } 135 idempotent()136 bool idempotent() const { return idempotent_; } setIdempotent()137 void setIdempotent() { idempotent_ = true; } 138 setFallbackOffset(CodeOffset offset)139 void setFallbackOffset(CodeOffset offset) { 140 fallbackOffset_ = offset.offset(); 141 } setRejoinOffset(CodeOffset offset)142 void setRejoinOffset(CodeOffset offset) { rejoinOffset_ = offset.offset(); } 143 144 void resetCodeRaw(IonScript* ionScript); 145 146 uint8_t* fallbackAddr(IonScript* ionScript) const; 147 uint8_t* rejoinAddr(IonScript* ionScript) const; 148 asGetPropertyIC()149 IonGetPropertyIC* asGetPropertyIC() { 150 MOZ_ASSERT(kind_ == CacheKind::GetProp || kind_ == CacheKind::GetElem); 151 return (IonGetPropertyIC*)this; 152 } asSetPropertyIC()153 IonSetPropertyIC* asSetPropertyIC() { 154 MOZ_ASSERT(kind_ == CacheKind::SetProp || kind_ == CacheKind::SetElem); 155 return (IonSetPropertyIC*)this; 156 } asGetPropSuperIC()157 IonGetPropSuperIC* asGetPropSuperIC() { 158 MOZ_ASSERT(kind_ == CacheKind::GetPropSuper || 159 kind_ == CacheKind::GetElemSuper); 160 return (IonGetPropSuperIC*)this; 161 } asGetNameIC()162 IonGetNameIC* asGetNameIC() { 163 MOZ_ASSERT(kind_ == CacheKind::GetName); 164 return (IonGetNameIC*)this; 165 } asBindNameIC()166 IonBindNameIC* asBindNameIC() { 167 MOZ_ASSERT(kind_ == CacheKind::BindName); 168 return (IonBindNameIC*)this; 169 } asGetIteratorIC()170 IonGetIteratorIC* asGetIteratorIC() { 171 MOZ_ASSERT(kind_ == CacheKind::GetIterator); 172 return (IonGetIteratorIC*)this; 173 } asHasOwnIC()174 IonHasOwnIC* asHasOwnIC() { 175 MOZ_ASSERT(kind_ == CacheKind::HasOwn); 176 return (IonHasOwnIC*)this; 177 } asInIC()178 IonInIC* asInIC() { 179 MOZ_ASSERT(kind_ == CacheKind::In); 180 return (IonInIC*)this; 181 } asInstanceOfIC()182 IonInstanceOfIC* asInstanceOfIC() { 183 MOZ_ASSERT(kind_ == CacheKind::InstanceOf); 184 return (IonInstanceOfIC*)this; 185 } asCompareIC()186 IonCompareIC* asCompareIC() { 187 MOZ_ASSERT(kind_ == CacheKind::Compare); 188 return (IonCompareIC*)this; 189 } asUnaryArithIC()190 IonUnaryArithIC* asUnaryArithIC() { 191 MOZ_ASSERT(kind_ == CacheKind::UnaryArith); 192 return (IonUnaryArithIC*)this; 193 } asBinaryArithIC()194 IonBinaryArithIC* asBinaryArithIC() { 195 MOZ_ASSERT(kind_ == CacheKind::BinaryArith); 196 return (IonBinaryArithIC*)this; 197 } 198 199 // Returns the Register to use as scratch when entering IC stubs. This 200 // should either be an output register or a temp. 201 Register scratchRegisterForEntryJump(); 202 203 void trace(JSTracer* trc, IonScript* ionScript); 204 205 void attachCacheIRStub(JSContext* cx, const CacheIRWriter& writer, 206 CacheKind kind, IonScript* ionScript, bool* attached, 207 const PropertyTypeCheckInfo* typeCheckInfo = nullptr); 208 }; 209 210 class IonGetPropertyIC : public IonIC { 211 private: 212 LiveRegisterSet liveRegs_; 213 214 TypedOrValueRegister value_; 215 ConstantOrRegister id_; 216 TypedOrValueRegister output_; 217 Register maybeTemp_; // Might be InvalidReg. 218 219 GetPropertyResultFlags resultFlags_; 220 221 public: IonGetPropertyIC(CacheKind kind,LiveRegisterSet liveRegs,TypedOrValueRegister value,const ConstantOrRegister & id,TypedOrValueRegister output,Register maybeTemp,GetPropertyResultFlags resultFlags)222 IonGetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, 223 TypedOrValueRegister value, const ConstantOrRegister& id, 224 TypedOrValueRegister output, Register maybeTemp, 225 GetPropertyResultFlags resultFlags) 226 : IonIC(kind), 227 liveRegs_(liveRegs), 228 value_(value), 229 id_(id), 230 output_(output), 231 maybeTemp_(maybeTemp), 232 resultFlags_(resultFlags) {} 233 value()234 TypedOrValueRegister value() const { return value_; } id()235 ConstantOrRegister id() const { return id_; } output()236 TypedOrValueRegister output() const { return output_; } maybeTemp()237 Register maybeTemp() const { return maybeTemp_; } liveRegs()238 LiveRegisterSet liveRegs() const { return liveRegs_; } resultFlags()239 GetPropertyResultFlags resultFlags() const { return resultFlags_; } monitoredResult()240 bool monitoredResult() const { 241 return resultFlags_ & GetPropertyResultFlags::Monitored; 242 } allowDoubleResult()243 bool allowDoubleResult() const { 244 return resultFlags_ & GetPropertyResultFlags::AllowDouble; 245 } 246 247 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 248 IonGetPropertyIC* ic, HandleValue val, 249 HandleValue idVal, MutableHandleValue res); 250 }; 251 252 class IonGetPropSuperIC : public IonIC { 253 LiveRegisterSet liveRegs_; 254 255 Register object_; 256 TypedOrValueRegister receiver_; 257 ConstantOrRegister id_; 258 TypedOrValueRegister output_; 259 260 public: IonGetPropSuperIC(CacheKind kind,LiveRegisterSet liveRegs,Register object,TypedOrValueRegister receiver,const ConstantOrRegister & id,TypedOrValueRegister output)261 IonGetPropSuperIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, 262 TypedOrValueRegister receiver, const ConstantOrRegister& id, 263 TypedOrValueRegister output) 264 : IonIC(kind), 265 liveRegs_(liveRegs), 266 object_(object), 267 receiver_(receiver), 268 id_(id), 269 output_(output) {} 270 object()271 Register object() const { return object_; } receiver()272 TypedOrValueRegister receiver() const { return receiver_; } id()273 ConstantOrRegister id() const { return id_; } output()274 TypedOrValueRegister output() const { return output_; } liveRegs()275 LiveRegisterSet liveRegs() const { return liveRegs_; } 276 277 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 278 IonGetPropSuperIC* ic, HandleObject obj, 279 HandleValue receiver, HandleValue idVal, 280 MutableHandleValue res); 281 }; 282 283 class IonSetPropertyIC : public IonIC { 284 LiveRegisterSet liveRegs_; 285 286 Register object_; 287 Register temp_; 288 ConstantOrRegister id_; 289 ConstantOrRegister rhs_; 290 bool strict_ : 1; 291 bool needsPostBarrier_ : 1; 292 bool needsTypeBarrier_ : 1; 293 bool guardHoles_ : 1; 294 295 public: IonSetPropertyIC(CacheKind kind,LiveRegisterSet liveRegs,Register object,Register temp,const ConstantOrRegister & id,const ConstantOrRegister & rhs,bool strict,bool needsPostBarrier,bool needsTypeBarrier,bool guardHoles)296 IonSetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, Register object, 297 Register temp, const ConstantOrRegister& id, 298 const ConstantOrRegister& rhs, bool strict, 299 bool needsPostBarrier, bool needsTypeBarrier, 300 bool guardHoles) 301 : IonIC(kind), 302 liveRegs_(liveRegs), 303 object_(object), 304 temp_(temp), 305 id_(id), 306 rhs_(rhs), 307 strict_(strict), 308 needsPostBarrier_(needsPostBarrier), 309 needsTypeBarrier_(needsTypeBarrier), 310 guardHoles_(guardHoles) {} 311 liveRegs()312 LiveRegisterSet liveRegs() const { return liveRegs_; } object()313 Register object() const { return object_; } id()314 ConstantOrRegister id() const { return id_; } rhs()315 ConstantOrRegister rhs() const { return rhs_; } 316 temp()317 Register temp() const { return temp_; } 318 strict()319 bool strict() const { return strict_; } needsPostBarrier()320 bool needsPostBarrier() const { return needsPostBarrier_; } needsTypeBarrier()321 bool needsTypeBarrier() const { return needsTypeBarrier_; } guardHoles()322 bool guardHoles() const { return guardHoles_; } 323 324 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 325 IonSetPropertyIC* ic, HandleObject obj, 326 HandleValue idVal, HandleValue rhs); 327 }; 328 329 class IonGetNameIC : public IonIC { 330 LiveRegisterSet liveRegs_; 331 332 Register environment_; 333 ValueOperand output_; 334 Register temp_; 335 336 public: IonGetNameIC(LiveRegisterSet liveRegs,Register environment,ValueOperand output,Register temp)337 IonGetNameIC(LiveRegisterSet liveRegs, Register environment, 338 ValueOperand output, Register temp) 339 : IonIC(CacheKind::GetName), 340 liveRegs_(liveRegs), 341 environment_(environment), 342 output_(output), 343 temp_(temp) {} 344 environment()345 Register environment() const { return environment_; } output()346 ValueOperand output() const { return output_; } temp()347 Register temp() const { return temp_; } liveRegs()348 LiveRegisterSet liveRegs() const { return liveRegs_; } 349 350 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 351 IonGetNameIC* ic, HandleObject envChain, 352 MutableHandleValue res); 353 }; 354 355 class IonBindNameIC : public IonIC { 356 LiveRegisterSet liveRegs_; 357 358 Register environment_; 359 Register output_; 360 Register temp_; 361 362 public: IonBindNameIC(LiveRegisterSet liveRegs,Register environment,Register output,Register temp)363 IonBindNameIC(LiveRegisterSet liveRegs, Register environment, Register output, 364 Register temp) 365 : IonIC(CacheKind::BindName), 366 liveRegs_(liveRegs), 367 environment_(environment), 368 output_(output), 369 temp_(temp) {} 370 environment()371 Register environment() const { return environment_; } output()372 Register output() const { return output_; } temp()373 Register temp() const { return temp_; } liveRegs()374 LiveRegisterSet liveRegs() const { return liveRegs_; } 375 376 static JSObject* update(JSContext* cx, HandleScript outerScript, 377 IonBindNameIC* ic, HandleObject envChain); 378 }; 379 380 class IonGetIteratorIC : public IonIC { 381 LiveRegisterSet liveRegs_; 382 TypedOrValueRegister value_; 383 Register output_; 384 Register temp1_; 385 Register temp2_; 386 387 public: IonGetIteratorIC(LiveRegisterSet liveRegs,TypedOrValueRegister value,Register output,Register temp1,Register temp2)388 IonGetIteratorIC(LiveRegisterSet liveRegs, TypedOrValueRegister value, 389 Register output, Register temp1, Register temp2) 390 : IonIC(CacheKind::GetIterator), 391 liveRegs_(liveRegs), 392 value_(value), 393 output_(output), 394 temp1_(temp1), 395 temp2_(temp2) {} 396 value()397 TypedOrValueRegister value() const { return value_; } output()398 Register output() const { return output_; } temp1()399 Register temp1() const { return temp1_; } temp2()400 Register temp2() const { return temp2_; } liveRegs()401 LiveRegisterSet liveRegs() const { return liveRegs_; } 402 403 static JSObject* update(JSContext* cx, HandleScript outerScript, 404 IonGetIteratorIC* ic, HandleValue value); 405 }; 406 407 class IonHasOwnIC : public IonIC { 408 LiveRegisterSet liveRegs_; 409 410 TypedOrValueRegister value_; 411 TypedOrValueRegister id_; 412 Register output_; 413 414 public: IonHasOwnIC(LiveRegisterSet liveRegs,TypedOrValueRegister value,TypedOrValueRegister id,Register output)415 IonHasOwnIC(LiveRegisterSet liveRegs, TypedOrValueRegister value, 416 TypedOrValueRegister id, Register output) 417 : IonIC(CacheKind::HasOwn), 418 liveRegs_(liveRegs), 419 value_(value), 420 id_(id), 421 output_(output) {} 422 value()423 TypedOrValueRegister value() const { return value_; } id()424 TypedOrValueRegister id() const { return id_; } output()425 Register output() const { return output_; } liveRegs()426 LiveRegisterSet liveRegs() const { return liveRegs_; } 427 428 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 429 IonHasOwnIC* ic, HandleValue val, 430 HandleValue idVal, int32_t* res); 431 }; 432 433 class IonInIC : public IonIC { 434 LiveRegisterSet liveRegs_; 435 436 ConstantOrRegister key_; 437 Register object_; 438 Register output_; 439 Register temp_; 440 441 public: IonInIC(LiveRegisterSet liveRegs,const ConstantOrRegister & key,Register object,Register output,Register temp)442 IonInIC(LiveRegisterSet liveRegs, const ConstantOrRegister& key, 443 Register object, Register output, Register temp) 444 : IonIC(CacheKind::In), 445 liveRegs_(liveRegs), 446 key_(key), 447 object_(object), 448 output_(output), 449 temp_(temp) {} 450 key()451 ConstantOrRegister key() const { return key_; } object()452 Register object() const { return object_; } output()453 Register output() const { return output_; } temp()454 Register temp() const { return temp_; } liveRegs()455 LiveRegisterSet liveRegs() const { return liveRegs_; } 456 457 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 458 IonInIC* ic, HandleValue key, 459 HandleObject obj, bool* res); 460 }; 461 462 class IonInstanceOfIC : public IonIC { 463 LiveRegisterSet liveRegs_; 464 465 TypedOrValueRegister lhs_; 466 Register rhs_; 467 Register output_; 468 469 public: IonInstanceOfIC(LiveRegisterSet liveRegs,TypedOrValueRegister lhs,Register rhs,Register output)470 IonInstanceOfIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, 471 Register rhs, Register output) 472 : IonIC(CacheKind::InstanceOf), 473 liveRegs_(liveRegs), 474 lhs_(lhs), 475 rhs_(rhs), 476 output_(output) {} 477 liveRegs()478 LiveRegisterSet liveRegs() const { return liveRegs_; } lhs()479 TypedOrValueRegister lhs() const { return lhs_; } rhs()480 Register rhs() const { return rhs_; } output()481 Register output() const { return output_; } 482 483 // This signature mimics that of TryAttachInstanceOfStub in baseline 484 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 485 IonInstanceOfIC* ic, HandleValue lhs, 486 HandleObject rhs, bool* attached); 487 }; 488 489 class IonCompareIC : public IonIC { 490 LiveRegisterSet liveRegs_; 491 492 TypedOrValueRegister lhs_; 493 TypedOrValueRegister rhs_; 494 Register output_; 495 496 public: IonCompareIC(LiveRegisterSet liveRegs,TypedOrValueRegister lhs,TypedOrValueRegister rhs,Register output)497 IonCompareIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, 498 TypedOrValueRegister rhs, Register output) 499 : IonIC(CacheKind::Compare), 500 liveRegs_(liveRegs), 501 lhs_(lhs), 502 rhs_(rhs), 503 output_(output) {} 504 liveRegs()505 LiveRegisterSet liveRegs() const { return liveRegs_; } lhs()506 TypedOrValueRegister lhs() const { return lhs_; } rhs()507 TypedOrValueRegister rhs() const { return rhs_; } output()508 Register output() const { return output_; } 509 510 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 511 IonCompareIC* stub, HandleValue lhs, 512 HandleValue rhs, bool* res); 513 }; 514 515 class IonUnaryArithIC : public IonIC { 516 LiveRegisterSet liveRegs_; 517 518 TypedOrValueRegister input_; 519 ValueOperand output_; 520 521 public: IonUnaryArithIC(LiveRegisterSet liveRegs,TypedOrValueRegister input,ValueOperand output)522 IonUnaryArithIC(LiveRegisterSet liveRegs, TypedOrValueRegister input, 523 ValueOperand output) 524 : IonIC(CacheKind::UnaryArith), 525 liveRegs_(liveRegs), 526 input_(input), 527 output_(output) {} 528 liveRegs()529 LiveRegisterSet liveRegs() const { return liveRegs_; } input()530 TypedOrValueRegister input() const { return input_; } output()531 ValueOperand output() const { return output_; } 532 533 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 534 IonUnaryArithIC* stub, HandleValue val, 535 MutableHandleValue res); 536 }; 537 538 class IonBinaryArithIC : public IonIC { 539 LiveRegisterSet liveRegs_; 540 541 TypedOrValueRegister lhs_; 542 TypedOrValueRegister rhs_; 543 ValueOperand output_; 544 545 public: IonBinaryArithIC(LiveRegisterSet liveRegs,TypedOrValueRegister lhs,TypedOrValueRegister rhs,ValueOperand output)546 IonBinaryArithIC(LiveRegisterSet liveRegs, TypedOrValueRegister lhs, 547 TypedOrValueRegister rhs, ValueOperand output) 548 : IonIC(CacheKind::BinaryArith), 549 liveRegs_(liveRegs), 550 lhs_(lhs), 551 rhs_(rhs), 552 output_(output) {} 553 liveRegs()554 LiveRegisterSet liveRegs() const { return liveRegs_; } lhs()555 TypedOrValueRegister lhs() const { return lhs_; } rhs()556 TypedOrValueRegister rhs() const { return rhs_; } output()557 ValueOperand output() const { return output_; } 558 559 static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, 560 IonBinaryArithIC* stub, HandleValue lhs, 561 HandleValue rhs, MutableHandleValue res); 562 }; 563 564 } // namespace jit 565 } // namespace js 566 567 #endif /* jit_IonIC_h */ 568