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_CacheIR_h
8 #define jit_CacheIR_h
9 
10 #include "mozilla/Maybe.h"
11 
12 #include "jsmath.h"
13 
14 #include "NamespaceImports.h"
15 
16 #include "gc/Rooting.h"
17 #include "jit/CacheIROpsGenerated.h"
18 #include "jit/CompactBuffer.h"
19 #include "jit/ICState.h"
20 #include "jit/MacroAssembler.h"
21 #include "jit/Simulator.h"
22 #include "vm/Iteration.h"
23 #include "vm/Shape.h"
24 
25 namespace js {
26 namespace jit {
27 
28 enum class BaselineCacheIRStubKind;
29 
30 // [SMDOC] CacheIR
31 //
32 // CacheIR is an (extremely simple) linear IR language for inline caches.
33 // From this IR, we can generate machine code for Baseline or Ion IC stubs.
34 //
35 // IRWriter
36 // --------
37 // CacheIR bytecode is written using IRWriter. This class also records some
38 // metadata that's used by the Baseline and Ion code generators to generate
39 // (efficient) machine code.
40 //
41 // Sharing Baseline stub code
42 // --------------------------
43 // Baseline stores data (like Shape* and fixed slot offsets) inside the ICStub
44 // structure, instead of embedding them directly in the JitCode. This makes
45 // Baseline IC code slightly slower, but allows us to share IC code between
46 // caches. CacheIR makes it easy to share code between stubs: stubs that have
47 // the same CacheIR (and CacheKind), will have the same Baseline stub code.
48 //
49 // Baseline stubs that share JitCode also share a CacheIRStubInfo structure.
50 // This class stores the CacheIR and the location of GC things stored in the
51 // stub, for the GC.
52 //
53 // JitZone has a CacheIRStubInfo* -> JitCode* weak map that's used to share both
54 // the IR and JitCode between Baseline CacheIR stubs. This HashMap owns the
55 // stubInfo (it uses UniquePtr), so once there are no references left to the
56 // shared stub code, we can also free the CacheIRStubInfo.
57 //
58 // Ion stubs
59 // ---------
60 // Unlike Baseline stubs, Ion stubs do not share stub code, and data stored in
61 // the IonICStub is baked into JIT code. This is one of the reasons Ion stubs
62 // are faster than Baseline stubs. Also note that Ion ICs contain more state
63 // (see IonGetPropertyIC for example) and use dynamic input/output registers,
64 // so sharing stub code for Ion would be much more difficult.
65 
66 // An OperandId represents either a cache input or a value returned by a
67 // CacheIR instruction. Most code should use the ValOperandId and ObjOperandId
68 // classes below. The ObjOperandId class represents an operand that's known to
69 // be an object, just as StringOperandId represents a known string, etc.
70 class OperandId {
71  protected:
72   static const uint16_t InvalidId = UINT16_MAX;
73   uint16_t id_;
74 
OperandId()75   OperandId() : id_(InvalidId) {}
OperandId(uint16_t id)76   explicit OperandId(uint16_t id) : id_(id) {}
77 
78  public:
id()79   uint16_t id() const { return id_; }
valid()80   bool valid() const { return id_ != InvalidId; }
81 };
82 
83 class ValOperandId : public OperandId {
84  public:
85   ValOperandId() = default;
ValOperandId(uint16_t id)86   explicit ValOperandId(uint16_t id) : OperandId(id) {}
87 };
88 
89 class ValueTagOperandId : public OperandId {
90  public:
91   ValueTagOperandId() = default;
ValueTagOperandId(uint16_t id)92   explicit ValueTagOperandId(uint16_t id) : OperandId(id) {}
93 };
94 
95 class ObjOperandId : public OperandId {
96  public:
97   ObjOperandId() = default;
ObjOperandId(uint16_t id)98   explicit ObjOperandId(uint16_t id) : OperandId(id) {}
99 
100   bool operator==(const ObjOperandId& other) const { return id_ == other.id_; }
101   bool operator!=(const ObjOperandId& other) const { return id_ != other.id_; }
102 };
103 
104 class NumberOperandId : public ValOperandId {
105  public:
106   NumberOperandId() = default;
NumberOperandId(uint16_t id)107   explicit NumberOperandId(uint16_t id) : ValOperandId(id) {}
108 };
109 
110 class StringOperandId : public OperandId {
111  public:
112   StringOperandId() = default;
StringOperandId(uint16_t id)113   explicit StringOperandId(uint16_t id) : OperandId(id) {}
114 };
115 
116 class SymbolOperandId : public OperandId {
117  public:
118   SymbolOperandId() = default;
SymbolOperandId(uint16_t id)119   explicit SymbolOperandId(uint16_t id) : OperandId(id) {}
120 };
121 
122 class BigIntOperandId : public OperandId {
123  public:
124   BigIntOperandId() = default;
BigIntOperandId(uint16_t id)125   explicit BigIntOperandId(uint16_t id) : OperandId(id) {}
126 };
127 
128 class Int32OperandId : public OperandId {
129  public:
130   Int32OperandId() = default;
Int32OperandId(uint16_t id)131   explicit Int32OperandId(uint16_t id) : OperandId(id) {}
132 };
133 
134 class TypedOperandId : public OperandId {
135   JSValueType type_;
136 
137  public:
TypedOperandId(ObjOperandId id)138   MOZ_IMPLICIT TypedOperandId(ObjOperandId id)
139       : OperandId(id.id()), type_(JSVAL_TYPE_OBJECT) {}
TypedOperandId(StringOperandId id)140   MOZ_IMPLICIT TypedOperandId(StringOperandId id)
141       : OperandId(id.id()), type_(JSVAL_TYPE_STRING) {}
TypedOperandId(SymbolOperandId id)142   MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
143       : OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL) {}
TypedOperandId(BigIntOperandId id)144   MOZ_IMPLICIT TypedOperandId(BigIntOperandId id)
145       : OperandId(id.id()), type_(JSVAL_TYPE_BIGINT) {}
TypedOperandId(Int32OperandId id)146   MOZ_IMPLICIT TypedOperandId(Int32OperandId id)
147       : OperandId(id.id()), type_(JSVAL_TYPE_INT32) {}
TypedOperandId(ValueTagOperandId val)148   MOZ_IMPLICIT TypedOperandId(ValueTagOperandId val)
149       : OperandId(val.id()), type_(JSVAL_TYPE_UNKNOWN) {}
TypedOperandId(ValOperandId val,JSValueType type)150   TypedOperandId(ValOperandId val, JSValueType type)
151       : OperandId(val.id()), type_(type) {}
152 
type()153   JSValueType type() const { return type_; }
154 };
155 
156 #define CACHE_IR_KINDS(_) \
157   _(GetProp)              \
158   _(GetElem)              \
159   _(GetName)              \
160   _(GetPropSuper)         \
161   _(GetElemSuper)         \
162   _(GetIntrinsic)         \
163   _(SetProp)              \
164   _(SetElem)              \
165   _(BindName)             \
166   _(In)                   \
167   _(HasOwn)               \
168   _(TypeOf)               \
169   _(InstanceOf)           \
170   _(GetIterator)          \
171   _(Compare)              \
172   _(ToBool)               \
173   _(Call)                 \
174   _(UnaryArith)           \
175   _(BinaryArith)          \
176   _(NewObject)
177 
178 enum class CacheKind : uint8_t {
179 #define DEFINE_KIND(kind) kind,
180   CACHE_IR_KINDS(DEFINE_KIND)
181 #undef DEFINE_KIND
182 };
183 
184 extern const char* const CacheKindNames[];
185 
186 #ifdef DEBUG
187 extern size_t NumInputsForCacheKind(CacheKind kind);
188 #endif
189 
190 enum class CacheOp {
191 #define DEFINE_OP(op, ...) op,
192   CACHE_IR_OPS(DEFINE_OP)
193 #undef DEFINE_OP
194 };
195 
196 extern const char* const CacheIROpNames[];
197 extern const uint32_t CacheIROpArgLengths[];
198 
199 class StubField {
200  public:
201   enum class Type : uint8_t {
202     // These fields take up a single word.
203     RawWord,
204     Shape,
205     ObjectGroup,
206     JSObject,
207     Symbol,
208     String,
209     Id,
210 
211     // These fields take up 64 bits on all platforms.
212     RawInt64,
213     First64BitType = RawInt64,
214     DOMExpandoGeneration,
215     Value,
216 
217     Limit
218   };
219 
sizeIsWord(Type type)220   static bool sizeIsWord(Type type) {
221     MOZ_ASSERT(type != Type::Limit);
222     return type < Type::First64BitType;
223   }
224 
sizeIsInt64(Type type)225   static bool sizeIsInt64(Type type) {
226     MOZ_ASSERT(type != Type::Limit);
227     return type >= Type::First64BitType;
228   }
229 
sizeInBytes(Type type)230   static size_t sizeInBytes(Type type) {
231     if (sizeIsWord(type)) {
232       return sizeof(uintptr_t);
233     }
234     MOZ_ASSERT(sizeIsInt64(type));
235     return sizeof(int64_t);
236   }
237 
238  private:
239   uint64_t data_;
240   Type type_;
241 
242  public:
StubField(uint64_t data,Type type)243   StubField(uint64_t data, Type type) : data_(data), type_(type) {
244     MOZ_ASSERT_IF(sizeIsWord(), data <= UINTPTR_MAX);
245   }
246 
type()247   Type type() const { return type_; }
248 
sizeIsWord()249   bool sizeIsWord() const { return sizeIsWord(type_); }
sizeIsInt64()250   bool sizeIsInt64() const { return sizeIsInt64(type_); }
251 
asWord()252   uintptr_t asWord() const {
253     MOZ_ASSERT(sizeIsWord());
254     return uintptr_t(data_);
255   }
asInt64()256   uint64_t asInt64() const {
257     MOZ_ASSERT(sizeIsInt64());
258     return data_;
259   }
260 } JS_HAZ_GC_POINTER;
261 
262 // This class is used to wrap up information about a call to make it
263 // easier to convey from one function to another. (In particular,
264 // CacheIRWriter encodes the CallFlags in CacheIR, and CacheIRReader
265 // decodes them and uses them for compilation.)
266 class CallFlags {
267  public:
268   enum ArgFormat : uint8_t {
269     Standard,
270     Spread,
271     FunCall,
272     FunApplyArgs,
273     FunApplyArray,
274     LastArgFormat = FunApplyArray
275   };
276 
277   CallFlags(bool isConstructing, bool isSpread, bool isSameRealm = false)
278       : argFormat_(isSpread ? Spread : Standard),
279         isConstructing_(isConstructing),
280         isSameRealm_(isSameRealm) {}
CallFlags(ArgFormat format)281   explicit CallFlags(ArgFormat format)
282       : argFormat_(format), isConstructing_(false), isSameRealm_(false) {}
283 
getArgFormat()284   ArgFormat getArgFormat() const { return argFormat_; }
isConstructing()285   bool isConstructing() const {
286     MOZ_ASSERT_IF(isConstructing_,
287                   argFormat_ == Standard || argFormat_ == Spread);
288     return isConstructing_;
289   }
isSameRealm()290   bool isSameRealm() const { return isSameRealm_; }
291 
toByte()292   uint8_t toByte() const {
293     // See CacheIRReader::callFlags()
294     uint8_t value = getArgFormat();
295     if (isConstructing()) {
296       value |= CallFlags::IsConstructing;
297     }
298     if (isSameRealm()) {
299       value |= CallFlags::IsSameRealm;
300     }
301     return value;
302   }
303 
304  private:
305   ArgFormat argFormat_;
306   bool isConstructing_;
307   bool isSameRealm_;
308 
309   // Used for encoding/decoding
310   static const uint8_t ArgFormatBits = 4;
311   static const uint8_t ArgFormatMask = (1 << ArgFormatBits) - 1;
312   static_assert(LastArgFormat <= ArgFormatMask, "Not enough arg format bits");
313   static const uint8_t IsConstructing = 1 << 5;
314   static const uint8_t IsSameRealm = 1 << 6;
315 
316   friend class CacheIRReader;
317   friend class CacheIRWriter;
318 };
319 
320 enum class AttachDecision {
321   // We cannot attach a stub.
322   NoAction,
323 
324   // We can attach a stub.
325   Attach,
326 
327   // We cannot currently attach a stub, but we expect to be able to do so in the
328   // future. In this case, we do not call trackNotAttached().
329   TemporarilyUnoptimizable,
330 
331   // We want to attach a stub, but the result of the operation is
332   // needed to generate that stub. For example, AddSlot needs to know
333   // the resulting shape. Note: the attached stub will inspect the
334   // inputs to the operation, so most input checks should be done
335   // before the actual operation, with only minimal checks remaining
336   // for the deferred portion. This prevents arbitrary scripted code
337   // run by the operation from interfering with the conditions being
338   // checked.
339   Deferred
340 };
341 
342 // If the input expression evaluates to an AttachDecision other than NoAction,
343 // return that AttachDecision. If it is NoAction, do nothing.
344 #define TRY_ATTACH(expr)                                    \
345   do {                                                      \
346     AttachDecision tryAttachTempResult_ = expr;             \
347     if (tryAttachTempResult_ != AttachDecision::NoAction) { \
348       return tryAttachTempResult_;                          \
349     }                                                       \
350   } while (0)
351 
352 // Set of arguments supported by GetIndexOfArgument.
353 // Support for Arg2 and up can be added easily, but is currently unneeded.
354 enum class ArgumentKind : uint8_t { Callee, This, NewTarget, Arg0, Arg1 };
355 
356 // This function calculates the index of an argument based on the call flags.
357 // addArgc is an out-parameter, indicating whether the value of argc should
358 // be added to the return value to find the actual index.
GetIndexOfArgument(ArgumentKind kind,CallFlags flags,bool * addArgc)359 inline int32_t GetIndexOfArgument(ArgumentKind kind, CallFlags flags,
360                                   bool* addArgc) {
361   // *** STACK LAYOUT (bottom to top) ***        ******** INDEX ********
362   //   Callee                                <-- argc+1 + isConstructing
363   //   ThisValue                             <-- argc   + isConstructing
364   //   Args: | Arg0 |        |  ArgArray  |  <-- argc-1 + isConstructing
365   //         | Arg1 | --or-- |            |  <-- argc-2 + isConstructing
366   //         | ...  |        | (if spread |  <-- ...
367   //         | ArgN |        |  call)     |  <-- 0      + isConstructing
368   //   NewTarget (only if constructing)      <-- 0 (if it exists)
369   //
370   // If this is a spread call, then argc is always 1, and we can calculate the
371   // index directly. If this is not a spread call, then the index of any
372   // argument other than NewTarget depends on argc.
373 
374   // First we determine whether the caller needs to add argc.
375   switch (flags.getArgFormat()) {
376     case CallFlags::Standard:
377       *addArgc = true;
378       break;
379     case CallFlags::Spread:
380       // Spread calls do not have Arg1 or higher.
381       MOZ_ASSERT(kind != ArgumentKind::Arg1);
382       *addArgc = false;
383       break;
384     case CallFlags::FunCall:
385     case CallFlags::FunApplyArgs:
386     case CallFlags::FunApplyArray:
387       MOZ_CRASH("Currently unreachable");
388       break;
389   }
390 
391   // Second, we determine the offset relative to argc.
392   bool hasArgumentArray = !*addArgc;
393   switch (kind) {
394     case ArgumentKind::Callee:
395       return flags.isConstructing() + hasArgumentArray + 1;
396     case ArgumentKind::This:
397       return flags.isConstructing() + hasArgumentArray;
398     case ArgumentKind::Arg0:
399       return flags.isConstructing() + hasArgumentArray - 1;
400     case ArgumentKind::Arg1:
401       return flags.isConstructing() + hasArgumentArray - 2;
402     case ArgumentKind::NewTarget:
403       MOZ_ASSERT(flags.isConstructing());
404       *addArgc = false;
405       return 0;
406     default:
407       MOZ_CRASH("Invalid argument kind");
408   }
409 }
410 
411 // We use this enum as GuardClass operand, instead of storing Class* pointers
412 // in the IR, to keep the IR compact and the same size on all platforms.
413 enum class GuardClassKind : uint8_t {
414   Array,
415   MappedArguments,
416   UnmappedArguments,
417   WindowProxy,
418   JSFunction,
419 };
420 
421 // Some ops refer to shapes that might be in other zones. Instead of putting
422 // cross-zone pointers in the caches themselves (which would complicate tracing
423 // enormously), these ops instead contain wrappers for objects in the target
424 // zone, which refer to the actual shape via a reserved slot.
425 JSObject* NewWrapperWithObjectShape(JSContext* cx, HandleNativeObject obj);
426 
427 // Enum for stubs handling a combination of typed arrays and typed objects.
428 enum class TypedThingLayout : uint8_t {
429   TypedArray,
430   OutlineTypedObject,
431   InlineTypedObject
432 };
433 
434 void LoadShapeWrapperContents(MacroAssembler& masm, Register obj, Register dst,
435                               Label* failure);
436 
437 enum class MetaTwoByteKind : uint8_t {
438   NativeTemplateObject,
439   ScriptedTemplateObject,
440 };
441 
442 #ifdef JS_SIMULATOR
443 bool CallAnyNative(JSContext* cx, unsigned argc, Value* vp);
444 #endif
445 
446 // Class to record CacheIR + some additional metadata for code generation.
447 class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
448   JSContext* cx_;
449   CompactBufferWriter buffer_;
450 
451   uint32_t nextOperandId_;
452   uint32_t nextInstructionId_;
453   uint32_t numInputOperands_;
454 
455   // The data (shapes, slot offsets, etc.) that will be stored in the ICStub.
456   Vector<StubField, 8, SystemAllocPolicy> stubFields_;
457   size_t stubDataSize_;
458 
459   // For each operand id, record which instruction accessed it last. This
460   // information greatly improves register allocation.
461   Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
462 
463   // OperandId and stub offsets are stored in a single byte, so make sure
464   // this doesn't overflow. We use a very conservative limit for now.
465   static const size_t MaxOperandIds = 20;
466   static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
467   bool tooLarge_;
468 
469   // Basic caching to avoid quadatic lookup behaviour in readStubFieldForIon.
470   mutable uint32_t lastOffset_;
471   mutable uint32_t lastIndex_;
472 
473 #ifdef DEBUG
474   // Information for assertLengthMatches.
475   mozilla::Maybe<CacheOp> currentOp_;
476   size_t currentOpArgsStart_ = 0;
477 #endif
478 
479   void assertSameCompartment(JSObject*);
480 
writeOp(CacheOp op)481   void writeOp(CacheOp op) {
482     MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
483     buffer_.writeByte(uint32_t(op));
484     nextInstructionId_++;
485 #ifdef DEBUG
486     MOZ_ASSERT(currentOp_.isNothing(), "Missing call to assertLengthMatches?");
487     currentOp_.emplace(op);
488     currentOpArgsStart_ = buffer_.length();
489 #endif
490   }
491 
assertLengthMatches()492   void assertLengthMatches() {
493 #ifdef DEBUG
494     // After writing arguments, assert the length matches CacheIROpArgLengths.
495     size_t expectedLen = CacheIROpArgLengths[size_t(*currentOp_)];
496     MOZ_ASSERT_IF(!failed(),
497                   buffer_.length() - currentOpArgsStart_ == expectedLen);
498     currentOp_.reset();
499 #endif
500   }
501 
writeOperandId(OperandId opId)502   void writeOperandId(OperandId opId) {
503     if (opId.id() < MaxOperandIds) {
504       static_assert(MaxOperandIds <= UINT8_MAX,
505                     "operand id must fit in a single byte");
506       buffer_.writeByte(opId.id());
507     } else {
508       tooLarge_ = true;
509       return;
510     }
511     if (opId.id() >= operandLastUsed_.length()) {
512       buffer_.propagateOOM(operandLastUsed_.resize(opId.id() + 1));
513       if (buffer_.oom()) {
514         return;
515       }
516     }
517     MOZ_ASSERT(nextInstructionId_ > 0);
518     operandLastUsed_[opId.id()] = nextInstructionId_ - 1;
519   }
520 
writeCallFlagsImm(CallFlags flags)521   void writeCallFlagsImm(CallFlags flags) { buffer_.writeByte(flags.toByte()); }
522 
addStubField(uint64_t value,StubField::Type fieldType)523   uint8_t addStubField(uint64_t value, StubField::Type fieldType) {
524     uint8_t offset = 0;
525     size_t newStubDataSize = stubDataSize_ + StubField::sizeInBytes(fieldType);
526     if (newStubDataSize < MaxStubDataSizeInBytes) {
527       buffer_.propagateOOM(stubFields_.append(StubField(value, fieldType)));
528       MOZ_ASSERT((stubDataSize_ % sizeof(uintptr_t)) == 0);
529       offset = stubDataSize_ / sizeof(uintptr_t);
530       buffer_.writeByte(offset);
531       stubDataSize_ = newStubDataSize;
532     } else {
533       tooLarge_ = true;
534     }
535     return offset;
536   }
537 
writeShapeField(Shape * shape)538   void writeShapeField(Shape* shape) {
539     MOZ_ASSERT(shape);
540     addStubField(uintptr_t(shape), StubField::Type::Shape);
541   }
writeGroupField(ObjectGroup * group)542   void writeGroupField(ObjectGroup* group) {
543     MOZ_ASSERT(group);
544     addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
545   }
writeObjectField(JSObject * obj)546   void writeObjectField(JSObject* obj) {
547     assertSameCompartment(obj);
548     addStubField(uintptr_t(obj), StubField::Type::JSObject);
549   }
writeStringField(JSString * str)550   void writeStringField(JSString* str) {
551     MOZ_ASSERT(str);
552     addStubField(uintptr_t(str), StubField::Type::String);
553   }
writeSymbolField(JS::Symbol * sym)554   void writeSymbolField(JS::Symbol* sym) {
555     MOZ_ASSERT(sym);
556     addStubField(uintptr_t(sym), StubField::Type::Symbol);
557   }
writeRawWordField(uintptr_t word)558   void writeRawWordField(uintptr_t word) {
559     addStubField(word, StubField::Type::RawWord);
560   }
writeRawPointerField(const void * ptr)561   void writeRawPointerField(const void* ptr) {
562     addStubField(uintptr_t(ptr), StubField::Type::RawWord);
563   }
writeIdField(jsid id)564   void writeIdField(jsid id) {
565     addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
566   }
writeValueField(const Value & val)567   void writeValueField(const Value& val) {
568     addStubField(val.asRawBits(), StubField::Type::Value);
569   }
writeDOMExpandoGenerationField(uint64_t generation)570   void writeDOMExpandoGenerationField(uint64_t generation) {
571     addStubField(generation, StubField::Type::DOMExpandoGeneration);
572   }
573 
writeJSOpImm(JSOp op)574   void writeJSOpImm(JSOp op) {
575     static_assert(sizeof(JSOp) == sizeof(uint8_t), "JSOp must fit in a byte");
576     buffer_.writeByte(uint8_t(op));
577   }
writeGuardClassKindImm(GuardClassKind kind)578   void writeGuardClassKindImm(GuardClassKind kind) {
579     static_assert(sizeof(GuardClassKind) == sizeof(uint8_t),
580                   "GuardClassKind must fit in a byte");
581     buffer_.writeByte(uint8_t(kind));
582   }
writeValueTypeImm(ValueType type)583   void writeValueTypeImm(ValueType type) {
584     static_assert(sizeof(ValueType) == sizeof(uint8_t),
585                   "ValueType must fit in uint8_t");
586     buffer_.writeByte(uint8_t(type));
587   }
writeJSWhyMagicImm(JSWhyMagic whyMagic)588   void writeJSWhyMagicImm(JSWhyMagic whyMagic) {
589     static_assert(JS_WHY_MAGIC_COUNT <= UINT8_MAX,
590                   "JSWhyMagic must fit in uint8_t");
591     buffer_.writeByte(uint8_t(whyMagic));
592   }
writeTypedThingLayoutImm(TypedThingLayout layout)593   void writeTypedThingLayoutImm(TypedThingLayout layout) {
594     static_assert(sizeof(TypedThingLayout) == sizeof(uint8_t),
595                   "TypedThingLayout must fit in a byte");
596     buffer_.writeByte(uint8_t(layout));
597   }
writeReferenceTypeImm(ReferenceType type)598   void writeReferenceTypeImm(ReferenceType type) {
599     MOZ_ASSERT(size_t(type) <= UINT8_MAX);
600     buffer_.writeByte(uint8_t(type));
601   }
writeScalarTypeImm(Scalar::Type type)602   void writeScalarTypeImm(Scalar::Type type) {
603     MOZ_ASSERT(size_t(type) <= UINT8_MAX);
604     buffer_.writeByte(uint8_t(type));
605   }
writeMetaTwoByteKindImm(MetaTwoByteKind kind)606   void writeMetaTwoByteKindImm(MetaTwoByteKind kind) {
607     static_assert(sizeof(MetaTwoByteKind) == sizeof(uint8_t),
608                   "MetaTwoByteKind must fit in a byte");
609     buffer_.writeByte(uint8_t(kind));
610   }
writeUnaryMathFunctionImm(UnaryMathFunction fun)611   void writeUnaryMathFunctionImm(UnaryMathFunction fun) {
612     static_assert(sizeof(UnaryMathFunction) == sizeof(uint8_t),
613                   "UnaryMathFunction must fit in a byte");
614     buffer_.writeByte(uint8_t(fun));
615   }
writeBoolImm(bool b)616   void writeBoolImm(bool b) { buffer_.writeByte(uint32_t(b)); }
617 
writeByteImm(uint32_t b)618   void writeByteImm(uint32_t b) {
619     MOZ_ASSERT(b <= UINT8_MAX);
620     buffer_.writeByte(b);
621   }
622 
writeInt32Imm(int32_t i32)623   void writeInt32Imm(int32_t i32) { buffer_.writeFixedUint32_t(i32); }
writeUInt32Imm(uint32_t u32)624   void writeUInt32Imm(uint32_t u32) { buffer_.writeFixedUint32_t(u32); }
writePointer(const void * ptr)625   void writePointer(const void* ptr) { buffer_.writeRawPointer(ptr); }
626 
writeJSNativeImm(JSNative native)627   void writeJSNativeImm(JSNative native) {
628     writePointer(JS_FUNC_TO_DATA_PTR(void*, native));
629   }
writeStaticStringImm(const char * str)630   void writeStaticStringImm(const char* str) { writePointer(str); }
631 
newOperandId()632   uint32_t newOperandId() { return nextOperandId_++; }
633 
634   CacheIRWriter(const CacheIRWriter&) = delete;
635   CacheIRWriter& operator=(const CacheIRWriter&) = delete;
636 
637  public:
CacheIRWriter(JSContext * cx)638   explicit CacheIRWriter(JSContext* cx)
639       : CustomAutoRooter(cx),
640         cx_(cx),
641         nextOperandId_(0),
642         nextInstructionId_(0),
643         numInputOperands_(0),
644         stubDataSize_(0),
645         tooLarge_(false),
646         lastOffset_(0),
647         lastIndex_(0) {}
648 
failed()649   bool failed() const { return buffer_.oom() || tooLarge_; }
650 
numInputOperands()651   uint32_t numInputOperands() const { return numInputOperands_; }
numOperandIds()652   uint32_t numOperandIds() const { return nextOperandId_; }
numInstructions()653   uint32_t numInstructions() const { return nextInstructionId_; }
654 
numStubFields()655   size_t numStubFields() const { return stubFields_.length(); }
stubFieldType(uint32_t i)656   StubField::Type stubFieldType(uint32_t i) const {
657     return stubFields_[i].type();
658   }
659 
setInputOperandId(uint32_t op)660   uint32_t setInputOperandId(uint32_t op) {
661     MOZ_ASSERT(op == nextOperandId_);
662     nextOperandId_++;
663     numInputOperands_++;
664     return op;
665   }
666 
trace(JSTracer * trc)667   void trace(JSTracer* trc) override {
668     // For now, assert we only GC before we append stub fields.
669     MOZ_RELEASE_ASSERT(stubFields_.empty());
670   }
671 
stubDataSize()672   size_t stubDataSize() const { return stubDataSize_; }
673   void copyStubData(uint8_t* dest) const;
674   bool stubDataEqualsMaybeUpdate(uint8_t* stubData, bool* updated) const;
675 
operandIsDead(uint32_t operandId,uint32_t currentInstruction)676   bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
677     if (operandId >= operandLastUsed_.length()) {
678       return false;
679     }
680     return currentInstruction > operandLastUsed_[operandId];
681   }
682 
codeStart()683   const uint8_t* codeStart() const {
684     MOZ_ASSERT(!failed());
685     return buffer_.buffer();
686   }
687 
codeEnd()688   const uint8_t* codeEnd() const {
689     MOZ_ASSERT(!failed());
690     return buffer_.buffer() + buffer_.length();
691   }
692 
codeLength()693   uint32_t codeLength() const {
694     MOZ_ASSERT(!failed());
695     return buffer_.length();
696   }
697 
698   // This should not be used when compiling Baseline code, as Baseline code
699   // shouldn't bake in stub values.
700   StubField readStubFieldForIon(uint32_t offset, StubField::Type type) const;
701 
guardToObject(ValOperandId input)702   ObjOperandId guardToObject(ValOperandId input) {
703     guardToObject_(input);
704     return ObjOperandId(input.id());
705   }
706 
guardToString(ValOperandId input)707   StringOperandId guardToString(ValOperandId input) {
708     guardToString_(input);
709     return StringOperandId(input.id());
710   }
711 
guardToSymbol(ValOperandId input)712   SymbolOperandId guardToSymbol(ValOperandId input) {
713     guardToSymbol_(input);
714     return SymbolOperandId(input.id());
715   }
716 
guardToBigInt(ValOperandId input)717   BigIntOperandId guardToBigInt(ValOperandId input) {
718     guardToBigInt_(input);
719     return BigIntOperandId(input.id());
720   }
721 
guardIsNumber(ValOperandId input)722   NumberOperandId guardIsNumber(ValOperandId input) {
723     guardIsNumber_(input);
724     return NumberOperandId(input.id());
725   }
726 
guardShapeForClass(ObjOperandId obj,Shape * shape)727   void guardShapeForClass(ObjOperandId obj, Shape* shape) {
728     // Guard shape to ensure that object class is unchanged. This is true
729     // for all shapes.
730     guardShape(obj, shape);
731   }
732 
guardShapeForOwnProperties(ObjOperandId obj,Shape * shape)733   void guardShapeForOwnProperties(ObjOperandId obj, Shape* shape) {
734     // Guard shape to detect changes to (non-dense) own properties. This
735     // also implies |guardShapeForClass|.
736     MOZ_ASSERT(shape->getObjectClass()->isNative());
737     guardShape(obj, shape);
738   }
739 
740  public:
741   // Instead of calling guardGroup manually, use (or create) a specialization
742   // below to clarify what constraint the group guard is implying.
guardGroupForProto(ObjOperandId obj,ObjectGroup * group)743   void guardGroupForProto(ObjOperandId obj, ObjectGroup* group) {
744     MOZ_ASSERT(!group->hasUncacheableProto());
745     guardGroup(obj, group);
746   }
747 
guardGroupForTypeBarrier(ObjOperandId obj,ObjectGroup * group)748   void guardGroupForTypeBarrier(ObjOperandId obj, ObjectGroup* group) {
749     // Typesets will always be a super-set of any typesets previously seen
750     // for this group. If the type/group of a value being stored to a
751     // property in this group is not known, a TypeUpdate IC chain should be
752     // used as well.
753     guardGroup(obj, group);
754   }
755 
guardGroupForLayout(ObjOperandId obj,ObjectGroup * group)756   void guardGroupForLayout(ObjOperandId obj, ObjectGroup* group) {
757     // NOTE: Comment in guardGroupForTypeBarrier also applies.
758     MOZ_ASSERT(IsTypedObjectClass(group->clasp()));
759     guardGroup(obj, group);
760   }
761 
guardSpecificFunction(ObjOperandId obj,JSFunction * expected)762   void guardSpecificFunction(ObjOperandId obj, JSFunction* expected) {
763     // Guard object is a specific function. This implies immutable fields on
764     // the JSFunction struct itself are unchanged.
765     // Bake in the nargs and FunctionFlags so Warp can use them off-main thread,
766     // instead of directly using the JSFunction fields.
767     static_assert(JSFunction::NArgsBits == 16);
768     static_assert(sizeof(decltype(expected->flags().toRaw())) ==
769                   sizeof(uint16_t));
770 
771     uint32_t nargsAndFlags =
772         (uint32_t(expected->nargs()) << 16) | expected->flags().toRaw();
773     guardSpecificFunction_(obj, expected, nargsAndFlags);
774   }
775 
776   ValOperandId loadArgumentFixedSlot(
777       ArgumentKind kind, uint32_t argc,
778       CallFlags flags = CallFlags(CallFlags::Standard)) {
779     bool addArgc;
780     int32_t slotIndex = GetIndexOfArgument(kind, flags, &addArgc);
781     if (addArgc) {
782       slotIndex += argc;
783     }
784     MOZ_ASSERT(slotIndex >= 0);
785     MOZ_ASSERT(slotIndex <= UINT8_MAX);
786     return loadArgumentFixedSlot_(slotIndex);
787   }
788 
789   ValOperandId loadArgumentDynamicSlot(
790       ArgumentKind kind, Int32OperandId argcId,
791       CallFlags flags = CallFlags(CallFlags::Standard)) {
792     bool addArgc;
793     int32_t slotIndex = GetIndexOfArgument(kind, flags, &addArgc);
794     if (addArgc) {
795       return loadArgumentDynamicSlot_(argcId, slotIndex);
796     }
797     return loadArgumentFixedSlot_(slotIndex);
798   }
799 
callNativeFunction(ObjOperandId calleeId,Int32OperandId argc,JSOp op,HandleFunction calleeFunc,CallFlags flags)800   void callNativeFunction(ObjOperandId calleeId, Int32OperandId argc, JSOp op,
801                           HandleFunction calleeFunc, CallFlags flags) {
802     // Some native functions can be implemented faster if we know that
803     // the return value is ignored.
804     bool ignoresReturnValue =
805         op == JSOp::CallIgnoresRv && calleeFunc->hasJitInfo() &&
806         calleeFunc->jitInfo()->type() == JSJitInfo::IgnoresReturnValueNative;
807 
808 #ifdef JS_SIMULATOR
809     // The simulator requires VM calls to be redirected to a special
810     // swi instruction to handle them, so we store the redirected
811     // pointer in the stub and use that instead of the original one.
812     // If we are calling the ignoresReturnValue version of a native
813     // function, we bake it into the redirected pointer.
814     // (See BaselineCacheIRCompiler::emitCallNativeFunction.)
815     JSNative target = ignoresReturnValue
816                           ? calleeFunc->jitInfo()->ignoresReturnValueMethod
817                           : calleeFunc->native();
818     void* rawPtr = JS_FUNC_TO_DATA_PTR(void*, target);
819     void* redirected = Simulator::RedirectNativeFunction(rawPtr, Args_General3);
820     callNativeFunction_(calleeId, argc, flags, redirected);
821 #else
822     // If we are not running in the simulator, we generate different jitcode
823     // to find the ignoresReturnValue version of a native function.
824     callNativeFunction_(calleeId, argc, flags, ignoresReturnValue);
825 #endif
826   }
827 
callAnyNativeFunction(ObjOperandId calleeId,Int32OperandId argc,CallFlags flags)828   void callAnyNativeFunction(ObjOperandId calleeId, Int32OperandId argc,
829                              CallFlags flags) {
830     MOZ_ASSERT(!flags.isSameRealm());
831 #ifdef JS_SIMULATOR
832     // The simulator requires native calls to be redirected to a
833     // special swi instruction. If we are calling an arbitrary native
834     // function, we can't wrap the real target ahead of time, so we
835     // call a wrapper function (CallAnyNative) that calls the target
836     // itself, and redirect that wrapper.
837     JSNative target = CallAnyNative;
838     void* rawPtr = JS_FUNC_TO_DATA_PTR(void*, target);
839     void* redirected = Simulator::RedirectNativeFunction(rawPtr, Args_General3);
840     callNativeFunction_(calleeId, argc, flags, redirected);
841 #else
842     callNativeFunction_(calleeId, argc, flags,
843                         /* ignoresReturnValue = */ false);
844 #endif
845   }
846 
callClassHook(ObjOperandId calleeId,Int32OperandId argc,JSNative hook,CallFlags flags)847   void callClassHook(ObjOperandId calleeId, Int32OperandId argc, JSNative hook,
848                      CallFlags flags) {
849     MOZ_ASSERT(!flags.isSameRealm());
850     void* target = JS_FUNC_TO_DATA_PTR(void*, hook);
851 #ifdef JS_SIMULATOR
852     // The simulator requires VM calls to be redirected to a special
853     // swi instruction to handle them, so we store the redirected
854     // pointer in the stub and use that instead of the original one.
855     target = Simulator::RedirectNativeFunction(target, Args_General3);
856 #endif
857     callClassHook_(calleeId, argc, flags, target);
858   }
859 
860   // These generate no code, but save the template object in a stub
861   // field for BaselineInspector.
metaNativeTemplateObject(JSFunction * callee,JSObject * templateObject)862   void metaNativeTemplateObject(JSFunction* callee, JSObject* templateObject) {
863     metaTwoByte_(MetaTwoByteKind::NativeTemplateObject, callee, templateObject);
864   }
865 
metaScriptedTemplateObject(JSFunction * callee,JSObject * templateObject)866   void metaScriptedTemplateObject(JSFunction* callee,
867                                   JSObject* templateObject) {
868     metaTwoByte_(MetaTwoByteKind::ScriptedTemplateObject, callee,
869                  templateObject);
870   }
871 
872   CACHE_IR_WRITER_GENERATED
873 };
874 
875 class CacheIRStubInfo;
876 
877 // Helper class for reading CacheIR bytecode.
878 class MOZ_RAII CacheIRReader {
879   CompactBufferReader buffer_;
880 
881   CacheIRReader(const CacheIRReader&) = delete;
882   CacheIRReader& operator=(const CacheIRReader&) = delete;
883 
884  public:
CacheIRReader(const uint8_t * start,const uint8_t * end)885   CacheIRReader(const uint8_t* start, const uint8_t* end)
886       : buffer_(start, end) {}
CacheIRReader(const CacheIRWriter & writer)887   explicit CacheIRReader(const CacheIRWriter& writer)
888       : CacheIRReader(writer.codeStart(), writer.codeEnd()) {}
889   explicit CacheIRReader(const CacheIRStubInfo* stubInfo);
890 
more()891   bool more() const { return buffer_.more(); }
892 
readOp()893   CacheOp readOp() { return CacheOp(buffer_.readByte()); }
894 
895   // Skip data not currently used.
skip()896   void skip() { buffer_.readByte(); }
skip(uint32_t skipLength)897   void skip(uint32_t skipLength) {
898     if (skipLength > 0) {
899       buffer_.seek(buffer_.currentPosition(), skipLength);
900     }
901   }
902 
valOperandId()903   ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
valueTagOperandId()904   ValueTagOperandId valueTagOperandId() {
905     return ValueTagOperandId(buffer_.readByte());
906   }
907 
objOperandId()908   ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
numberOperandId()909   NumberOperandId numberOperandId() {
910     return NumberOperandId(buffer_.readByte());
911   }
stringOperandId()912   StringOperandId stringOperandId() {
913     return StringOperandId(buffer_.readByte());
914   }
915 
symbolOperandId()916   SymbolOperandId symbolOperandId() {
917     return SymbolOperandId(buffer_.readByte());
918   }
919 
bigIntOperandId()920   BigIntOperandId bigIntOperandId() {
921     return BigIntOperandId(buffer_.readByte());
922   }
923 
int32OperandId()924   Int32OperandId int32OperandId() { return Int32OperandId(buffer_.readByte()); }
925 
rawOperandId()926   uint32_t rawOperandId() { return buffer_.readByte(); }
927 
stubOffset()928   uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
guardClassKind()929   GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
jsValueType()930   JSValueType jsValueType() { return JSValueType(buffer_.readByte()); }
valueType()931   ValueType valueType() { return ValueType(buffer_.readByte()); }
932 
typedThingLayout()933   TypedThingLayout typedThingLayout() {
934     return TypedThingLayout(buffer_.readByte());
935   }
936 
scalarType()937   Scalar::Type scalarType() { return Scalar::Type(buffer_.readByte()); }
typeDescrKey()938   uint32_t typeDescrKey() { return buffer_.readByte(); }
whyMagic()939   JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
jsop()940   JSOp jsop() { return JSOp(buffer_.readByte()); }
int32Immediate()941   int32_t int32Immediate() { return int32_t(buffer_.readFixedUint32_t()); }
uint32Immediate()942   uint32_t uint32Immediate() { return buffer_.readFixedUint32_t(); }
pointer()943   void* pointer() { return buffer_.readRawPointer(); }
944 
945   template <typename MetaKind>
metaKind()946   MetaKind metaKind() {
947     return MetaKind(buffer_.readByte());
948   }
949 
referenceTypeDescrType()950   ReferenceType referenceTypeDescrType() {
951     return ReferenceType(buffer_.readByte());
952   }
953 
unaryMathFunction()954   UnaryMathFunction unaryMathFunction() {
955     return UnaryMathFunction(buffer_.readByte());
956   }
957 
callFlags()958   CallFlags callFlags() {
959     // See CacheIRWriter::writeCallFlagsImm()
960     uint8_t encoded = buffer_.readByte();
961     CallFlags::ArgFormat format =
962         CallFlags::ArgFormat(encoded & CallFlags::ArgFormatMask);
963     bool isConstructing = encoded & CallFlags::IsConstructing;
964     bool isSameRealm = encoded & CallFlags::IsSameRealm;
965     switch (format) {
966       case CallFlags::Standard:
967         return CallFlags(isConstructing, /*isSpread =*/false, isSameRealm);
968       case CallFlags::Spread:
969         return CallFlags(isConstructing, /*isSpread =*/true, isSameRealm);
970       default:
971         // The existing non-standard argument formats (FunCall and FunApply)
972         // can't be constructors and have no support for isSameRealm.
973         MOZ_ASSERT(!isConstructing && !isSameRealm);
974         return CallFlags(format);
975     }
976   }
977 
readByte()978   uint8_t readByte() { return buffer_.readByte(); }
readBool()979   bool readBool() {
980     uint8_t b = buffer_.readByte();
981     MOZ_ASSERT(b <= 1);
982     return bool(b);
983   }
984 
matchOp(CacheOp op)985   bool matchOp(CacheOp op) {
986     const uint8_t* pos = buffer_.currentPosition();
987     if (readOp() == op) {
988       return true;
989     }
990     buffer_.seek(pos, 0);
991     return false;
992   }
993 
matchOp(CacheOp op,OperandId id)994   bool matchOp(CacheOp op, OperandId id) {
995     const uint8_t* pos = buffer_.currentPosition();
996     if (readOp() == op && buffer_.readByte() == id.id()) {
997       return true;
998     }
999     buffer_.seek(pos, 0);
1000     return false;
1001   }
1002 
matchOpEither(CacheOp op1,CacheOp op2)1003   bool matchOpEither(CacheOp op1, CacheOp op2) {
1004     const uint8_t* pos = buffer_.currentPosition();
1005     CacheOp op = readOp();
1006     if (op == op1 || op == op2) {
1007       return true;
1008     }
1009     buffer_.seek(pos, 0);
1010     return false;
1011   }
currentPosition()1012   const uint8_t* currentPosition() const { return buffer_.currentPosition(); }
1013 };
1014 
1015 class MOZ_RAII IRGenerator {
1016  protected:
1017   CacheIRWriter writer;
1018   JSContext* cx_;
1019   HandleScript script_;
1020   jsbytecode* pc_;
1021   CacheKind cacheKind_;
1022   ICState::Mode mode_;
1023 
1024   IRGenerator(const IRGenerator&) = delete;
1025   IRGenerator& operator=(const IRGenerator&) = delete;
1026 
1027   bool maybeGuardInt32Index(const Value& index, ValOperandId indexId,
1028                             uint32_t* int32Index, Int32OperandId* int32IndexId);
1029 
1030   ObjOperandId guardDOMProxyExpandoObjectAndShape(JSObject* obj,
1031                                                   ObjOperandId objId,
1032                                                   const Value& expandoVal,
1033                                                   JSObject* expandoObj);
1034 
1035   void emitIdGuard(ValOperandId valId, jsid id);
1036 
1037   friend class CacheIRSpewer;
1038 
1039  public:
1040   explicit IRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1041                        CacheKind cacheKind, ICState::Mode mode);
1042 
writerRef()1043   const CacheIRWriter& writerRef() const { return writer; }
cacheKind()1044   CacheKind cacheKind() const { return cacheKind_; }
1045 
1046   static constexpr char* NotAttached = nullptr;
1047 };
1048 
1049 // Flags used to describe what values a GetProperty cache may produce.
1050 enum class GetPropertyResultFlags {
1051   None = 0,
1052 
1053   // Values produced by this cache will go through a type barrier,
1054   // so the cache may produce any type of value that is compatible with its
1055   // result operand.
1056   Monitored = 1 << 0,
1057 
1058   // Whether particular primitives may be produced by this cache.
1059   AllowUndefined = 1 << 1,
1060   AllowInt32 = 1 << 2,
1061   AllowDouble = 1 << 3,
1062 
1063   All = Monitored | AllowUndefined | AllowInt32 | AllowDouble
1064 };
1065 
1066 static inline bool operator&(GetPropertyResultFlags a,
1067                              GetPropertyResultFlags b) {
1068   return static_cast<int>(a) & static_cast<int>(b);
1069 }
1070 
1071 static inline GetPropertyResultFlags operator|(GetPropertyResultFlags a,
1072                                                GetPropertyResultFlags b) {
1073   return static_cast<GetPropertyResultFlags>(static_cast<int>(a) |
1074                                              static_cast<int>(b));
1075 }
1076 
1077 static inline GetPropertyResultFlags& operator|=(GetPropertyResultFlags& lhs,
1078                                                  GetPropertyResultFlags b) {
1079   lhs = lhs | b;
1080   return lhs;
1081 }
1082 
1083 // GetPropIRGenerator generates CacheIR for a GetProp IC.
1084 class MOZ_RAII GetPropIRGenerator : public IRGenerator {
1085   HandleValue val_;
1086   HandleValue idVal_;
1087   HandleValue receiver_;
1088   GetPropertyResultFlags resultFlags_;
1089 
1090   enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
1091   PreliminaryObjectAction preliminaryObjectAction_;
1092 
1093   AttachDecision tryAttachNative(HandleObject obj, ObjOperandId objId,
1094                                  HandleId id);
1095   AttachDecision tryAttachUnboxed(HandleObject obj, ObjOperandId objId,
1096                                   HandleId id);
1097   AttachDecision tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId,
1098                                          HandleId id);
1099   AttachDecision tryAttachTypedObject(HandleObject obj, ObjOperandId objId,
1100                                       HandleId id);
1101   AttachDecision tryAttachObjectLength(HandleObject obj, ObjOperandId objId,
1102                                        HandleId id);
1103   AttachDecision tryAttachTypedArrayLength(HandleObject obj, ObjOperandId objId,
1104                                            HandleId id);
1105   AttachDecision tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId,
1106                                           HandleId id);
1107   AttachDecision tryAttachWindowProxy(HandleObject obj, ObjOperandId objId,
1108                                       HandleId id);
1109   AttachDecision tryAttachCrossCompartmentWrapper(HandleObject obj,
1110                                                   ObjOperandId objId,
1111                                                   HandleId id);
1112   AttachDecision tryAttachXrayCrossCompartmentWrapper(HandleObject obj,
1113                                                       ObjOperandId objId,
1114                                                       HandleId id);
1115   AttachDecision tryAttachFunction(HandleObject obj, ObjOperandId objId,
1116                                    HandleId id);
1117 
1118   AttachDecision tryAttachGenericProxy(HandleObject obj, ObjOperandId objId,
1119                                        HandleId id, bool handleDOMProxies);
1120   AttachDecision tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId,
1121                                           HandleId id);
1122   AttachDecision tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId,
1123                                            HandleId id);
1124   AttachDecision tryAttachDOMProxyUnshadowed(HandleObject obj,
1125                                              ObjOperandId objId, HandleId id);
1126   AttachDecision tryAttachProxy(HandleObject obj, ObjOperandId objId,
1127                                 HandleId id);
1128 
1129   AttachDecision tryAttachPrimitive(ValOperandId valId, HandleId id);
1130   AttachDecision tryAttachStringChar(ValOperandId valId, ValOperandId indexId);
1131   AttachDecision tryAttachStringLength(ValOperandId valId, HandleId id);
1132   AttachDecision tryAttachMagicArgumentsName(ValOperandId valId, HandleId id);
1133 
1134   AttachDecision tryAttachMagicArgument(ValOperandId valId,
1135                                         ValOperandId indexId);
1136   AttachDecision tryAttachArgumentsObjectArg(HandleObject obj,
1137                                              ObjOperandId objId,
1138                                              Int32OperandId indexId);
1139 
1140   AttachDecision tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
1141                                        uint32_t index, Int32OperandId indexId);
1142   AttachDecision tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId,
1143                                            uint32_t index,
1144                                            Int32OperandId indexId);
1145   AttachDecision tryAttachSparseElement(HandleObject obj, ObjOperandId objId,
1146                                         uint32_t index, Int32OperandId indexId);
1147   AttachDecision tryAttachTypedElement(HandleObject obj, ObjOperandId objId,
1148                                        uint32_t index, Int32OperandId indexId);
1149   AttachDecision tryAttachTypedArrayNonInt32Index(HandleObject obj,
1150                                                   ObjOperandId objId);
1151 
1152   AttachDecision tryAttachGenericElement(HandleObject obj, ObjOperandId objId,
1153                                          uint32_t index,
1154                                          Int32OperandId indexId);
1155 
1156   AttachDecision tryAttachProxyElement(HandleObject obj, ObjOperandId objId);
1157 
1158   void attachMegamorphicNativeSlot(ObjOperandId objId, jsid id,
1159                                    bool handleMissing);
1160 
getElemKeyValueId()1161   ValOperandId getElemKeyValueId() const {
1162     MOZ_ASSERT(cacheKind_ == CacheKind::GetElem ||
1163                cacheKind_ == CacheKind::GetElemSuper);
1164     return ValOperandId(1);
1165   }
1166 
getSuperReceiverValueId()1167   ValOperandId getSuperReceiverValueId() const {
1168     if (cacheKind_ == CacheKind::GetPropSuper) {
1169       return ValOperandId(1);
1170     }
1171 
1172     MOZ_ASSERT(cacheKind_ == CacheKind::GetElemSuper);
1173     return ValOperandId(2);
1174   }
1175 
isSuper()1176   bool isSuper() const {
1177     return (cacheKind_ == CacheKind::GetPropSuper ||
1178             cacheKind_ == CacheKind::GetElemSuper);
1179   }
1180 
1181   // No pc if idempotent, as there can be multiple bytecode locations
1182   // due to GVN.
idempotent()1183   bool idempotent() const { return pc_ == nullptr; }
1184 
1185   // If this is a GetElem cache, emit instructions to guard the incoming Value
1186   // matches |id|.
1187   void maybeEmitIdGuard(jsid id);
1188 
1189   void trackAttached(const char* name);
1190 
1191  public:
1192   GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1193                      ICState::Mode mode, CacheKind cacheKind, HandleValue val,
1194                      HandleValue idVal, HandleValue receiver,
1195                      GetPropertyResultFlags resultFlags);
1196 
1197   AttachDecision tryAttachStub();
1198   AttachDecision tryAttachIdempotentStub();
1199 
shouldUnlinkPreliminaryObjectStubs()1200   bool shouldUnlinkPreliminaryObjectStubs() const {
1201     return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
1202   }
1203 
shouldNotePreliminaryObjectStub()1204   bool shouldNotePreliminaryObjectStub() const {
1205     return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
1206   }
1207 };
1208 
1209 // GetNameIRGenerator generates CacheIR for a GetName IC.
1210 class MOZ_RAII GetNameIRGenerator : public IRGenerator {
1211   HandleObject env_;
1212   HandlePropertyName name_;
1213 
1214   AttachDecision tryAttachGlobalNameValue(ObjOperandId objId, HandleId id);
1215   AttachDecision tryAttachGlobalNameGetter(ObjOperandId objId, HandleId id);
1216   AttachDecision tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
1217 
1218   void trackAttached(const char* name);
1219 
1220  public:
1221   GetNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1222                      ICState::Mode mode, HandleObject env,
1223                      HandlePropertyName name);
1224 
1225   AttachDecision tryAttachStub();
1226 };
1227 
1228 // BindNameIRGenerator generates CacheIR for a BindName IC.
1229 class MOZ_RAII BindNameIRGenerator : public IRGenerator {
1230   HandleObject env_;
1231   HandlePropertyName name_;
1232 
1233   AttachDecision tryAttachGlobalName(ObjOperandId objId, HandleId id);
1234   AttachDecision tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
1235 
1236   void trackAttached(const char* name);
1237 
1238  public:
1239   BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1240                       ICState::Mode mode, HandleObject env,
1241                       HandlePropertyName name);
1242 
1243   AttachDecision tryAttachStub();
1244 };
1245 
1246 // Information used by SetProp/SetElem stubs to check/update property types.
1247 class MOZ_RAII PropertyTypeCheckInfo {
1248   RootedObjectGroup group_;
1249   RootedId id_;
1250   bool needsTypeBarrier_;
1251 
1252   PropertyTypeCheckInfo(const PropertyTypeCheckInfo&) = delete;
1253   void operator=(const PropertyTypeCheckInfo&) = delete;
1254 
1255  public:
PropertyTypeCheckInfo(JSContext * cx,bool needsTypeBarrier)1256   PropertyTypeCheckInfo(JSContext* cx, bool needsTypeBarrier)
1257       : group_(cx), id_(cx), needsTypeBarrier_(needsTypeBarrier) {
1258     if (!IsTypeInferenceEnabled()) {
1259       needsTypeBarrier_ = false;
1260     }
1261   }
1262 
needsTypeBarrier()1263   bool needsTypeBarrier() const { return needsTypeBarrier_; }
isSet()1264   bool isSet() const { return group_ != nullptr; }
1265 
group()1266   ObjectGroup* group() const {
1267     MOZ_ASSERT(isSet());
1268     return group_;
1269   }
1270 
id()1271   jsid id() const {
1272     MOZ_ASSERT(isSet());
1273     return id_;
1274   }
1275 
set(ObjectGroup * group,jsid id)1276   void set(ObjectGroup* group, jsid id) {
1277     MOZ_ASSERT(!group_);
1278     MOZ_ASSERT(group);
1279     if (needsTypeBarrier_) {
1280       group_ = group;
1281       id_ = id;
1282     }
1283   }
1284 };
1285 
1286 // SetPropIRGenerator generates CacheIR for a SetProp IC.
1287 class MOZ_RAII SetPropIRGenerator : public IRGenerator {
1288   HandleValue lhsVal_;
1289   HandleValue idVal_;
1290   HandleValue rhsVal_;
1291   PropertyTypeCheckInfo typeCheckInfo_;
1292 
1293   enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
1294   PreliminaryObjectAction preliminaryObjectAction_;
1295   bool attachedTypedArrayOOBStub_;
1296 
1297   bool maybeHasExtraIndexedProps_;
1298 
1299  public:
1300   enum class DeferType { None, AddSlot };
1301 
1302  private:
1303   DeferType deferType_ = DeferType::None;
1304 
setElemKeyValueId()1305   ValOperandId setElemKeyValueId() const {
1306     MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
1307     return ValOperandId(1);
1308   }
1309 
rhsValueId()1310   ValOperandId rhsValueId() const {
1311     if (cacheKind_ == CacheKind::SetProp) {
1312       return ValOperandId(1);
1313     }
1314     MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
1315     return ValOperandId(2);
1316   }
1317 
1318   // If this is a SetElem cache, emit instructions to guard the incoming Value
1319   // matches |id|.
1320   void maybeEmitIdGuard(jsid id);
1321 
1322   OperandId emitNumericGuard(ValOperandId valId, Scalar::Type type);
1323 
1324   AttachDecision tryAttachNativeSetSlot(HandleObject obj, ObjOperandId objId,
1325                                         HandleId id, ValOperandId rhsId);
1326   AttachDecision tryAttachUnboxedExpandoSetSlot(HandleObject obj,
1327                                                 ObjOperandId objId, HandleId id,
1328                                                 ValOperandId rhsId);
1329   AttachDecision tryAttachUnboxedProperty(HandleObject obj, ObjOperandId objId,
1330                                           HandleId id, ValOperandId rhsId);
1331   AttachDecision tryAttachTypedObjectProperty(HandleObject obj,
1332                                               ObjOperandId objId, HandleId id,
1333                                               ValOperandId rhsId);
1334   AttachDecision tryAttachSetter(HandleObject obj, ObjOperandId objId,
1335                                  HandleId id, ValOperandId rhsId);
1336   AttachDecision tryAttachSetArrayLength(HandleObject obj, ObjOperandId objId,
1337                                          HandleId id, ValOperandId rhsId);
1338   AttachDecision tryAttachWindowProxy(HandleObject obj, ObjOperandId objId,
1339                                       HandleId id, ValOperandId rhsId);
1340 
1341   AttachDecision tryAttachSetDenseElement(HandleObject obj, ObjOperandId objId,
1342                                           uint32_t index,
1343                                           Int32OperandId indexId,
1344                                           ValOperandId rhsId);
1345   AttachDecision tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId,
1346                                           uint32_t index,
1347                                           Int32OperandId indexId,
1348                                           ValOperandId rhsId);
1349   AttachDecision tryAttachSetTypedArrayElementNonInt32Index(HandleObject obj,
1350                                                             ObjOperandId objId,
1351                                                             ValOperandId rhsId);
1352 
1353   AttachDecision tryAttachSetDenseElementHole(HandleObject obj,
1354                                               ObjOperandId objId,
1355                                               uint32_t index,
1356                                               Int32OperandId indexId,
1357                                               ValOperandId rhsId);
1358 
1359   AttachDecision tryAttachAddOrUpdateSparseElement(HandleObject obj,
1360                                                    ObjOperandId objId,
1361                                                    uint32_t index,
1362                                                    Int32OperandId indexId,
1363                                                    ValOperandId rhsId);
1364 
1365   AttachDecision tryAttachGenericProxy(HandleObject obj, ObjOperandId objId,
1366                                        HandleId id, ValOperandId rhsId,
1367                                        bool handleDOMProxies);
1368   AttachDecision tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId,
1369                                            HandleId id, ValOperandId rhsId);
1370   AttachDecision tryAttachDOMProxyUnshadowed(HandleObject obj,
1371                                              ObjOperandId objId, HandleId id,
1372                                              ValOperandId rhsId);
1373   AttachDecision tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId,
1374                                           HandleId id, ValOperandId rhsId);
1375   AttachDecision tryAttachProxy(HandleObject obj, ObjOperandId objId,
1376                                 HandleId id, ValOperandId rhsId);
1377   AttachDecision tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
1378                                        ValOperandId rhsId);
1379   AttachDecision tryAttachMegamorphicSetElement(HandleObject obj,
1380                                                 ObjOperandId objId,
1381                                                 ValOperandId rhsId);
1382 
1383   bool canAttachAddSlotStub(HandleObject obj, HandleId id);
1384 
1385  public:
1386   SetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1387                      CacheKind cacheKind, ICState::Mode mode,
1388                      HandleValue lhsVal, HandleValue idVal, HandleValue rhsVal,
1389                      bool needsTypeBarrier = true,
1390                      bool maybeHasExtraIndexedProps = true);
1391 
1392   AttachDecision tryAttachStub();
1393   AttachDecision tryAttachAddSlotStub(HandleObjectGroup oldGroup,
1394                                       HandleShape oldShape);
1395   void trackAttached(const char* name);
1396 
shouldUnlinkPreliminaryObjectStubs()1397   bool shouldUnlinkPreliminaryObjectStubs() const {
1398     return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
1399   }
1400 
shouldNotePreliminaryObjectStub()1401   bool shouldNotePreliminaryObjectStub() const {
1402     return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
1403   }
1404 
typeCheckInfo()1405   const PropertyTypeCheckInfo* typeCheckInfo() const { return &typeCheckInfo_; }
1406 
attachedTypedArrayOOBStub()1407   bool attachedTypedArrayOOBStub() const { return attachedTypedArrayOOBStub_; }
1408 
deferType()1409   DeferType deferType() const { return deferType_; }
1410 };
1411 
1412 // HasPropIRGenerator generates CacheIR for a HasProp IC. Used for
1413 // CacheKind::In / CacheKind::HasOwn.
1414 class MOZ_RAII HasPropIRGenerator : public IRGenerator {
1415   HandleValue val_;
1416   HandleValue idVal_;
1417 
1418   AttachDecision tryAttachDense(HandleObject obj, ObjOperandId objId,
1419                                 uint32_t index, Int32OperandId indexId);
1420   AttachDecision tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
1421                                     uint32_t index, Int32OperandId indexId);
1422   AttachDecision tryAttachTypedArray(HandleObject obj, ObjOperandId objId,
1423                                      Int32OperandId indexId);
1424   AttachDecision tryAttachTypedArrayNonInt32Index(HandleObject obj,
1425                                                   ObjOperandId objId,
1426                                                   ValOperandId keyId);
1427   AttachDecision tryAttachSparse(HandleObject obj, ObjOperandId objId,
1428                                  Int32OperandId indexId);
1429   AttachDecision tryAttachNamedProp(HandleObject obj, ObjOperandId objId,
1430                                     HandleId key, ValOperandId keyId);
1431   AttachDecision tryAttachMegamorphic(ObjOperandId objId, ValOperandId keyId);
1432   AttachDecision tryAttachNative(JSObject* obj, ObjOperandId objId, jsid key,
1433                                  ValOperandId keyId, PropertyResult prop,
1434                                  JSObject* holder);
1435   AttachDecision tryAttachUnboxed(JSObject* obj, ObjOperandId objId, jsid key,
1436                                   ValOperandId keyId);
1437   AttachDecision tryAttachUnboxedExpando(JSObject* obj, ObjOperandId objId,
1438                                          jsid key, ValOperandId keyId);
1439   AttachDecision tryAttachTypedObject(JSObject* obj, ObjOperandId objId,
1440                                       jsid key, ValOperandId keyId);
1441   AttachDecision tryAttachSlotDoesNotExist(JSObject* obj, ObjOperandId objId,
1442                                            jsid key, ValOperandId keyId);
1443   AttachDecision tryAttachDoesNotExist(HandleObject obj, ObjOperandId objId,
1444                                        HandleId key, ValOperandId keyId);
1445   AttachDecision tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
1446                                        ValOperandId keyId);
1447 
1448   void trackAttached(const char* name);
1449 
1450  public:
1451   // NOTE: Argument order is PROPERTY, OBJECT
1452   HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc,
1453                      ICState::Mode mode, CacheKind cacheKind, HandleValue idVal,
1454                      HandleValue val);
1455 
1456   AttachDecision tryAttachStub();
1457 };
1458 
1459 class MOZ_RAII InstanceOfIRGenerator : public IRGenerator {
1460   HandleValue lhsVal_;
1461   HandleObject rhsObj_;
1462 
1463   void trackAttached(const char* name);
1464 
1465  public:
1466   InstanceOfIRGenerator(JSContext*, HandleScript, jsbytecode*, ICState::Mode,
1467                         HandleValue, HandleObject);
1468 
1469   AttachDecision tryAttachStub();
1470 };
1471 
1472 class MOZ_RAII TypeOfIRGenerator : public IRGenerator {
1473   HandleValue val_;
1474 
1475   AttachDecision tryAttachPrimitive(ValOperandId valId);
1476   AttachDecision tryAttachObject(ValOperandId valId);
1477   void trackAttached(const char* name);
1478 
1479  public:
1480   TypeOfIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1481                     ICState::Mode mode, HandleValue value);
1482 
1483   AttachDecision tryAttachStub();
1484 };
1485 
1486 class MOZ_RAII GetIteratorIRGenerator : public IRGenerator {
1487   HandleValue val_;
1488 
1489   AttachDecision tryAttachNativeIterator(ObjOperandId objId, HandleObject obj);
1490 
1491  public:
1492   GetIteratorIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1493                          ICState::Mode mode, HandleValue value);
1494 
1495   AttachDecision tryAttachStub();
1496 
1497   void trackAttached(const char* name);
1498 };
1499 
1500 enum class StringChar { CodeAt, At };
1501 
1502 class MOZ_RAII CallIRGenerator : public IRGenerator {
1503  private:
1504   JSOp op_;
1505   uint32_t argc_;
1506   HandleValue callee_;
1507   HandleValue thisval_;
1508   HandleValue newTarget_;
1509   HandleValueArray args_;
1510   PropertyTypeCheckInfo typeCheckInfo_;
1511   BaselineCacheIRStubKind cacheIRStubKind_;
1512 
1513   bool getTemplateObjectForScripted(HandleFunction calleeFunc,
1514                                     MutableHandleObject result,
1515                                     bool* skipAttach);
1516   bool getTemplateObjectForNative(HandleFunction calleeFunc,
1517                                   MutableHandleObject result);
1518 
1519   void emitNativeCalleeGuard(HandleFunction callee);
1520 
1521   AttachDecision tryAttachArrayPush(HandleFunction callee);
1522   AttachDecision tryAttachArrayJoin(HandleFunction callee);
1523   AttachDecision tryAttachArrayIsArray(HandleFunction callee);
1524   AttachDecision tryAttachIsSuspendedGenerator(HandleFunction callee);
1525   AttachDecision tryAttachToString(HandleFunction callee);
1526   AttachDecision tryAttachToObject(HandleFunction callee);
1527   AttachDecision tryAttachToInteger(HandleFunction callee);
1528   AttachDecision tryAttachIsObject(HandleFunction callee);
1529   AttachDecision tryAttachIsCallable(HandleFunction callee);
1530   AttachDecision tryAttachIsConstructor(HandleFunction callee);
1531   AttachDecision tryAttachStringChar(HandleFunction callee, StringChar kind);
1532   AttachDecision tryAttachStringCharCodeAt(HandleFunction callee);
1533   AttachDecision tryAttachStringCharAt(HandleFunction callee);
1534   AttachDecision tryAttachMathAbs(HandleFunction callee);
1535   AttachDecision tryAttachMathFloor(HandleFunction callee);
1536   AttachDecision tryAttachMathCeil(HandleFunction callee);
1537   AttachDecision tryAttachMathRound(HandleFunction callee);
1538   AttachDecision tryAttachMathSqrt(HandleFunction callee);
1539   AttachDecision tryAttachMathFunction(HandleFunction callee,
1540                                        UnaryMathFunction fun);
1541 
1542   AttachDecision tryAttachFunCall(HandleFunction calleeFunc);
1543   AttachDecision tryAttachFunApply(HandleFunction calleeFunc);
1544   AttachDecision tryAttachCallScripted(HandleFunction calleeFunc);
1545   AttachDecision tryAttachInlinableNative(HandleFunction calleeFunc);
1546   AttachDecision tryAttachCallNative(HandleFunction calleeFunc);
1547   AttachDecision tryAttachCallHook(HandleObject calleeObj);
1548 
1549   void trackAttached(const char* name);
1550 
1551  public:
1552   CallIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, JSOp op,
1553                   ICState::Mode mode, uint32_t argc, HandleValue callee,
1554                   HandleValue thisval, HandleValue newTarget,
1555                   HandleValueArray args);
1556 
1557   AttachDecision tryAttachStub();
1558 
1559   AttachDecision tryAttachDeferredStub(HandleValue result);
1560 
cacheIRStubKind()1561   BaselineCacheIRStubKind cacheIRStubKind() const { return cacheIRStubKind_; }
1562 
typeCheckInfo()1563   const PropertyTypeCheckInfo* typeCheckInfo() const { return &typeCheckInfo_; }
1564 };
1565 
1566 class MOZ_RAII CompareIRGenerator : public IRGenerator {
1567   JSOp op_;
1568   HandleValue lhsVal_;
1569   HandleValue rhsVal_;
1570 
1571   AttachDecision tryAttachString(ValOperandId lhsId, ValOperandId rhsId);
1572   AttachDecision tryAttachObject(ValOperandId lhsId, ValOperandId rhsId);
1573   AttachDecision tryAttachSymbol(ValOperandId lhsId, ValOperandId rhsId);
1574   AttachDecision tryAttachStrictDifferentTypes(ValOperandId lhsId,
1575                                                ValOperandId rhsId);
1576   AttachDecision tryAttachInt32(ValOperandId lhsId, ValOperandId rhsId);
1577   AttachDecision tryAttachNumber(ValOperandId lhsId, ValOperandId rhsId);
1578   AttachDecision tryAttachBigInt(ValOperandId lhsId, ValOperandId rhsId);
1579   AttachDecision tryAttachNumberUndefined(ValOperandId lhsId,
1580                                           ValOperandId rhsId);
1581   AttachDecision tryAttachPrimitiveUndefined(ValOperandId lhsId,
1582                                              ValOperandId rhsId);
1583   AttachDecision tryAttachObjectUndefined(ValOperandId lhsId,
1584                                           ValOperandId rhsId);
1585   AttachDecision tryAttachNullUndefined(ValOperandId lhsId, ValOperandId rhsId);
1586   AttachDecision tryAttachStringNumber(ValOperandId lhsId, ValOperandId rhsId);
1587   AttachDecision tryAttachPrimitiveSymbol(ValOperandId lhsId,
1588                                           ValOperandId rhsId);
1589   AttachDecision tryAttachBoolStringOrNumber(ValOperandId lhsId,
1590                                              ValOperandId rhsId);
1591   AttachDecision tryAttachBigIntInt32(ValOperandId lhsId, ValOperandId rhsId);
1592   AttachDecision tryAttachBigIntNumber(ValOperandId lhsId, ValOperandId rhsId);
1593   AttachDecision tryAttachBigIntString(ValOperandId lhsId, ValOperandId rhsId);
1594 
1595   void trackAttached(const char* name);
1596 
1597  public:
1598   CompareIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1599                      ICState::Mode mode, JSOp op, HandleValue lhsVal,
1600                      HandleValue rhsVal);
1601 
1602   AttachDecision tryAttachStub();
1603 };
1604 
1605 class MOZ_RAII ToBoolIRGenerator : public IRGenerator {
1606   HandleValue val_;
1607 
1608   AttachDecision tryAttachInt32();
1609   AttachDecision tryAttachNumber();
1610   AttachDecision tryAttachString();
1611   AttachDecision tryAttachSymbol();
1612   AttachDecision tryAttachNullOrUndefined();
1613   AttachDecision tryAttachObject();
1614   AttachDecision tryAttachBigInt();
1615 
1616   void trackAttached(const char* name);
1617 
1618  public:
1619   ToBoolIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1620                     ICState::Mode mode, HandleValue val);
1621 
1622   AttachDecision tryAttachStub();
1623 };
1624 
1625 class MOZ_RAII GetIntrinsicIRGenerator : public IRGenerator {
1626   HandleValue val_;
1627 
1628   void trackAttached(const char* name);
1629 
1630  public:
1631   GetIntrinsicIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1632                           ICState::Mode, HandleValue val);
1633 
1634   AttachDecision tryAttachStub();
1635 };
1636 
1637 class MOZ_RAII UnaryArithIRGenerator : public IRGenerator {
1638   JSOp op_;
1639   HandleValue val_;
1640   HandleValue res_;
1641 
1642   AttachDecision tryAttachInt32();
1643   AttachDecision tryAttachNumber();
1644   AttachDecision tryAttachBigInt();
1645   AttachDecision tryAttachStringInt32();
1646   AttachDecision tryAttachStringNumber();
1647 
1648   void trackAttached(const char* name);
1649 
1650  public:
1651   UnaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1652                         ICState::Mode mode, JSOp op, HandleValue val,
1653                         HandleValue res);
1654 
1655   AttachDecision tryAttachStub();
1656 };
1657 
1658 class MOZ_RAII BinaryArithIRGenerator : public IRGenerator {
1659   JSOp op_;
1660   HandleValue lhs_;
1661   HandleValue rhs_;
1662   HandleValue res_;
1663 
1664   void trackAttached(const char* name);
1665 
1666   AttachDecision tryAttachInt32();
1667   AttachDecision tryAttachDouble();
1668   AttachDecision tryAttachBitwise();
1669   AttachDecision tryAttachStringConcat();
1670   AttachDecision tryAttachStringObjectConcat();
1671   AttachDecision tryAttachStringNumberConcat();
1672   AttachDecision tryAttachStringBooleanConcat();
1673   AttachDecision tryAttachBigInt();
1674   AttachDecision tryAttachStringInt32Arith();
1675 
1676  public:
1677   BinaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1678                          ICState::Mode, JSOp op, HandleValue lhs,
1679                          HandleValue rhs, HandleValue res);
1680 
1681   AttachDecision tryAttachStub();
1682 };
1683 
1684 class MOZ_RAII NewObjectIRGenerator : public IRGenerator {
1685 #ifdef JS_CACHEIR_SPEW
1686   JSOp op_;
1687 #endif
1688   HandleObject templateObject_;
1689 
1690   void trackAttached(const char* name);
1691 
1692  public:
1693   NewObjectIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc,
1694                        ICState::Mode, JSOp op, HandleObject templateObj);
1695 
1696   AttachDecision tryAttachStub();
1697 };
1698 
SimpleTypeDescrKey(SimpleTypeDescr * descr)1699 static inline uint32_t SimpleTypeDescrKey(SimpleTypeDescr* descr) {
1700   if (descr->is<ScalarTypeDescr>()) {
1701     return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
1702   }
1703   return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
1704 }
1705 
SimpleTypeDescrKeyIsScalar(uint32_t key)1706 inline bool SimpleTypeDescrKeyIsScalar(uint32_t key) { return !(key & 1); }
1707 
ScalarTypeFromSimpleTypeDescrKey(uint32_t key)1708 inline ScalarTypeDescr::Type ScalarTypeFromSimpleTypeDescrKey(uint32_t key) {
1709   MOZ_ASSERT(SimpleTypeDescrKeyIsScalar(key));
1710   return ScalarTypeDescr::Type(key >> 1);
1711 }
1712 
ReferenceTypeFromSimpleTypeDescrKey(uint32_t key)1713 inline ReferenceType ReferenceTypeFromSimpleTypeDescrKey(uint32_t key) {
1714   MOZ_ASSERT(!SimpleTypeDescrKeyIsScalar(key));
1715   return ReferenceType(key >> 1);
1716 }
1717 
1718 // Returns whether obj is a WindowProxy wrapping the script's global.
1719 extern bool IsWindowProxyForScriptGlobal(JSScript* script, JSObject* obj);
1720 
1721 }  // namespace jit
1722 }  // namespace js
1723 
1724 #endif /* jit_CacheIR_h */
1725