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