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