Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 "NamespaceImports.h"
13 :
14 : #include "gc/Rooting.h"
15 : #include "jit/CompactBuffer.h"
16 : #include "jit/ICState.h"
17 : #include "jit/SharedIC.h"
18 :
19 : namespace js {
20 : namespace jit {
21 :
22 : // CacheIR is an (extremely simple) linear IR language for inline caches.
23 : // From this IR, we can generate machine code for Baseline or Ion IC stubs.
24 : //
25 : // IRWriter
26 : // --------
27 : // CacheIR bytecode is written using IRWriter. This class also records some
28 : // metadata that's used by the Baseline and Ion code generators to generate
29 : // (efficient) machine code.
30 : //
31 : // Sharing Baseline stub code
32 : // --------------------------
33 : // Baseline stores data (like Shape* and fixed slot offsets) inside the ICStub
34 : // structure, instead of embedding them directly in the JitCode. This makes
35 : // Baseline IC code slightly slower, but allows us to share IC code between
36 : // caches. CacheIR makes it easy to share code between stubs: stubs that have
37 : // the same CacheIR (and CacheKind), will have the same Baseline stub code.
38 : //
39 : // Baseline stubs that share JitCode also share a CacheIRStubInfo structure.
40 : // This class stores the CacheIR and the location of GC things stored in the
41 : // stub, for the GC.
42 : //
43 : // JitCompartment has a CacheIRStubInfo* -> JitCode* weak map that's used to
44 : // share both the IR and JitCode between CacheIR stubs. This HashMap owns the
45 : // stubInfo (it uses UniquePtr), so once there are no references left to the
46 : // shared stub code, we can also free the CacheIRStubInfo.
47 : //
48 : // Ion stubs
49 : // ---------
50 : // Unlike Baseline stubs, Ion stubs do not share stub code, and data stored in
51 : // the IonICStub is baked into JIT code. This is one of the reasons Ion stubs
52 : // are faster than Baseline stubs. Also note that Ion ICs contain more state
53 : // (see IonGetPropertyIC for example) and use dynamic input/output registers,
54 : // so sharing stub code for Ion would be much more difficult.
55 :
56 : // An OperandId represents either a cache input or a value returned by a
57 : // CacheIR instruction. Most code should use the ValOperandId and ObjOperandId
58 : // classes below. The ObjOperandId class represents an operand that's known to
59 : // be an object.
60 : class OperandId
61 : {
62 : protected:
63 : static const uint16_t InvalidId = UINT16_MAX;
64 : uint16_t id_;
65 :
66 2064 : OperandId() : id_(InvalidId) {}
67 27532 : explicit OperandId(uint16_t id) : id_(id) {}
68 :
69 : public:
70 158377 : uint16_t id() const { return id_; }
71 2957 : bool valid() const { return id_ != InvalidId; }
72 : };
73 :
74 : class ValOperandId : public OperandId
75 : {
76 : public:
77 1711 : ValOperandId() = default;
78 13289 : explicit ValOperandId(uint16_t id) : OperandId(id) {}
79 : };
80 :
81 : class ObjOperandId : public OperandId
82 : {
83 : public:
84 : ObjOperandId() = default;
85 10999 : explicit ObjOperandId(uint16_t id) : OperandId(id) {}
86 :
87 : bool operator==(const ObjOperandId& other) const { return id_ == other.id_; }
88 : bool operator!=(const ObjOperandId& other) const { return id_ != other.id_; }
89 : };
90 :
91 : class StringOperandId : public OperandId
92 : {
93 : public:
94 : StringOperandId() = default;
95 1614 : explicit StringOperandId(uint16_t id) : OperandId(id) {}
96 : };
97 :
98 : class SymbolOperandId : public OperandId
99 : {
100 : public:
101 : SymbolOperandId() = default;
102 133 : explicit SymbolOperandId(uint16_t id) : OperandId(id) {}
103 : };
104 :
105 : class Int32OperandId : public OperandId
106 : {
107 : public:
108 353 : Int32OperandId() = default;
109 410 : explicit Int32OperandId(uint16_t id) : OperandId(id) {}
110 : };
111 :
112 : class TypedOperandId : public OperandId
113 : {
114 : JSValueType type_;
115 :
116 : public:
117 937 : MOZ_IMPLICIT TypedOperandId(ObjOperandId id)
118 937 : : OperandId(id.id()), type_(JSVAL_TYPE_OBJECT)
119 937 : {}
120 70 : MOZ_IMPLICIT TypedOperandId(StringOperandId id)
121 70 : : OperandId(id.id()), type_(JSVAL_TYPE_STRING)
122 70 : {}
123 14 : MOZ_IMPLICIT TypedOperandId(SymbolOperandId id)
124 14 : : OperandId(id.id()), type_(JSVAL_TYPE_SYMBOL)
125 14 : {}
126 66 : MOZ_IMPLICIT TypedOperandId(Int32OperandId id)
127 66 : : OperandId(id.id()), type_(JSVAL_TYPE_INT32)
128 66 : {}
129 0 : TypedOperandId(ValOperandId val, JSValueType type)
130 0 : : OperandId(val.id()), type_(type)
131 0 : {}
132 :
133 461 : JSValueType type() const { return type_; }
134 : };
135 :
136 : #define CACHE_IR_KINDS(_) \
137 : _(GetProp) \
138 : _(GetElem) \
139 : _(GetName) \
140 : _(GetPropSuper) \
141 : _(GetElemSuper) \
142 : _(SetProp) \
143 : _(SetElem) \
144 : _(BindName) \
145 : _(In) \
146 : _(HasOwn) \
147 : _(TypeOf) \
148 : _(Compare) \
149 : _(Call)
150 :
151 : enum class CacheKind : uint8_t
152 : {
153 : #define DEFINE_KIND(kind) kind,
154 : CACHE_IR_KINDS(DEFINE_KIND)
155 : #undef DEFINE_KIND
156 : };
157 :
158 : extern const char* CacheKindNames[];
159 :
160 : #define CACHE_IR_OPS(_) \
161 : _(GuardIsObject) \
162 : _(GuardIsObjectOrNull) \
163 : _(GuardIsString) \
164 : _(GuardIsSymbol) \
165 : _(GuardIsInt32Index) \
166 : _(GuardType) \
167 : _(GuardShape) \
168 : _(GuardGroup) \
169 : _(GuardProto) \
170 : _(GuardClass) \
171 : _(GuardCompartment) \
172 : _(GuardIsNativeFunction) \
173 : _(GuardIsProxy) \
174 : _(GuardIsCrossCompartmentWrapper) \
175 : _(GuardNotDOMProxy) \
176 : _(GuardSpecificObject) \
177 : _(GuardSpecificAtom) \
178 : _(GuardSpecificSymbol) \
179 : _(GuardSpecificInt32Immediate) \
180 : _(GuardNoDetachedTypedObjects) \
181 : _(GuardMagicValue) \
182 : _(GuardFrameHasNoArgumentsObject) \
183 : _(GuardNoDenseElements) \
184 : _(GuardNoUnboxedExpando) \
185 : _(GuardAndLoadUnboxedExpando) \
186 : _(GuardAndGetIndexFromString) \
187 : _(GuardHasGetterSetter) \
188 : _(GuardGroupHasUnanalyzedNewScript) \
189 : _(LoadStackValue) \
190 : _(LoadObject) \
191 : _(LoadProto) \
192 : _(LoadEnclosingEnvironment) \
193 : _(LoadWrapperTarget) \
194 : \
195 : _(MegamorphicLoadSlotResult) \
196 : _(MegamorphicLoadSlotByValueResult) \
197 : _(MegamorphicStoreSlot) \
198 : _(MegamorphicHasOwnResult) \
199 : \
200 : /* See CacheIR.cpp 'DOM proxies' comment. */ \
201 : _(LoadDOMExpandoValue) \
202 : _(LoadDOMExpandoValueGuardGeneration) \
203 : _(LoadDOMExpandoValueIgnoreGeneration)\
204 : _(GuardDOMExpandoMissingOrGuardShape) \
205 : \
206 : _(StoreFixedSlot) \
207 : _(StoreDynamicSlot) \
208 : _(AddAndStoreFixedSlot) \
209 : _(AddAndStoreDynamicSlot) \
210 : _(AllocateAndStoreDynamicSlot) \
211 : _(StoreTypedObjectReferenceProperty) \
212 : _(StoreTypedObjectScalarProperty) \
213 : _(StoreUnboxedProperty) \
214 : _(StoreDenseElement) \
215 : _(StoreDenseElementHole) \
216 : _(StoreTypedElement) \
217 : _(StoreUnboxedArrayElement) \
218 : _(StoreUnboxedArrayElementHole) \
219 : _(CallNativeSetter) \
220 : _(CallScriptedSetter) \
221 : _(CallSetArrayLength) \
222 : _(CallProxySet) \
223 : _(CallProxySetByValue) \
224 : \
225 : /* The *Result ops load a value into the cache's result register. */ \
226 : _(LoadFixedSlotResult) \
227 : _(LoadDynamicSlotResult) \
228 : _(LoadUnboxedPropertyResult) \
229 : _(LoadTypedObjectResult) \
230 : _(LoadDenseElementResult) \
231 : _(LoadDenseElementHoleResult) \
232 : _(LoadDenseElementExistsResult) \
233 : _(LoadDenseElementHoleExistsResult) \
234 : _(LoadUnboxedArrayElementResult) \
235 : _(LoadTypedElementResult) \
236 : _(LoadInt32ArrayLengthResult) \
237 : _(LoadUnboxedArrayLengthResult) \
238 : _(LoadArgumentsObjectArgResult) \
239 : _(LoadArgumentsObjectLengthResult) \
240 : _(LoadFunctionLengthResult) \
241 : _(LoadStringCharResult) \
242 : _(LoadStringLengthResult) \
243 : _(LoadFrameCalleeResult) \
244 : _(LoadFrameNumActualArgsResult) \
245 : _(LoadFrameArgumentResult) \
246 : _(LoadEnvironmentFixedSlotResult) \
247 : _(LoadEnvironmentDynamicSlotResult) \
248 : _(LoadObjectResult) \
249 : _(CallScriptedGetterResult) \
250 : _(CallNativeGetterResult) \
251 : _(CallProxyGetResult) \
252 : _(CallProxyGetByValueResult) \
253 : _(CallProxyHasOwnResult) \
254 : _(LoadUndefinedResult) \
255 : _(LoadBooleanResult) \
256 : _(LoadStringResult) \
257 : _(LoadTypeOfObjectResult) \
258 : \
259 : _(CallStringSplitResult) \
260 : \
261 : _(CompareStringResult) \
262 : _(CompareObjectResult) \
263 : _(CompareSymbolResult) \
264 : \
265 : _(CallPrintString) \
266 : _(Breakpoint) \
267 : \
268 : _(TypeMonitorResult) \
269 : _(ReturnFromIC) \
270 : _(WrapResult)
271 :
272 : enum class CacheOp {
273 : #define DEFINE_OP(op) op,
274 : CACHE_IR_OPS(DEFINE_OP)
275 : #undef DEFINE_OP
276 : };
277 :
278 : class StubField
279 : {
280 : public:
281 : enum class Type : uint8_t {
282 : // These fields take up a single word.
283 : RawWord,
284 : Shape,
285 : ObjectGroup,
286 : JSObject,
287 : Symbol,
288 : String,
289 : Id,
290 :
291 : // These fields take up 64 bits on all platforms.
292 : RawInt64,
293 : First64BitType = RawInt64,
294 : DOMExpandoGeneration,
295 : Value,
296 :
297 : Limit
298 : };
299 :
300 115489 : static bool sizeIsWord(Type type) {
301 115489 : MOZ_ASSERT(type != Type::Limit);
302 115489 : return type < Type::First64BitType;
303 : }
304 0 : static bool sizeIsInt64(Type type) {
305 0 : MOZ_ASSERT(type != Type::Limit);
306 0 : return type >= Type::First64BitType;
307 : }
308 70530 : static size_t sizeInBytes(Type type) {
309 70530 : if (sizeIsWord(type))
310 70530 : return sizeof(uintptr_t);
311 0 : MOZ_ASSERT(sizeIsInt64(type));
312 0 : return sizeof(int64_t);
313 : }
314 :
315 : private:
316 : union {
317 : uintptr_t dataWord_;
318 : uint64_t dataInt64_;
319 : };
320 : Type type_;
321 :
322 : public:
323 17887 : StubField(uint64_t data, Type type)
324 17887 : : dataInt64_(data), type_(type)
325 : {
326 17887 : MOZ_ASSERT_IF(sizeIsWord(), data <= UINTPTR_MAX);
327 17887 : }
328 :
329 35372 : Type type() const { return type_; }
330 :
331 44959 : bool sizeIsWord() const { return sizeIsWord(type_); }
332 0 : bool sizeIsInt64() const { return sizeIsInt64(type_); }
333 :
334 22205 : uintptr_t asWord() const { MOZ_ASSERT(sizeIsWord()); return dataWord_; }
335 0 : uint64_t asInt64() const { MOZ_ASSERT(sizeIsInt64()); return dataInt64_; }
336 : } JS_HAZ_GC_POINTER;
337 :
338 : // We use this enum as GuardClass operand, instead of storing Class* pointers
339 : // in the IR, to keep the IR compact and the same size on all platforms.
340 : enum class GuardClassKind : uint8_t
341 : {
342 : Array,
343 : UnboxedArray,
344 : MappedArguments,
345 : UnmappedArguments,
346 : WindowProxy,
347 : JSFunction,
348 : };
349 :
350 : // Class to record CacheIR + some additional metadata for code generation.
351 12114 : class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
352 : {
353 : CompactBufferWriter buffer_;
354 :
355 : uint32_t nextOperandId_;
356 : uint32_t nextInstructionId_;
357 : uint32_t numInputOperands_;
358 :
359 : // The data (shapes, slot offsets, etc.) that will be stored in the ICStub.
360 : Vector<StubField, 8, SystemAllocPolicy> stubFields_;
361 : size_t stubDataSize_;
362 :
363 : // For each operand id, record which instruction accessed it last. This
364 : // information greatly improves register allocation.
365 : Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
366 :
367 : // OperandId and stub offsets are stored in a single byte, so make sure
368 : // this doesn't overflow. We use a very conservative limit for now.
369 : static const size_t MaxOperandIds = 20;
370 : static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
371 : bool tooLarge_;
372 :
373 36377 : void writeOp(CacheOp op) {
374 36377 : MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
375 36377 : buffer_.writeByte(uint32_t(op));
376 36377 : nextInstructionId_++;
377 36377 : }
378 :
379 33329 : void writeOperandId(OperandId opId) {
380 33329 : if (opId.id() < MaxOperandIds) {
381 : static_assert(MaxOperandIds <= UINT8_MAX, "operand id must fit in a single byte");
382 33329 : buffer_.writeByte(opId.id());
383 : } else {
384 0 : tooLarge_ = true;
385 0 : return;
386 : }
387 33329 : if (opId.id() >= operandLastUsed_.length()) {
388 12696 : buffer_.propagateOOM(operandLastUsed_.resize(opId.id() + 1));
389 12696 : if (buffer_.oom())
390 0 : return;
391 : }
392 33329 : MOZ_ASSERT(nextInstructionId_ > 0);
393 33329 : operandLastUsed_[opId.id()] = nextInstructionId_ - 1;
394 : }
395 :
396 1 : void writeInt32Immediate(int32_t i32) {
397 1 : buffer_.writeSigned(i32);
398 1 : }
399 3 : void writeUint32Immediate(uint32_t u32) {
400 3 : buffer_.writeUnsigned(u32);
401 3 : }
402 1 : void writePointer(void* ptr) {
403 1 : buffer_.writeRawPointer(ptr);
404 1 : }
405 :
406 28936 : void writeOpWithOperandId(CacheOp op, OperandId opId) {
407 28936 : writeOp(op);
408 28936 : writeOperandId(opId);
409 28936 : }
410 :
411 17887 : void addStubField(uint64_t value, StubField::Type fieldType) {
412 17887 : size_t newStubDataSize = stubDataSize_ + StubField::sizeInBytes(fieldType);
413 17887 : if (newStubDataSize < MaxStubDataSizeInBytes) {
414 17887 : buffer_.propagateOOM(stubFields_.append(StubField(value, fieldType)));
415 17887 : MOZ_ASSERT((stubDataSize_ % sizeof(uintptr_t)) == 0);
416 17887 : buffer_.writeByte(stubDataSize_ / sizeof(uintptr_t));
417 17887 : stubDataSize_ = newStubDataSize;
418 : } else {
419 0 : tooLarge_ = true;
420 : }
421 17887 : }
422 :
423 : CacheIRWriter(const CacheIRWriter&) = delete;
424 : CacheIRWriter& operator=(const CacheIRWriter&) = delete;
425 :
426 : public:
427 12114 : explicit CacheIRWriter(JSContext* cx)
428 12114 : : CustomAutoRooter(cx),
429 : nextOperandId_(0),
430 : nextInstructionId_(0),
431 : numInputOperands_(0),
432 : stubDataSize_(0),
433 12114 : tooLarge_(false)
434 12114 : {}
435 :
436 30564 : bool failed() const { return buffer_.oom() || tooLarge_; }
437 :
438 5892 : uint32_t numInputOperands() const { return numInputOperands_; }
439 266 : uint32_t numOperandIds() const { return nextOperandId_; }
440 : uint32_t numInstructions() const { return nextInstructionId_; }
441 :
442 272 : size_t numStubFields() const { return stubFields_.length(); }
443 725 : StubField::Type stubFieldType(uint32_t i) const { return stubFields_[i].type(); }
444 :
445 12626 : uint32_t setInputOperandId(uint32_t op) {
446 12626 : MOZ_ASSERT(op == nextOperandId_);
447 12626 : nextOperandId_++;
448 12626 : numInputOperands_++;
449 12626 : return op;
450 : }
451 :
452 14 : void trace(JSTracer* trc) override {
453 : // For now, assert we only GC before we append stub fields.
454 14 : MOZ_RELEASE_ASSERT(stubFields_.empty());
455 14 : }
456 :
457 6361 : size_t stubDataSize() const {
458 6361 : return stubDataSize_;
459 : }
460 : void copyStubData(uint8_t* dest) const;
461 : bool stubDataEqualsMaybeUpdate(uint8_t* stubData, bool* updated) const;
462 :
463 259 : bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
464 259 : if (operandId >= operandLastUsed_.length())
465 0 : return false;
466 259 : return currentInstruction > operandLastUsed_[operandId];
467 : }
468 6899 : const uint8_t* codeStart() const {
469 6899 : MOZ_ASSERT(!failed());
470 6899 : return buffer_.buffer();
471 : }
472 266 : const uint8_t* codeEnd() const {
473 266 : MOZ_ASSERT(!failed());
474 266 : return buffer_.buffer() + buffer_.length();
475 : }
476 7386 : uint32_t codeLength() const {
477 7386 : MOZ_ASSERT(!failed());
478 7386 : return buffer_.length();
479 : }
480 :
481 : // This should not be used when compiling Baseline code, as Baseline code
482 : // shouldn't bake in stub values.
483 29 : StubField readStubFieldForIon(size_t i, StubField::Type type) const {
484 29 : MOZ_ASSERT(stubFields_[i].type() == type);
485 29 : return stubFields_[i];
486 : }
487 :
488 5930 : ObjOperandId guardIsObject(ValOperandId val) {
489 5930 : writeOpWithOperandId(CacheOp::GuardIsObject, val);
490 5930 : return ObjOperandId(val.id());
491 : }
492 1544 : StringOperandId guardIsString(ValOperandId val) {
493 1544 : writeOpWithOperandId(CacheOp::GuardIsString, val);
494 1544 : return StringOperandId(val.id());
495 : }
496 119 : SymbolOperandId guardIsSymbol(ValOperandId val) {
497 119 : writeOpWithOperandId(CacheOp::GuardIsSymbol, val);
498 119 : return SymbolOperandId(val.id());
499 : }
500 341 : Int32OperandId guardIsInt32Index(ValOperandId val) {
501 341 : Int32OperandId res(nextOperandId_++);
502 341 : writeOpWithOperandId(CacheOp::GuardIsInt32Index, val);
503 341 : writeOperandId(res);
504 341 : return res;
505 : }
506 130 : void guardType(ValOperandId val, JSValueType type) {
507 130 : writeOpWithOperandId(CacheOp::GuardType, val);
508 : static_assert(sizeof(type) == sizeof(uint8_t), "JSValueType should fit in a byte");
509 130 : buffer_.writeByte(uint32_t(type));
510 130 : }
511 21 : void guardIsObjectOrNull(ValOperandId val) {
512 21 : writeOpWithOperandId(CacheOp::GuardIsObjectOrNull, val);
513 21 : }
514 7772 : void guardShape(ObjOperandId obj, Shape* shape) {
515 7772 : writeOpWithOperandId(CacheOp::GuardShape, obj);
516 7772 : addStubField(uintptr_t(shape), StubField::Type::Shape);
517 7772 : }
518 1043 : void guardGroup(ObjOperandId obj, ObjectGroup* group) {
519 1043 : writeOpWithOperandId(CacheOp::GuardGroup, obj);
520 1043 : addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
521 1043 : }
522 88 : void guardProto(ObjOperandId obj, JSObject* proto) {
523 88 : writeOpWithOperandId(CacheOp::GuardProto, obj);
524 88 : addStubField(uintptr_t(proto), StubField::Type::JSObject);
525 88 : }
526 110 : void guardClass(ObjOperandId obj, GuardClassKind kind) {
527 : static_assert(sizeof(GuardClassKind) == sizeof(uint8_t),
528 : "GuardClassKind must fit in a byte");
529 110 : writeOpWithOperandId(CacheOp::GuardClass, obj);
530 110 : buffer_.writeByte(uint32_t(kind));
531 110 : }
532 1 : void guardIsNativeFunction(ObjOperandId obj, JSNative nativeFunc) {
533 1 : writeOpWithOperandId(CacheOp::GuardIsNativeFunction, obj);
534 1 : writePointer(JS_FUNC_TO_DATA_PTR(void*, nativeFunc));
535 1 : }
536 683 : void guardIsProxy(ObjOperandId obj) {
537 683 : writeOpWithOperandId(CacheOp::GuardIsProxy, obj);
538 683 : }
539 544 : void guardIsCrossCompartmentWrapper(ObjOperandId obj) {
540 544 : writeOpWithOperandId(CacheOp::GuardIsCrossCompartmentWrapper, obj);
541 544 : }
542 95 : void guardNotDOMProxy(ObjOperandId obj) {
543 95 : writeOpWithOperandId(CacheOp::GuardNotDOMProxy, obj);
544 95 : }
545 0 : void guardSpecificObject(ObjOperandId obj, JSObject* expected) {
546 0 : writeOpWithOperandId(CacheOp::GuardSpecificObject, obj);
547 0 : addStubField(uintptr_t(expected), StubField::Type::JSObject);
548 0 : }
549 792 : void guardSpecificAtom(StringOperandId str, JSAtom* expected) {
550 792 : writeOpWithOperandId(CacheOp::GuardSpecificAtom, str);
551 792 : addStubField(uintptr_t(expected), StubField::Type::String);
552 792 : }
553 119 : void guardSpecificSymbol(SymbolOperandId sym, JS::Symbol* expected) {
554 119 : writeOpWithOperandId(CacheOp::GuardSpecificSymbol, sym);
555 119 : addStubField(uintptr_t(expected), StubField::Type::Symbol);
556 119 : }
557 1 : void guardSpecificInt32Immediate(Int32OperandId operand, int32_t expected) {
558 1 : writeOp(CacheOp::GuardSpecificInt32Immediate);
559 1 : writeOperandId(operand);
560 1 : writeInt32Immediate(expected);
561 1 : }
562 54 : void guardMagicValue(ValOperandId val, JSWhyMagic magic) {
563 54 : writeOpWithOperandId(CacheOp::GuardMagicValue, val);
564 54 : buffer_.writeByte(uint32_t(magic));
565 54 : }
566 544 : void guardCompartment(ObjOperandId obj, JSObject* global, JSCompartment* compartment) {
567 544 : writeOpWithOperandId(CacheOp::GuardCompartment, obj);
568 : // Add a reference to the compartment's global to keep it alive.
569 544 : addStubField(uintptr_t(global), StubField::Type::JSObject);
570 : // Use RawWord, because compartments never move and it can't be GCed.
571 544 : addStubField(uintptr_t(compartment), StubField::Type::RawWord);
572 544 : }
573 0 : void guardNoDetachedTypedObjects() {
574 0 : writeOp(CacheOp::GuardNoDetachedTypedObjects);
575 0 : }
576 54 : void guardFrameHasNoArgumentsObject() {
577 54 : writeOp(CacheOp::GuardFrameHasNoArgumentsObject);
578 54 : }
579 :
580 2 : Int32OperandId guardAndGetIndexFromString(StringOperandId str) {
581 2 : Int32OperandId res(nextOperandId_++);
582 2 : writeOpWithOperandId(CacheOp::GuardAndGetIndexFromString, str);
583 2 : writeOperandId(res);
584 2 : return res;
585 : }
586 :
587 16 : void guardHasGetterSetter(ObjOperandId obj, Shape* shape) {
588 16 : writeOpWithOperandId(CacheOp::GuardHasGetterSetter, obj);
589 16 : addStubField(uintptr_t(shape), StubField::Type::Shape);
590 16 : }
591 111 : void guardGroupHasUnanalyzedNewScript(ObjectGroup* group) {
592 111 : writeOp(CacheOp::GuardGroupHasUnanalyzedNewScript);
593 111 : addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
594 111 : }
595 :
596 0 : void loadFrameCalleeResult() {
597 0 : writeOp(CacheOp::LoadFrameCalleeResult);
598 0 : }
599 38 : void loadFrameNumActualArgsResult() {
600 38 : writeOp(CacheOp::LoadFrameNumActualArgsResult);
601 38 : }
602 16 : void loadFrameArgumentResult(Int32OperandId index) {
603 16 : writeOpWithOperandId(CacheOp::LoadFrameArgumentResult, index);
604 16 : }
605 2 : void guardNoDenseElements(ObjOperandId obj) {
606 2 : writeOpWithOperandId(CacheOp::GuardNoDenseElements, obj);
607 2 : }
608 0 : void guardNoUnboxedExpando(ObjOperandId obj) {
609 0 : writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
610 0 : }
611 0 : ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
612 0 : ObjOperandId res(nextOperandId_++);
613 0 : writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
614 0 : writeOperandId(res);
615 0 : return res;
616 : }
617 :
618 3 : ValOperandId loadStackValue(uint32_t idx) {
619 3 : ValOperandId res(nextOperandId_++);
620 3 : writeOpWithOperandId(CacheOp::LoadStackValue, res);
621 3 : writeUint32Immediate(idx);
622 3 : return res;
623 : }
624 788 : ObjOperandId loadObject(JSObject* obj) {
625 788 : ObjOperandId res(nextOperandId_++);
626 788 : writeOpWithOperandId(CacheOp::LoadObject, res);
627 788 : addStubField(uintptr_t(obj), StubField::Type::JSObject);
628 788 : return res;
629 : }
630 948 : ObjOperandId loadProto(ObjOperandId obj) {
631 948 : ObjOperandId res(nextOperandId_++);
632 948 : writeOpWithOperandId(CacheOp::LoadProto, obj);
633 948 : writeOperandId(res);
634 948 : return res;
635 : }
636 :
637 731 : ObjOperandId loadEnclosingEnvironment(ObjOperandId obj) {
638 731 : ObjOperandId res(nextOperandId_++);
639 731 : writeOpWithOperandId(CacheOp::LoadEnclosingEnvironment, obj);
640 731 : writeOperandId(res);
641 731 : return res;
642 : }
643 :
644 544 : ObjOperandId loadWrapperTarget(ObjOperandId obj) {
645 544 : ObjOperandId res(nextOperandId_++);
646 544 : writeOpWithOperandId(CacheOp::LoadWrapperTarget, obj);
647 544 : writeOperandId(res);
648 544 : return res;
649 : }
650 :
651 6 : ValOperandId loadDOMExpandoValue(ObjOperandId obj) {
652 6 : ValOperandId res(nextOperandId_++);
653 6 : writeOpWithOperandId(CacheOp::LoadDOMExpandoValue, obj);
654 6 : writeOperandId(res);
655 6 : return res;
656 : }
657 0 : void guardDOMExpandoMissingOrGuardShape(ValOperandId expando, Shape* shape) {
658 0 : writeOpWithOperandId(CacheOp::GuardDOMExpandoMissingOrGuardShape, expando);
659 0 : addStubField(uintptr_t(shape), StubField::Type::Shape);
660 0 : }
661 0 : ValOperandId loadDOMExpandoValueGuardGeneration(ObjOperandId obj,
662 : ExpandoAndGeneration* expandoAndGeneration)
663 : {
664 0 : ValOperandId res(nextOperandId_++);
665 0 : writeOpWithOperandId(CacheOp::LoadDOMExpandoValueGuardGeneration, obj);
666 0 : addStubField(uintptr_t(expandoAndGeneration), StubField::Type::RawWord);
667 0 : addStubField(expandoAndGeneration->generation, StubField::Type::DOMExpandoGeneration);
668 0 : writeOperandId(res);
669 0 : return res;
670 : }
671 0 : ValOperandId loadDOMExpandoValueIgnoreGeneration(ObjOperandId obj) {
672 0 : ValOperandId res(nextOperandId_++);
673 0 : writeOpWithOperandId(CacheOp::LoadDOMExpandoValueIgnoreGeneration, obj);
674 0 : writeOperandId(res);
675 0 : return res;
676 : }
677 :
678 381 : void storeFixedSlot(ObjOperandId obj, size_t offset, ValOperandId rhs) {
679 381 : writeOpWithOperandId(CacheOp::StoreFixedSlot, obj);
680 381 : addStubField(offset, StubField::Type::RawWord);
681 381 : writeOperandId(rhs);
682 381 : }
683 41 : void storeDynamicSlot(ObjOperandId obj, size_t offset, ValOperandId rhs) {
684 41 : writeOpWithOperandId(CacheOp::StoreDynamicSlot, obj);
685 41 : addStubField(offset, StubField::Type::RawWord);
686 41 : writeOperandId(rhs);
687 41 : }
688 110 : void addAndStoreFixedSlot(ObjOperandId obj, size_t offset, ValOperandId rhs,
689 : Shape* newShape, bool changeGroup, ObjectGroup* newGroup)
690 : {
691 110 : writeOpWithOperandId(CacheOp::AddAndStoreFixedSlot, obj);
692 110 : addStubField(offset, StubField::Type::RawWord);
693 110 : writeOperandId(rhs);
694 110 : buffer_.writeByte(changeGroup);
695 110 : addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
696 110 : addStubField(uintptr_t(newShape), StubField::Type::Shape);
697 110 : }
698 274 : void addAndStoreDynamicSlot(ObjOperandId obj, size_t offset, ValOperandId rhs,
699 : Shape* newShape, bool changeGroup, ObjectGroup* newGroup)
700 : {
701 274 : writeOpWithOperandId(CacheOp::AddAndStoreDynamicSlot, obj);
702 274 : addStubField(offset, StubField::Type::RawWord);
703 274 : writeOperandId(rhs);
704 274 : buffer_.writeByte(changeGroup);
705 274 : addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
706 274 : addStubField(uintptr_t(newShape), StubField::Type::Shape);
707 274 : }
708 60 : void allocateAndStoreDynamicSlot(ObjOperandId obj, size_t offset, ValOperandId rhs,
709 : Shape* newShape, bool changeGroup, ObjectGroup* newGroup,
710 : uint32_t numNewSlots)
711 : {
712 60 : writeOpWithOperandId(CacheOp::AllocateAndStoreDynamicSlot, obj);
713 60 : addStubField(offset, StubField::Type::RawWord);
714 60 : writeOperandId(rhs);
715 60 : buffer_.writeByte(changeGroup);
716 60 : addStubField(uintptr_t(newGroup), StubField::Type::ObjectGroup);
717 60 : addStubField(uintptr_t(newShape), StubField::Type::Shape);
718 60 : addStubField(numNewSlots, StubField::Type::RawWord);
719 60 : }
720 :
721 0 : void storeTypedObjectReferenceProperty(ObjOperandId obj, uint32_t offset,
722 : TypedThingLayout layout, ReferenceTypeDescr::Type type,
723 : ValOperandId rhs)
724 : {
725 0 : writeOpWithOperandId(CacheOp::StoreTypedObjectReferenceProperty, obj);
726 0 : addStubField(offset, StubField::Type::RawWord);
727 0 : buffer_.writeByte(uint32_t(layout));
728 0 : buffer_.writeByte(uint32_t(type));
729 0 : writeOperandId(rhs);
730 0 : }
731 0 : void storeTypedObjectScalarProperty(ObjOperandId obj, uint32_t offset, TypedThingLayout layout,
732 : Scalar::Type type, ValOperandId rhs)
733 : {
734 0 : writeOpWithOperandId(CacheOp::StoreTypedObjectScalarProperty, obj);
735 0 : addStubField(offset, StubField::Type::RawWord);
736 0 : buffer_.writeByte(uint32_t(layout));
737 0 : buffer_.writeByte(uint32_t(type));
738 0 : writeOperandId(rhs);
739 0 : }
740 47 : void storeUnboxedProperty(ObjOperandId obj, JSValueType type, size_t offset,
741 : ValOperandId rhs)
742 : {
743 47 : writeOpWithOperandId(CacheOp::StoreUnboxedProperty, obj);
744 47 : buffer_.writeByte(uint32_t(type));
745 47 : addStubField(offset, StubField::Type::RawWord);
746 47 : writeOperandId(rhs);
747 47 : }
748 26 : void storeDenseElement(ObjOperandId obj, Int32OperandId index, ValOperandId rhs) {
749 26 : writeOpWithOperandId(CacheOp::StoreDenseElement, obj);
750 26 : writeOperandId(index);
751 26 : writeOperandId(rhs);
752 26 : }
753 0 : void storeTypedElement(ObjOperandId obj, Int32OperandId index, ValOperandId rhs,
754 : TypedThingLayout layout, Scalar::Type elementType, bool handleOOB)
755 : {
756 0 : writeOpWithOperandId(CacheOp::StoreTypedElement, obj);
757 0 : writeOperandId(index);
758 0 : writeOperandId(rhs);
759 0 : buffer_.writeByte(uint32_t(layout));
760 0 : buffer_.writeByte(uint32_t(elementType));
761 0 : buffer_.writeByte(uint32_t(handleOOB));
762 0 : }
763 0 : void storeUnboxedArrayElement(ObjOperandId obj, Int32OperandId index, ValOperandId rhs,
764 : JSValueType elementType)
765 : {
766 0 : writeOpWithOperandId(CacheOp::StoreUnboxedArrayElement, obj);
767 0 : writeOperandId(index);
768 0 : writeOperandId(rhs);
769 0 : buffer_.writeByte(uint32_t(elementType));
770 0 : }
771 0 : void storeUnboxedArrayElementHole(ObjOperandId obj, Int32OperandId index, ValOperandId rhs,
772 : JSValueType elementType)
773 : {
774 0 : writeOpWithOperandId(CacheOp::StoreUnboxedArrayElementHole, obj);
775 0 : writeOperandId(index);
776 0 : writeOperandId(rhs);
777 0 : buffer_.writeByte(uint32_t(elementType));
778 0 : }
779 96 : void storeDenseElementHole(ObjOperandId obj, Int32OperandId index, ValOperandId rhs,
780 : bool handleAdd)
781 : {
782 96 : writeOpWithOperandId(CacheOp::StoreDenseElementHole, obj);
783 96 : writeOperandId(index);
784 96 : writeOperandId(rhs);
785 96 : buffer_.writeByte(handleAdd);
786 96 : }
787 4 : void callScriptedSetter(ObjOperandId obj, JSFunction* setter, ValOperandId rhs) {
788 4 : writeOpWithOperandId(CacheOp::CallScriptedSetter, obj);
789 4 : addStubField(uintptr_t(setter), StubField::Type::JSObject);
790 4 : writeOperandId(rhs);
791 4 : }
792 6 : void callNativeSetter(ObjOperandId obj, JSFunction* setter, ValOperandId rhs) {
793 6 : writeOpWithOperandId(CacheOp::CallNativeSetter, obj);
794 6 : addStubField(uintptr_t(setter), StubField::Type::JSObject);
795 6 : writeOperandId(rhs);
796 6 : }
797 10 : void callSetArrayLength(ObjOperandId obj, bool strict, ValOperandId rhs) {
798 10 : writeOpWithOperandId(CacheOp::CallSetArrayLength, obj);
799 10 : buffer_.writeByte(uint32_t(strict));
800 10 : writeOperandId(rhs);
801 10 : }
802 14 : void callProxySet(ObjOperandId obj, jsid id, ValOperandId rhs, bool strict) {
803 14 : writeOpWithOperandId(CacheOp::CallProxySet, obj);
804 14 : writeOperandId(rhs);
805 14 : addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
806 14 : buffer_.writeByte(uint32_t(strict));
807 14 : }
808 1 : void callProxySetByValue(ObjOperandId obj, ValOperandId id, ValOperandId rhs, bool strict) {
809 1 : writeOpWithOperandId(CacheOp::CallProxySetByValue, obj);
810 1 : writeOperandId(id);
811 1 : writeOperandId(rhs);
812 1 : buffer_.writeByte(uint32_t(strict));
813 1 : }
814 :
815 28 : void megamorphicLoadSlotResult(ObjOperandId obj, PropertyName* name, bool handleMissing) {
816 28 : writeOpWithOperandId(CacheOp::MegamorphicLoadSlotResult, obj);
817 28 : addStubField(uintptr_t(name), StubField::Type::String);
818 28 : buffer_.writeByte(uint32_t(handleMissing));
819 28 : }
820 33 : void megamorphicLoadSlotByValueResult(ObjOperandId obj, ValOperandId id, bool handleMissing) {
821 33 : writeOpWithOperandId(CacheOp::MegamorphicLoadSlotByValueResult, obj);
822 33 : writeOperandId(id);
823 33 : buffer_.writeByte(uint32_t(handleMissing));
824 33 : }
825 0 : void megamorphicStoreSlot(ObjOperandId obj, PropertyName* name, ValOperandId rhs,
826 : bool needsTypeBarrier) {
827 0 : writeOpWithOperandId(CacheOp::MegamorphicStoreSlot, obj);
828 0 : addStubField(uintptr_t(name), StubField::Type::String);
829 0 : writeOperandId(rhs);
830 0 : buffer_.writeByte(needsTypeBarrier);
831 0 : }
832 0 : void megamorphicHasOwnResult(ObjOperandId obj, ValOperandId id) {
833 0 : writeOpWithOperandId(CacheOp::MegamorphicHasOwnResult, obj);
834 0 : writeOperandId(id);
835 0 : }
836 :
837 123 : void loadBooleanResult(bool val) {
838 123 : writeOp(CacheOp::LoadBooleanResult);
839 123 : buffer_.writeByte(uint32_t(val));
840 123 : }
841 193 : void loadUndefinedResult() {
842 193 : writeOp(CacheOp::LoadUndefinedResult);
843 193 : }
844 61 : void loadStringResult(JSString* str) {
845 61 : writeOp(CacheOp::LoadStringResult);
846 61 : addStubField(uintptr_t(str), StubField::Type::String);
847 61 : }
848 1034 : void loadFixedSlotResult(ObjOperandId obj, size_t offset) {
849 1034 : writeOpWithOperandId(CacheOp::LoadFixedSlotResult, obj);
850 1034 : addStubField(offset, StubField::Type::RawWord);
851 1034 : }
852 2760 : void loadDynamicSlotResult(ObjOperandId obj, size_t offset) {
853 2760 : writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj);
854 2760 : addStubField(offset, StubField::Type::RawWord);
855 2760 : }
856 8 : void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, size_t offset) {
857 8 : writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj);
858 8 : buffer_.writeByte(uint32_t(type));
859 8 : addStubField(offset, StubField::Type::RawWord);
860 8 : }
861 0 : void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout,
862 : uint32_t typeDescr) {
863 0 : MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX);
864 0 : MOZ_ASSERT(typeDescr <= UINT8_MAX);
865 0 : writeOpWithOperandId(CacheOp::LoadTypedObjectResult, obj);
866 0 : buffer_.writeByte(uint32_t(layout));
867 0 : buffer_.writeByte(typeDescr);
868 0 : addStubField(offset, StubField::Type::RawWord);
869 0 : }
870 99 : void loadInt32ArrayLengthResult(ObjOperandId obj) {
871 99 : writeOpWithOperandId(CacheOp::LoadInt32ArrayLengthResult, obj);
872 99 : }
873 0 : void loadUnboxedArrayLengthResult(ObjOperandId obj) {
874 0 : writeOpWithOperandId(CacheOp::LoadUnboxedArrayLengthResult, obj);
875 0 : }
876 1 : void loadArgumentsObjectLengthResult(ObjOperandId obj) {
877 1 : writeOpWithOperandId(CacheOp::LoadArgumentsObjectLengthResult, obj);
878 1 : }
879 0 : void loadFunctionLengthResult(ObjOperandId obj) {
880 0 : writeOpWithOperandId(CacheOp::LoadFunctionLengthResult, obj);
881 0 : }
882 0 : void loadArgumentsObjectArgResult(ObjOperandId obj, Int32OperandId index) {
883 0 : writeOpWithOperandId(CacheOp::LoadArgumentsObjectArgResult, obj);
884 0 : writeOperandId(index);
885 0 : }
886 145 : void loadDenseElementResult(ObjOperandId obj, Int32OperandId index) {
887 145 : writeOpWithOperandId(CacheOp::LoadDenseElementResult, obj);
888 145 : writeOperandId(index);
889 145 : }
890 2 : void loadDenseElementHoleResult(ObjOperandId obj, Int32OperandId index) {
891 2 : writeOpWithOperandId(CacheOp::LoadDenseElementHoleResult, obj);
892 2 : writeOperandId(index);
893 2 : }
894 37 : void loadDenseElementExistsResult(ObjOperandId obj, Int32OperandId index) {
895 37 : writeOpWithOperandId(CacheOp::LoadDenseElementExistsResult, obj);
896 37 : writeOperandId(index);
897 37 : }
898 0 : void loadDenseElementHoleExistsResult(ObjOperandId obj, Int32OperandId index) {
899 0 : writeOpWithOperandId(CacheOp::LoadDenseElementHoleExistsResult, obj);
900 0 : writeOperandId(index);
901 0 : }
902 0 : void loadUnboxedArrayElementResult(ObjOperandId obj, Int32OperandId index, JSValueType elementType) {
903 0 : writeOpWithOperandId(CacheOp::LoadUnboxedArrayElementResult, obj);
904 0 : writeOperandId(index);
905 0 : buffer_.writeByte(uint32_t(elementType));
906 0 : }
907 0 : void loadTypedElementResult(ObjOperandId obj, Int32OperandId index, TypedThingLayout layout,
908 : Scalar::Type elementType) {
909 0 : writeOpWithOperandId(CacheOp::LoadTypedElementResult, obj);
910 0 : writeOperandId(index);
911 0 : buffer_.writeByte(uint32_t(layout));
912 0 : buffer_.writeByte(uint32_t(elementType));
913 0 : }
914 13 : void loadStringLengthResult(StringOperandId str) {
915 13 : writeOpWithOperandId(CacheOp::LoadStringLengthResult, str);
916 13 : }
917 3 : void loadStringCharResult(StringOperandId str, Int32OperandId index) {
918 3 : writeOpWithOperandId(CacheOp::LoadStringCharResult, str);
919 3 : writeOperandId(index);
920 3 : }
921 66 : void callScriptedGetterResult(ObjOperandId obj, JSFunction* getter) {
922 66 : writeOpWithOperandId(CacheOp::CallScriptedGetterResult, obj);
923 66 : addStubField(uintptr_t(getter), StubField::Type::JSObject);
924 66 : }
925 112 : void callNativeGetterResult(ObjOperandId obj, JSFunction* getter) {
926 112 : writeOpWithOperandId(CacheOp::CallNativeGetterResult, obj);
927 112 : addStubField(uintptr_t(getter), StubField::Type::JSObject);
928 112 : }
929 104 : void callProxyGetResult(ObjOperandId obj, jsid id) {
930 104 : writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
931 104 : addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
932 104 : }
933 20 : void callProxyGetByValueResult(ObjOperandId obj, ValOperandId idVal) {
934 20 : writeOpWithOperandId(CacheOp::CallProxyGetByValueResult, obj);
935 20 : writeOperandId(idVal);
936 20 : }
937 0 : void callProxyHasOwnResult(ObjOperandId obj, ValOperandId idVal) {
938 0 : writeOpWithOperandId(CacheOp::CallProxyHasOwnResult, obj);
939 0 : writeOperandId(idVal);
940 0 : }
941 4 : void loadEnvironmentFixedSlotResult(ObjOperandId obj, size_t offset) {
942 4 : writeOpWithOperandId(CacheOp::LoadEnvironmentFixedSlotResult, obj);
943 4 : addStubField(offset, StubField::Type::RawWord);
944 4 : }
945 7 : void loadEnvironmentDynamicSlotResult(ObjOperandId obj, size_t offset) {
946 7 : writeOpWithOperandId(CacheOp::LoadEnvironmentDynamicSlotResult, obj);
947 7 : addStubField(offset, StubField::Type::RawWord);
948 7 : }
949 0 : void loadObjectResult(ObjOperandId obj) {
950 0 : writeOpWithOperandId(CacheOp::LoadObjectResult, obj);
951 0 : }
952 19 : void loadTypeOfObjectResult(ObjOperandId obj) {
953 19 : writeOpWithOperandId(CacheOp::LoadTypeOfObjectResult, obj);
954 19 : }
955 :
956 1 : void callStringSplitResult(StringOperandId str, StringOperandId sep, ObjectGroup* group) {
957 1 : writeOp(CacheOp::CallStringSplitResult);
958 1 : writeOperandId(str);
959 1 : writeOperandId(sep);
960 1 : addStubField(uintptr_t(group), StubField::Type::ObjectGroup);
961 1 : }
962 :
963 366 : void compareStringResult(uint32_t op, StringOperandId lhs, StringOperandId rhs) {
964 366 : writeOpWithOperandId(CacheOp::CompareStringResult, lhs);
965 366 : writeOperandId(rhs);
966 366 : buffer_.writeByte(uint32_t(op));
967 366 : }
968 19 : void compareObjectResult(uint32_t op, ObjOperandId lhs, ObjOperandId rhs) {
969 19 : writeOpWithOperandId(CacheOp::CompareObjectResult, lhs);
970 19 : writeOperandId(rhs);
971 19 : buffer_.writeByte(uint32_t(op));
972 19 : }
973 0 : void compareSymbolResult(uint32_t op, SymbolOperandId lhs, SymbolOperandId rhs) {
974 0 : writeOpWithOperandId(CacheOp::CompareSymbolResult, lhs);
975 0 : writeOperandId(rhs);
976 0 : buffer_.writeByte(uint32_t(op));
977 0 : }
978 :
979 : void callPrintString(const char* str) {
980 : writeOp(CacheOp::CallPrintString);
981 : writePointer(const_cast<char*>(str));
982 : }
983 : void breakpoint() {
984 : writeOp(CacheOp::Breakpoint);
985 : }
986 :
987 4335 : void typeMonitorResult() {
988 4335 : writeOp(CacheOp::TypeMonitorResult);
989 4335 : }
990 2047 : void returnFromIC() {
991 2047 : writeOp(CacheOp::ReturnFromIC);
992 2047 : }
993 477 : void wrapResult() {
994 477 : writeOp(CacheOp::WrapResult);
995 477 : }
996 : };
997 :
998 : class CacheIRStubInfo;
999 :
1000 : // Helper class for reading CacheIR bytecode.
1001 : class MOZ_RAII CacheIRReader
1002 : {
1003 : CompactBufferReader buffer_;
1004 :
1005 : CacheIRReader(const CacheIRReader&) = delete;
1006 : CacheIRReader& operator=(const CacheIRReader&) = delete;
1007 :
1008 : public:
1009 410 : CacheIRReader(const uint8_t* start, const uint8_t* end)
1010 410 : : buffer_(start, end)
1011 410 : {}
1012 266 : explicit CacheIRReader(const CacheIRWriter& writer)
1013 266 : : CacheIRReader(writer.codeStart(), writer.codeEnd())
1014 266 : {}
1015 : explicit CacheIRReader(const CacheIRStubInfo* stubInfo);
1016 :
1017 1609 : bool more() const { return buffer_.more(); }
1018 :
1019 2188 : CacheOp readOp() {
1020 2188 : return CacheOp(buffer_.readByte());
1021 : }
1022 :
1023 454 : ValOperandId valOperandId() { return ValOperandId(buffer_.readByte()); }
1024 937 : ObjOperandId objOperandId() { return ObjOperandId(buffer_.readByte()); }
1025 70 : StringOperandId stringOperandId() { return StringOperandId(buffer_.readByte()); }
1026 14 : SymbolOperandId symbolOperandId() { return SymbolOperandId(buffer_.readByte()); }
1027 59 : Int32OperandId int32OperandId() { return Int32OperandId(buffer_.readByte()); }
1028 :
1029 805 : uint32_t stubOffset() { return buffer_.readByte() * sizeof(uintptr_t); }
1030 14 : GuardClassKind guardClassKind() { return GuardClassKind(buffer_.readByte()); }
1031 38 : JSValueType valueType() { return JSValueType(buffer_.readByte()); }
1032 0 : TypedThingLayout typedThingLayout() { return TypedThingLayout(buffer_.readByte()); }
1033 0 : Scalar::Type scalarType() { return Scalar::Type(buffer_.readByte()); }
1034 0 : uint32_t typeDescrKey() { return buffer_.readByte(); }
1035 6 : JSWhyMagic whyMagic() { return JSWhyMagic(buffer_.readByte()); }
1036 15 : JSOp jsop() { return JSOp(buffer_.readByte()); }
1037 1 : int32_t int32Immediate() { return buffer_.readSigned(); }
1038 3 : uint32_t uint32Immediate() { return buffer_.readUnsigned(); }
1039 1 : void* pointer() { return buffer_.readRawPointer(); }
1040 :
1041 0 : ReferenceTypeDescr::Type referenceTypeDescrType() {
1042 0 : return ReferenceTypeDescr::Type(buffer_.readByte());
1043 : }
1044 :
1045 60 : bool readBool() {
1046 60 : uint8_t b = buffer_.readByte();
1047 60 : MOZ_ASSERT(b <= 1);
1048 60 : return bool(b);
1049 : }
1050 :
1051 46 : bool matchOp(CacheOp op) {
1052 46 : const uint8_t* pos = buffer_.currentPosition();
1053 46 : if (readOp() == op)
1054 0 : return true;
1055 46 : buffer_.seek(pos, 0);
1056 46 : return false;
1057 : }
1058 522 : bool matchOp(CacheOp op, OperandId id) {
1059 522 : const uint8_t* pos = buffer_.currentPosition();
1060 522 : if (readOp() == op && buffer_.readByte() == id.id())
1061 203 : return true;
1062 319 : buffer_.seek(pos, 0);
1063 319 : return false;
1064 : }
1065 11 : bool matchOpEither(CacheOp op1, CacheOp op2) {
1066 11 : const uint8_t* pos = buffer_.currentPosition();
1067 11 : CacheOp op = readOp();
1068 11 : if (op == op1 || op == op2)
1069 10 : return true;
1070 1 : buffer_.seek(pos, 0);
1071 1 : return false;
1072 : }
1073 : };
1074 :
1075 12114 : class MOZ_RAII IRGenerator
1076 : {
1077 : protected:
1078 : CacheIRWriter writer;
1079 : JSContext* cx_;
1080 : HandleScript script_;
1081 : jsbytecode* pc_;
1082 : CacheKind cacheKind_;
1083 : ICState::Mode mode_;
1084 :
1085 : IRGenerator(const IRGenerator&) = delete;
1086 : IRGenerator& operator=(const IRGenerator&) = delete;
1087 :
1088 : bool maybeGuardInt32Index(const Value& index, ValOperandId indexId,
1089 : uint32_t* int32Index, Int32OperandId* int32IndexId);
1090 :
1091 : ObjOperandId guardDOMProxyExpandoObjectAndShape(JSObject* obj, ObjOperandId objId,
1092 : const Value& expandoVal, JSObject* expandoObj);
1093 :
1094 : void emitIdGuard(ValOperandId valId, jsid id);
1095 :
1096 : friend class CacheIRSpewer;
1097 :
1098 : public:
1099 : explicit IRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
1100 : ICState::Mode mode);
1101 :
1102 6382 : const CacheIRWriter& writerRef() const { return writer; }
1103 6382 : CacheKind cacheKind() const { return cacheKind_; }
1104 : };
1105 :
1106 : enum class CanAttachGetter { Yes, No };
1107 :
1108 : // GetPropIRGenerator generates CacheIR for a GetProp IC.
1109 4189 : class MOZ_RAII GetPropIRGenerator : public IRGenerator
1110 : {
1111 : HandleValue val_;
1112 : HandleValue idVal_;
1113 : HandleValue receiver_;
1114 : bool* isTemporarilyUnoptimizable_;
1115 : CanAttachGetter canAttachGetter_;
1116 :
1117 : enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
1118 : PreliminaryObjectAction preliminaryObjectAction_;
1119 :
1120 : bool tryAttachNative(HandleObject obj, ObjOperandId objId, HandleId id);
1121 : bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId, HandleId id);
1122 : bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId, HandleId id);
1123 : bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId, HandleId id);
1124 : bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId, HandleId id);
1125 : bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId, HandleId id);
1126 : bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id);
1127 : bool tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperandId objId, HandleId id);
1128 : bool tryAttachFunction(HandleObject obj, ObjOperandId objId, HandleId id);
1129 :
1130 : bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
1131 : bool handleDOMProxies);
1132 : bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId, HandleId id);
1133 : bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id);
1134 : bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id);
1135 : bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id);
1136 :
1137 : bool tryAttachPrimitive(ValOperandId valId, HandleId id);
1138 : bool tryAttachStringChar(ValOperandId valId, ValOperandId indexId);
1139 : bool tryAttachStringLength(ValOperandId valId, HandleId id);
1140 : bool tryAttachMagicArgumentsName(ValOperandId valId, HandleId id);
1141 :
1142 : bool tryAttachMagicArgument(ValOperandId valId, ValOperandId indexId);
1143 : bool tryAttachArgumentsObjectArg(HandleObject obj, ObjOperandId objId,
1144 : uint32_t index, Int32OperandId indexId);
1145 :
1146 : bool tryAttachDenseElement(HandleObject obj, ObjOperandId objId,
1147 : uint32_t index, Int32OperandId indexId);
1148 : bool tryAttachDenseElementHole(HandleObject obj, ObjOperandId objId,
1149 : uint32_t index, Int32OperandId indexId);
1150 : bool tryAttachUnboxedArrayElement(HandleObject obj, ObjOperandId objId,
1151 : uint32_t index, Int32OperandId indexId);
1152 : bool tryAttachTypedElement(HandleObject obj, ObjOperandId objId,
1153 : uint32_t index, Int32OperandId indexId);
1154 :
1155 : bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId);
1156 :
1157 : void attachMegamorphicNativeSlot(ObjOperandId objId, jsid id, bool handleMissing);
1158 :
1159 1524 : ValOperandId getElemKeyValueId() const {
1160 1524 : MOZ_ASSERT(cacheKind_ == CacheKind::GetElem || cacheKind_ == CacheKind::GetElemSuper);
1161 1524 : return ValOperandId(1);
1162 : }
1163 :
1164 0 : ValOperandId getSuperReceiverValueId() const {
1165 0 : if (cacheKind_ == CacheKind::GetPropSuper)
1166 0 : return ValOperandId(1);
1167 :
1168 0 : MOZ_ASSERT(cacheKind_ == CacheKind::GetElemSuper);
1169 0 : return ValOperandId(2);
1170 : }
1171 :
1172 4615 : bool isSuper() const {
1173 9230 : return (cacheKind_ == CacheKind::GetPropSuper ||
1174 9230 : cacheKind_ == CacheKind::GetElemSuper);
1175 : }
1176 :
1177 : // No pc if idempotent, as there can be multiple bytecode locations
1178 : // due to GVN.
1179 7992 : bool idempotent() const { return pc_ == nullptr; }
1180 :
1181 : // If this is a GetElem cache, emit instructions to guard the incoming Value
1182 : // matches |id|.
1183 : void maybeEmitIdGuard(jsid id);
1184 :
1185 : void trackAttached(const char* name);
1186 : void trackNotAttached();
1187 :
1188 : public:
1189 : GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
1190 : ICState::Mode mode, bool* isTemporarilyUnoptimizable, HandleValue val,
1191 : HandleValue idVal, HandleValue receiver, CanAttachGetter canAttachGetter);
1192 :
1193 : bool tryAttachStub();
1194 : bool tryAttachIdempotentStub();
1195 :
1196 3242 : bool shouldUnlinkPreliminaryObjectStubs() const {
1197 3242 : return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
1198 : }
1199 3669 : bool shouldNotePreliminaryObjectStub() const {
1200 3669 : return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
1201 : }
1202 : };
1203 :
1204 : // GetNameIRGenerator generates CacheIR for a GetName IC.
1205 977 : class MOZ_RAII GetNameIRGenerator : public IRGenerator
1206 : {
1207 : HandleObject env_;
1208 : HandlePropertyName name_;
1209 :
1210 : bool tryAttachGlobalNameValue(ObjOperandId objId, HandleId id);
1211 : bool tryAttachGlobalNameGetter(ObjOperandId objId, HandleId id);
1212 : bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
1213 :
1214 : void trackAttached(const char* name);
1215 : void trackNotAttached();
1216 :
1217 : public:
1218 : GetNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode,
1219 : HandleObject env, HandlePropertyName name);
1220 :
1221 : bool tryAttachStub();
1222 : };
1223 :
1224 : // BindNameIRGenerator generates CacheIR for a BindName IC.
1225 0 : class MOZ_RAII BindNameIRGenerator : public IRGenerator
1226 : {
1227 : HandleObject env_;
1228 : HandlePropertyName name_;
1229 :
1230 : bool tryAttachGlobalName(ObjOperandId objId, HandleId id);
1231 : bool tryAttachEnvironmentName(ObjOperandId objId, HandleId id);
1232 :
1233 : void trackAttached(const char* name);
1234 : void trackNotAttached();
1235 :
1236 : public:
1237 : BindNameIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, ICState::Mode mode,
1238 : HandleObject env, HandlePropertyName name);
1239 :
1240 : bool tryAttachStub();
1241 : };
1242 :
1243 : // Information used by SetProp/SetElem stubs to check/update property types.
1244 1705 : class MOZ_RAII PropertyTypeCheckInfo
1245 : {
1246 : RootedObjectGroup group_;
1247 : RootedId id_;
1248 : bool needsTypeBarrier_;
1249 :
1250 : PropertyTypeCheckInfo(const PropertyTypeCheckInfo&) = delete;
1251 : void operator=(const PropertyTypeCheckInfo&) = delete;
1252 :
1253 : public:
1254 1705 : PropertyTypeCheckInfo(JSContext* cx, bool needsTypeBarrier)
1255 1705 : : group_(cx), id_(cx), needsTypeBarrier_(needsTypeBarrier)
1256 1705 : {}
1257 :
1258 544 : bool needsTypeBarrier() const { return needsTypeBarrier_; }
1259 3137 : bool isSet() const { return group_ != nullptr; }
1260 1034 : ObjectGroup* group() const { MOZ_ASSERT(isSet()); return group_; }
1261 1034 : jsid id() const { MOZ_ASSERT(isSet()); return id_; }
1262 :
1263 1035 : void set(ObjectGroup* group, jsid id) {
1264 1035 : MOZ_ASSERT(!group_);
1265 1035 : MOZ_ASSERT(group);
1266 1035 : if (needsTypeBarrier_) {
1267 1035 : group_ = group;
1268 1035 : id_ = id;
1269 : }
1270 1035 : }
1271 : };
1272 :
1273 : // SetPropIRGenerator generates CacheIR for a SetProp IC.
1274 1705 : class MOZ_RAII SetPropIRGenerator : public IRGenerator
1275 : {
1276 : HandleValue lhsVal_;
1277 : HandleValue idVal_;
1278 : HandleValue rhsVal_;
1279 : bool* isTemporarilyUnoptimizable_;
1280 : PropertyTypeCheckInfo typeCheckInfo_;
1281 :
1282 : enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
1283 : PreliminaryObjectAction preliminaryObjectAction_;
1284 : bool attachedTypedArrayOOBStub_;
1285 :
1286 : bool maybeHasExtraIndexedProps_;
1287 :
1288 1258 : ValOperandId setElemKeyValueId() const {
1289 1258 : MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
1290 1258 : return ValOperandId(1);
1291 : }
1292 : ValOperandId rhsValueId() const {
1293 : if (cacheKind_ == CacheKind::SetProp)
1294 : return ValOperandId(1);
1295 : MOZ_ASSERT(cacheKind_ == CacheKind::SetElem);
1296 : return ValOperandId(2);
1297 : }
1298 :
1299 : // If this is a SetElem cache, emit instructions to guard the incoming Value
1300 : // matches |id|.
1301 : void maybeEmitIdGuard(jsid id);
1302 :
1303 : bool tryAttachNativeSetSlot(HandleObject obj, ObjOperandId objId, HandleId id,
1304 : ValOperandId rhsId);
1305 : bool tryAttachUnboxedExpandoSetSlot(HandleObject obj, ObjOperandId objId, HandleId id,
1306 : ValOperandId rhsId);
1307 : bool tryAttachUnboxedProperty(HandleObject obj, ObjOperandId objId, HandleId id,
1308 : ValOperandId rhsId);
1309 : bool tryAttachTypedObjectProperty(HandleObject obj, ObjOperandId objId, HandleId id,
1310 : ValOperandId rhsId);
1311 : bool tryAttachSetter(HandleObject obj, ObjOperandId objId, HandleId id,
1312 : ValOperandId rhsId);
1313 : bool tryAttachSetArrayLength(HandleObject obj, ObjOperandId objId, HandleId id,
1314 : ValOperandId rhsId);
1315 : bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id,
1316 : ValOperandId rhsId);
1317 :
1318 : bool tryAttachSetDenseElement(HandleObject obj, ObjOperandId objId, uint32_t index,
1319 : Int32OperandId indexId, ValOperandId rhsId);
1320 : bool tryAttachSetUnboxedArrayElement(HandleObject obj, ObjOperandId objId, uint32_t index,
1321 : Int32OperandId indexId, ValOperandId rhsId);
1322 : bool tryAttachSetTypedElement(HandleObject obj, ObjOperandId objId, uint32_t index,
1323 : Int32OperandId indexId, ValOperandId rhsId);
1324 :
1325 : bool tryAttachSetDenseElementHole(HandleObject obj, ObjOperandId objId, uint32_t index,
1326 : Int32OperandId indexId, ValOperandId rhsId);
1327 : bool tryAttachSetUnboxedArrayElementHole(HandleObject obj, ObjOperandId objId, uint32_t index,
1328 : Int32OperandId indexId, ValOperandId rhsId);
1329 :
1330 : bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId, HandleId id,
1331 : ValOperandId rhsId, bool handleDOMProxies);
1332 : bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId, HandleId id,
1333 : ValOperandId rhsId);
1334 : bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId, HandleId id,
1335 : ValOperandId rhsId);
1336 : bool tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objId, HandleId id,
1337 : ValOperandId rhsId);
1338 : bool tryAttachProxy(HandleObject obj, ObjOperandId objId, HandleId id, ValOperandId rhsId);
1339 : bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId, ValOperandId rhsId);
1340 :
1341 : void trackAttached(const char* name);
1342 :
1343 : public:
1344 : SetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
1345 : ICState::Mode mode, bool* isTemporarilyUnoptimizable, HandleValue lhsVal,
1346 : HandleValue idVal, HandleValue rhsVal, bool needsTypeBarrier = true,
1347 : bool maybeHasExtraIndexedProps = true);
1348 :
1349 : bool tryAttachStub();
1350 : bool tryAttachAddSlotStub(HandleObjectGroup oldGroup, HandleShape oldShape);
1351 : void trackNotAttached();
1352 :
1353 605 : bool shouldUnlinkPreliminaryObjectStubs() const {
1354 605 : return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
1355 : }
1356 1069 : bool shouldNotePreliminaryObjectStub() const {
1357 1069 : return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
1358 : }
1359 :
1360 1069 : const PropertyTypeCheckInfo* typeCheckInfo() const {
1361 1069 : return &typeCheckInfo_;
1362 : }
1363 :
1364 146 : bool attachedTypedArrayOOBStub() const {
1365 146 : return attachedTypedArrayOOBStub_;
1366 : }
1367 : };
1368 :
1369 : // HasPropIRGenerator generates CacheIR for a HasProp IC. Used for
1370 : // CacheKind::In / CacheKind::HasOwn.
1371 184 : class MOZ_RAII HasPropIRGenerator : public IRGenerator
1372 : {
1373 : HandleValue val_;
1374 : HandleValue idVal_;
1375 :
1376 : bool tryAttachDense(HandleObject obj, ObjOperandId objId,
1377 : uint32_t index, Int32OperandId indexId);
1378 : bool tryAttachDenseHole(HandleObject obj, ObjOperandId objId,
1379 : uint32_t index, Int32OperandId indexId);
1380 : bool tryAttachNative(HandleObject obj, ObjOperandId objId,
1381 : HandleId key, ValOperandId keyId);
1382 : bool tryAttachNativeDoesNotExist(HandleObject obj, ObjOperandId objId,
1383 : HandleId key, ValOperandId keyId);
1384 : bool tryAttachProxyElement(HandleObject obj, ObjOperandId objId,
1385 : ValOperandId keyId);
1386 :
1387 : void trackAttached(const char* name);
1388 : void trackNotAttached();
1389 :
1390 : public:
1391 : // NOTE: Argument order is PROPERTY, OBJECT
1392 : HasPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
1393 : ICState::Mode mode, HandleValue idVal, HandleValue val);
1394 :
1395 : bool tryAttachStub();
1396 : };
1397 :
1398 80 : class MOZ_RAII TypeOfIRGenerator : public IRGenerator
1399 : {
1400 : HandleValue val_;
1401 :
1402 : bool tryAttachPrimitive(ValOperandId valId);
1403 : bool tryAttachObject(ValOperandId valId);
1404 :
1405 : public:
1406 : TypeOfIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode, HandleValue value);
1407 :
1408 : bool tryAttachStub();
1409 : };
1410 :
1411 3981 : class MOZ_RAII CallIRGenerator : public IRGenerator
1412 : {
1413 : public:
1414 : enum class OptStrategy {
1415 : None = 0,
1416 : StringSplit
1417 : };
1418 :
1419 : private:
1420 : uint32_t argc_;
1421 : HandleValue callee_;
1422 : HandleValue thisval_;
1423 : HandleValueArray args_;
1424 :
1425 : mozilla::Maybe<OptStrategy> cachedStrategy_;
1426 :
1427 : OptStrategy canOptimize();
1428 : OptStrategy canOptimizeStringSplit(HandleFunction calleeFunc);
1429 : bool tryAttachStringSplit();
1430 :
1431 : public:
1432 : CallIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
1433 : uint32_t argc, HandleValue callee, HandleValue thisval,
1434 : HandleValueArray args);
1435 :
1436 : OptStrategy getOptStrategy(bool* optimizeAfterCall = nullptr);
1437 : bool tryAttachStub();
1438 : };
1439 :
1440 998 : class MOZ_RAII CompareIRGenerator : public IRGenerator
1441 : {
1442 : JSOp op_;
1443 : HandleValue lhsVal_;
1444 : HandleValue rhsVal_;
1445 :
1446 : bool tryAttachString(ValOperandId lhsId, ValOperandId rhsId);
1447 : bool tryAttachObject(ValOperandId lhsId, ValOperandId rhsId);
1448 : bool tryAttachSymbol(ValOperandId lhsId, ValOperandId rhsId);
1449 :
1450 : void trackAttached(const char* name);
1451 : void trackNotAttached();
1452 :
1453 : public:
1454 : CompareIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
1455 : JSOp op, HandleValue lhsVal, HandleValue rhsVal);
1456 :
1457 : bool tryAttachStub();
1458 : };
1459 :
1460 : } // namespace jit
1461 : } // namespace js
1462 :
1463 : #endif /* jit_CacheIR_h */
|