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/. */
7 #include "jit/WarpCacheIRTranspiler.h"
9 #include "mozilla/Casting.h"
10 #include "mozilla/Maybe.h"
14 #include "jit/AtomicOp.h"
15 #include "jit/CacheIR.h"
16 #include "jit/CacheIRCompiler.h"
17 #include "jit/CacheIROpsGenerated.h"
18 #include "jit/CacheIRReader.h"
21 #include "jit/MIRGenerator.h"
22 #include "jit/MIRGraph.h"
23 #include "jit/WarpBuilder.h"
24 #include "jit/WarpBuilderShared.h"
25 #include "jit/WarpSnapshot.h"
26 #include "js/ScalarType.h" // js::Scalar::Type
27 #include "vm/BytecodeLocation.h"
28 #include "wasm/WasmCode.h"
30 #include "gc/ObjectKind-inl.h"
31 #include "vm/NativeObject-inl.h"
32 #include "wasm/WasmInstance-inl.h"
35 using namespace js::jit
;
37 // The CacheIR transpiler generates MIR from Baseline CacheIR.
38 class MOZ_RAII WarpCacheIRTranspiler
: public WarpBuilderShared
{
39 WarpBuilder
* builder_
;
40 BytecodeLocation loc_
;
41 const CacheIRStubInfo
* stubInfo_
;
42 const uint8_t* stubData_
;
44 // Vector mapping OperandId to corresponding MDefinition.
45 using MDefinitionStackVector
= Vector
<MDefinition
*, 8, SystemAllocPolicy
>;
46 MDefinitionStackVector operands_
;
50 // Array mapping call arguments to OperandId.
51 using ArgumentKindArray
=
52 mozilla::EnumeratedArray
<ArgumentKind
, OperandId
,
53 size_t(ArgumentKind::NumKinds
)>;
54 ArgumentKindArray argumentOperandIds_
;
56 void setArgumentId(ArgumentKind kind
, OperandId id
) {
57 MOZ_ASSERT(kind
!= ArgumentKind::Callee
);
58 MOZ_ASSERT(!argumentOperandIds_
[kind
].valid());
59 argumentOperandIds_
[kind
] = id
;
62 void updateArgumentsFromOperands();
65 // Used to assert that there is only one effectful instruction
66 // per stub. And that this instruction has a resume point.
67 MInstruction
* effectful_
= nullptr;
68 bool pushedResult_
= false;
71 inline void addUnchecked(MInstruction
* ins
) {
74 // If we have not set a more specific bailout kind, mark this instruction
75 // as transpiled CacheIR. If one of these instructions bails out, we
76 // expect to hit the baseline fallback stub and invalidate the Warp script
78 if (ins
->bailoutKind() == BailoutKind::Unknown
) {
79 ins
->setBailoutKind(BailoutKind::TranspiledCacheIR
);
83 inline void add(MInstruction
* ins
) {
84 MOZ_ASSERT(!ins
->isEffectful());
88 inline void addEffectful(MInstruction
* ins
) {
89 MOZ_ASSERT(ins
->isEffectful());
90 MOZ_ASSERT(!effectful_
, "Can only have one effectful instruction");
97 // Bypasses all checks in addEffectful. Only used for testing functions.
98 inline void addEffectfulUnsafe(MInstruction
* ins
) {
99 MOZ_ASSERT(ins
->isEffectful());
103 [[nodiscard
]] bool resumeAfterUnchecked(MInstruction
* ins
) {
104 return WarpBuilderShared::resumeAfter(ins
, loc_
);
106 [[nodiscard
]] bool resumeAfter(MInstruction
* ins
) {
107 MOZ_ASSERT(effectful_
== ins
);
108 return resumeAfterUnchecked(ins
);
111 // CacheIR instructions writing to the IC's result register (the *Result
112 // instructions) must call this to push the result onto the virtual stack.
113 void pushResult(MDefinition
* result
) {
114 MOZ_ASSERT(!pushedResult_
, "Can't have more than one result");
115 current
->push(result
);
117 pushedResult_
= true;
121 MDefinition
* getOperand(OperandId id
) const { return operands_
[id
.id()]; }
123 void setOperand(OperandId id
, MDefinition
* def
) { operands_
[id
.id()] = def
; }
125 [[nodiscard
]] bool defineOperand(OperandId id
, MDefinition
* def
) {
126 MOZ_ASSERT(id
.id() == operands_
.length());
127 return operands_
.append(def
);
130 uintptr_t readStubWord(uint32_t offset
) {
131 return stubInfo_
->getStubRawWord(stubData_
, offset
);
134 Shape
* shapeStubField(uint32_t offset
) {
135 return reinterpret_cast<Shape
*>(readStubWord(offset
));
137 GetterSetter
* getterSetterStubField(uint32_t offset
) {
138 return reinterpret_cast<GetterSetter
*>(readStubWord(offset
));
140 const JSClass
* classStubField(uint32_t offset
) {
141 return reinterpret_cast<const JSClass
*>(readStubWord(offset
));
143 JSString
* stringStubField(uint32_t offset
) {
144 return reinterpret_cast<JSString
*>(readStubWord(offset
));
146 JS::Symbol
* symbolStubField(uint32_t offset
) {
147 return reinterpret_cast<JS::Symbol
*>(readStubWord(offset
));
149 BaseScript
* baseScriptStubField(uint32_t offset
) {
150 return reinterpret_cast<BaseScript
*>(readStubWord(offset
));
152 const JSJitInfo
* jitInfoStubField(uint32_t offset
) {
153 return reinterpret_cast<const JSJitInfo
*>(readStubWord(offset
));
155 JSNative
jsnativeStubField(uint32_t offset
) {
156 return reinterpret_cast<JSNative
>(readStubWord(offset
));
158 JS::ExpandoAndGeneration
* expandoAndGenerationField(uint32_t offset
) {
159 return reinterpret_cast<JS::ExpandoAndGeneration
*>(readStubWord(offset
));
161 const wasm::FuncExport
* wasmFuncExportField(uint32_t offset
) {
162 return reinterpret_cast<const wasm::FuncExport
*>(readStubWord(offset
));
164 NativeIteratorListHead
* nativeIteratorListHeadStubField(uint32_t offset
) {
165 return reinterpret_cast<NativeIteratorListHead
*>(readStubWord(offset
));
167 size_t* fuseStubField(uint32_t offset
) {
168 return reinterpret_cast<size_t*>(readStubWord(offset
));
170 gc::Heap
allocSiteInitialHeapField(uint32_t offset
) {
171 uintptr_t word
= readStubWord(offset
);
172 MOZ_ASSERT(word
== uintptr_t(gc::Heap::Default
) ||
173 word
== uintptr_t(gc::Heap::Tenured
));
174 return gc::Heap(word
);
176 const void* rawPointerField(uint32_t offset
) {
177 return reinterpret_cast<const void*>(readStubWord(offset
));
179 jsid
idStubField(uint32_t offset
) {
180 return jsid::fromRawBits(readStubWord(offset
));
182 int32_t int32StubField(uint32_t offset
) {
183 return static_cast<int32_t>(readStubWord(offset
));
185 uint32_t uint32StubField(uint32_t offset
) {
186 return static_cast<uint32_t>(readStubWord(offset
));
188 uint64_t uint64StubField(uint32_t offset
) {
189 return static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
191 Value
valueStubField(uint32_t offset
) {
193 static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
194 Value val
= Value::fromRawBits(raw
);
195 MOZ_ASSERT_IF(val
.isGCThing(), val
.toGCThing()->isTenured());
198 double doubleStubField(uint32_t offset
) {
200 static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
201 return mozilla::BitwiseCast
<double>(raw
);
204 // This must only be called when the caller knows the object is tenured and
205 // not a nursery index.
206 JSObject
* tenuredObjectStubField(uint32_t offset
) {
207 WarpObjectField field
= WarpObjectField::fromData(readStubWord(offset
));
208 return field
.toObject();
211 // Returns either MConstant or MNurseryIndex. See WarpObjectField.
212 MInstruction
* objectStubField(uint32_t offset
);
214 const JSClass
* classForGuardClassKind(GuardClassKind kind
);
216 [[nodiscard
]] bool emitGuardTo(ValOperandId inputId
, MIRType type
);
218 [[nodiscard
]] bool emitToString(OperandId inputId
, StringOperandId resultId
);
220 template <typename T
>
221 [[nodiscard
]] bool emitDoubleBinaryArithResult(NumberOperandId lhsId
,
222 NumberOperandId rhsId
);
224 template <typename T
>
225 [[nodiscard
]] bool emitInt32BinaryArithResult(Int32OperandId lhsId
,
226 Int32OperandId rhsId
);
228 template <typename T
>
229 [[nodiscard
]] bool emitBigIntBinaryArithResult(BigIntOperandId lhsId
,
230 BigIntOperandId rhsId
);
232 template <typename T
>
233 [[nodiscard
]] bool emitBigIntBinaryArithEffectfulResult(
234 BigIntOperandId lhsId
, BigIntOperandId rhsId
);
236 template <typename T
>
237 [[nodiscard
]] bool emitBigIntUnaryArithResult(BigIntOperandId inputId
);
239 [[nodiscard
]] bool emitCompareResult(JSOp op
, OperandId lhsId
,
241 MCompare::CompareType compareType
);
243 [[nodiscard
]] bool emitTruthyResult(OperandId inputId
);
245 [[nodiscard
]] bool emitNewIteratorResult(MNewIterator::Type type
,
246 uint32_t templateObjectOffset
);
248 MInstruction
* addBoundsCheck(MDefinition
* index
, MDefinition
* length
);
250 [[nodiscard
]] MInstruction
* convertToBoolean(MDefinition
* input
);
252 bool emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind kind
,
253 ObjOperandId objId
, uint32_t offsetOffset
,
254 ValOperandId rhsId
, uint32_t newShapeOffset
);
256 MInstruction
* emitTypedArrayLength(ArrayBufferViewKind viewKind
,
259 MInstruction
* emitDataViewLength(ArrayBufferViewKind viewKind
,
262 void addDataViewData(ArrayBufferViewKind viewKind
, MDefinition
* obj
,
263 Scalar::Type type
, MDefinition
** offset
,
264 MInstruction
** elements
);
266 [[nodiscard
]] bool emitAtomicsBinaryOp(
267 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
268 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
,
271 [[nodiscard
]] bool emitLoadArgumentSlot(ValOperandId resultId
,
274 // Calls are either Native (native function without a JitEntry),
275 // a DOM Native (native function with a JitInfo OpType::Method),
276 // or Scripted (scripted function or native function with a JitEntry).
277 enum class CallKind
{ Native
, DOM
, Scripted
};
279 [[nodiscard
]] bool updateCallInfo(MDefinition
* callee
, CallFlags flags
);
281 [[nodiscard
]] bool emitCallFunction(ObjOperandId calleeId
,
282 Int32OperandId argcId
,
283 mozilla::Maybe
<ObjOperandId
> thisObjId
,
284 CallFlags flags
, CallKind kind
);
285 [[nodiscard
]] bool emitFunApplyArgsObj(WrappedFunction
* wrappedTarget
,
288 MDefinition
* convertWasmArg(MDefinition
* arg
, wasm::ValType::Kind kind
);
290 WrappedFunction
* maybeWrappedFunction(MDefinition
* callee
, CallKind kind
,
291 uint16_t nargs
, FunctionFlags flags
);
292 WrappedFunction
* maybeCallTarget(MDefinition
* callee
, CallKind kind
);
294 bool maybeCreateThis(MDefinition
* callee
, CallFlags flags
, CallKind kind
);
296 [[nodiscard
]] bool emitCallGetterResult(CallKind kind
,
297 ValOperandId receiverId
,
298 uint32_t getterOffset
, bool sameRealm
,
299 uint32_t nargsAndFlagsOffset
);
300 [[nodiscard
]] bool emitCallSetter(CallKind kind
, ObjOperandId receiverId
,
301 uint32_t setterOffset
, ValOperandId rhsId
,
303 uint32_t nargsAndFlagsOffset
);
305 #ifndef JS_CODEGEN_X86
306 [[nodiscard
]] bool emitCallScriptedProxyGetShared(
307 MDefinition
* target
, MDefinition
* receiver
, MDefinition
* handler
,
308 MDefinition
* id
, MDefinition
* trapDef
, WrappedFunction
* trap
);
311 CACHE_IR_TRANSPILER_GENERATED
314 WarpCacheIRTranspiler(WarpBuilder
* builder
, BytecodeLocation loc
,
315 CallInfo
* callInfo
, const WarpCacheIR
* cacheIRSnapshot
)
316 : WarpBuilderShared(builder
->snapshot(), builder
->mirGen(),
317 builder
->currentBlock()),
320 stubInfo_(cacheIRSnapshot
->stubInfo()),
321 stubData_(cacheIRSnapshot
->stubData()),
322 callInfo_(callInfo
) {}
324 [[nodiscard
]] bool transpile(std::initializer_list
<MDefinition
*> inputs
);
327 bool WarpCacheIRTranspiler::transpile(
328 std::initializer_list
<MDefinition
*> inputs
) {
329 if (!operands_
.append(inputs
.begin(), inputs
.end())) {
333 CacheIRReader
reader(stubInfo_
);
335 CacheOp op
= reader
.readOp();
337 #define DEFINE_OP(op, ...) \
339 if (!emit##op(reader)) { \
343 CACHE_IR_TRANSPILER_OPS(DEFINE_OP
)
347 fprintf(stderr
, "Unsupported op: %s\n", CacheIROpNames
[size_t(op
)]);
348 MOZ_CRASH("Unsupported op");
350 } while (reader
.more());
352 // Effectful instructions should have a resume point. MIonToWasmCall is an
353 // exception: we can attach the resume point to the MInt64ToBigInt instruction
354 // instead. Other exceptions are MResizableTypedArrayLength and
355 // MResizableDataViewByteLength, and MGrowableSharedArrayBufferByteLength,
356 // which add the resume point to MPostIntPtrConversion.
357 MOZ_ASSERT_IF(effectful_
,
358 effectful_
->resumePoint() || effectful_
->isIonToWasmCall() ||
359 effectful_
->isResizableTypedArrayLength() ||
360 effectful_
->isResizableDataViewByteLength() ||
361 effectful_
->isGrowableSharedArrayBufferByteLength());
365 MInstruction
* WarpCacheIRTranspiler::objectStubField(uint32_t offset
) {
366 WarpObjectField field
= WarpObjectField::fromData(readStubWord(offset
));
368 if (field
.isNurseryIndex()) {
369 auto* ins
= MNurseryObject::New(alloc(), field
.toNurseryIndex());
374 auto* ins
= MConstant::NewObject(alloc(), field
.toObject());
379 bool WarpCacheIRTranspiler::emitGuardClass(ObjOperandId objId
,
380 GuardClassKind kind
) {
381 MDefinition
* def
= getOperand(objId
);
384 if (kind
== GuardClassKind::JSFunction
) {
385 ins
= MGuardToFunction::New(alloc(), def
);
387 const JSClass
* classp
= classForGuardClassKind(kind
);
388 ins
= MGuardToClass::New(alloc(), def
, classp
);
393 setOperand(objId
, ins
);
397 bool WarpCacheIRTranspiler::emitGuardEitherClass(ObjOperandId objId
,
398 GuardClassKind kind1
,
399 GuardClassKind kind2
) {
400 MDefinition
* def
= getOperand(objId
);
402 // We don't yet need this case, so it's unsupported for now.
403 MOZ_ASSERT(kind1
!= GuardClassKind::JSFunction
&&
404 kind2
!= GuardClassKind::JSFunction
);
406 const JSClass
* classp1
= classForGuardClassKind(kind1
);
407 const JSClass
* classp2
= classForGuardClassKind(kind2
);
408 auto* ins
= MGuardToEitherClass::New(alloc(), def
, classp1
, classp2
);
412 setOperand(objId
, ins
);
416 const JSClass
* WarpCacheIRTranspiler::classForGuardClassKind(
417 GuardClassKind kind
) {
419 case GuardClassKind::Array
:
420 case GuardClassKind::PlainObject
:
421 case GuardClassKind::FixedLengthArrayBuffer
:
422 case GuardClassKind::ResizableArrayBuffer
:
423 case GuardClassKind::FixedLengthSharedArrayBuffer
:
424 case GuardClassKind::GrowableSharedArrayBuffer
:
425 case GuardClassKind::FixedLengthDataView
:
426 case GuardClassKind::ResizableDataView
:
427 case GuardClassKind::MappedArguments
:
428 case GuardClassKind::UnmappedArguments
:
429 case GuardClassKind::Set
:
430 case GuardClassKind::Map
:
431 case GuardClassKind::BoundFunction
:
432 return ClassFor(kind
);
433 case GuardClassKind::WindowProxy
:
434 return mirGen().runtime
->maybeWindowProxyClass();
435 case GuardClassKind::JSFunction
:
438 MOZ_CRASH("unexpected kind");
441 bool WarpCacheIRTranspiler::emitGuardAnyClass(ObjOperandId objId
,
442 uint32_t claspOffset
) {
443 MDefinition
* def
= getOperand(objId
);
444 const JSClass
* classp
= classStubField(claspOffset
);
446 auto* ins
= MGuardToClass::New(alloc(), def
, classp
);
449 setOperand(objId
, ins
);
453 bool WarpCacheIRTranspiler::emitGuardShape(ObjOperandId objId
,
454 uint32_t shapeOffset
) {
455 MDefinition
* def
= getOperand(objId
);
457 // No read barrier is required because snapshot data is not weak and is traced
458 // as part of IonCompileTask.
459 Shape
* shape
= shapeStubField(shapeOffset
);
461 auto* ins
= MGuardShape::New(alloc(), def
, shape
);
464 setOperand(objId
, ins
);
468 bool WarpCacheIRTranspiler::emitGuardFuse(RealmFuses::FuseIndex fuseIndex
) {
469 auto* ins
= MGuardFuse::New(alloc(), fuseIndex
);
475 bool WarpCacheIRTranspiler::emitGuardMultipleShapes(ObjOperandId objId
,
476 uint32_t shapesOffset
) {
477 MDefinition
* def
= getOperand(objId
);
478 MInstruction
* shapeList
= objectStubField(shapesOffset
);
480 auto* ins
= MGuardMultipleShapes::New(alloc(), def
, shapeList
);
481 if (builder_
->info().inlineScriptTree()->hasSharedICScript()) {
482 ins
->setBailoutKind(BailoutKind::MonomorphicInlinedStubFolding
);
486 setOperand(objId
, ins
);
490 bool WarpCacheIRTranspiler::emitGuardNullProto(ObjOperandId objId
) {
491 MDefinition
* def
= getOperand(objId
);
493 auto* ins
= MGuardNullProto::New(alloc(), def
);
496 setOperand(objId
, ins
);
500 bool WarpCacheIRTranspiler::emitGuardIsNativeObject(ObjOperandId objId
) {
501 MDefinition
* obj
= getOperand(objId
);
503 auto* ins
= MGuardIsNativeObject::New(alloc(), obj
);
506 setOperand(objId
, ins
);
510 bool WarpCacheIRTranspiler::emitGuardIsProxy(ObjOperandId objId
) {
511 MDefinition
* obj
= getOperand(objId
);
513 auto* ins
= MGuardIsProxy::New(alloc(), obj
);
516 setOperand(objId
, ins
);
520 bool WarpCacheIRTranspiler::emitGuardIsNotProxy(ObjOperandId objId
) {
521 MDefinition
* obj
= getOperand(objId
);
523 auto* ins
= MGuardIsNotProxy::New(alloc(), obj
);
526 setOperand(objId
, ins
);
530 bool WarpCacheIRTranspiler::emitGuardIsNotDOMProxy(ObjOperandId objId
) {
531 MDefinition
* obj
= getOperand(objId
);
533 auto* ins
= MGuardIsNotDOMProxy::New(alloc(), obj
);
536 setOperand(objId
, ins
);
540 bool WarpCacheIRTranspiler::emitGuardHasGetterSetter(
541 ObjOperandId objId
, uint32_t idOffset
, uint32_t getterSetterOffset
) {
542 MDefinition
* obj
= getOperand(objId
);
543 jsid id
= idStubField(idOffset
);
544 GetterSetter
* gs
= getterSetterStubField(getterSetterOffset
);
546 auto* ins
= MGuardHasGetterSetter::New(alloc(), obj
, id
, gs
);
549 setOperand(objId
, ins
);
553 bool WarpCacheIRTranspiler::emitProxyGetResult(ObjOperandId objId
,
555 MDefinition
* obj
= getOperand(objId
);
556 jsid id
= idStubField(idOffset
);
558 auto* ins
= MProxyGet::New(alloc(), obj
, id
);
562 return resumeAfter(ins
);
565 bool WarpCacheIRTranspiler::emitProxyGetByValueResult(ObjOperandId objId
,
567 MDefinition
* obj
= getOperand(objId
);
568 MDefinition
* id
= getOperand(idId
);
570 auto* ins
= MProxyGetByValue::New(alloc(), obj
, id
);
574 return resumeAfter(ins
);
577 bool WarpCacheIRTranspiler::emitProxyHasPropResult(ObjOperandId objId
,
580 MDefinition
* obj
= getOperand(objId
);
581 MDefinition
* id
= getOperand(idId
);
583 auto* ins
= MProxyHasProp::New(alloc(), obj
, id
, hasOwn
);
587 return resumeAfter(ins
);
590 bool WarpCacheIRTranspiler::emitProxySet(ObjOperandId objId
, uint32_t idOffset
,
591 ValOperandId rhsId
, bool strict
) {
592 MDefinition
* obj
= getOperand(objId
);
593 jsid id
= idStubField(idOffset
);
594 MDefinition
* rhs
= getOperand(rhsId
);
596 auto* ins
= MProxySet::New(alloc(), obj
, rhs
, id
, strict
);
599 return resumeAfter(ins
);
602 bool WarpCacheIRTranspiler::emitProxySetByValue(ObjOperandId objId
,
606 MDefinition
* obj
= getOperand(objId
);
607 MDefinition
* id
= getOperand(idId
);
608 MDefinition
* rhs
= getOperand(rhsId
);
610 auto* ins
= MProxySetByValue::New(alloc(), obj
, id
, rhs
, strict
);
613 return resumeAfter(ins
);
616 bool WarpCacheIRTranspiler::emitCallSetArrayLength(ObjOperandId objId
,
618 ValOperandId rhsId
) {
619 MDefinition
* obj
= getOperand(objId
);
620 MDefinition
* rhs
= getOperand(rhsId
);
622 auto* ins
= MCallSetArrayLength::New(alloc(), obj
, rhs
, strict
);
625 return resumeAfter(ins
);
628 bool WarpCacheIRTranspiler::emitCallDOMGetterResult(ObjOperandId objId
,
629 uint32_t jitInfoOffset
) {
630 MDefinition
* obj
= getOperand(objId
);
631 const JSJitInfo
* jitInfo
= jitInfoStubField(jitInfoOffset
);
634 if (jitInfo
->isAlwaysInSlot
) {
635 ins
= MGetDOMMember::New(alloc(), jitInfo
, obj
, nullptr, nullptr);
637 // TODO(post-Warp): realms, guard operands (movable?).
638 ins
= MGetDOMProperty::New(alloc(), jitInfo
, DOMObjectKind::Native
,
639 (JS::Realm
*)mirGen().realm
->realmPtr(), obj
,
647 if (ins
->isEffectful()) {
650 return resumeAfter(ins
);
658 bool WarpCacheIRTranspiler::emitCallDOMSetter(ObjOperandId objId
,
659 uint32_t jitInfoOffset
,
660 ValOperandId rhsId
) {
661 MDefinition
* obj
= getOperand(objId
);
662 const JSJitInfo
* jitInfo
= jitInfoStubField(jitInfoOffset
);
663 MDefinition
* value
= getOperand(rhsId
);
665 MOZ_ASSERT(jitInfo
->type() == JSJitInfo::Setter
);
667 MSetDOMProperty::New(alloc(), jitInfo
->setter
, DOMObjectKind::Native
,
668 (JS::Realm
*)mirGen().realm
->realmPtr(), obj
, value
);
670 return resumeAfter(set
);
673 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValue(ObjOperandId objId
,
674 ValOperandId resultId
) {
675 MDefinition
* proxy
= getOperand(objId
);
677 auto* ins
= MLoadDOMExpandoValue::New(alloc(), proxy
);
680 return defineOperand(resultId
, ins
);
683 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueGuardGeneration(
684 ObjOperandId objId
, uint32_t expandoAndGenerationOffset
,
685 uint32_t generationOffset
, ValOperandId resultId
) {
686 MDefinition
* proxy
= getOperand(objId
);
687 JS::ExpandoAndGeneration
* expandoAndGeneration
=
688 expandoAndGenerationField(expandoAndGenerationOffset
);
689 uint64_t generation
= uint64StubField(generationOffset
);
691 auto* ins
= MLoadDOMExpandoValueGuardGeneration::New(
692 alloc(), proxy
, expandoAndGeneration
, generation
);
695 return defineOperand(resultId
, ins
);
698 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueIgnoreGeneration(
699 ObjOperandId objId
, ValOperandId resultId
) {
700 MDefinition
* proxy
= getOperand(objId
);
702 auto* ins
= MLoadDOMExpandoValueIgnoreGeneration::New(alloc(), proxy
);
705 return defineOperand(resultId
, ins
);
708 bool WarpCacheIRTranspiler::emitGuardDOMExpandoMissingOrGuardShape(
709 ValOperandId expandoId
, uint32_t shapeOffset
) {
710 MDefinition
* expando
= getOperand(expandoId
);
711 Shape
* shape
= shapeStubField(shapeOffset
);
713 auto* ins
= MGuardDOMExpandoMissingOrGuardShape::New(alloc(), expando
, shape
);
716 setOperand(expandoId
, ins
);
720 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotResult(ObjOperandId objId
,
721 uint32_t nameOffset
) {
722 MDefinition
* obj
= getOperand(objId
);
723 PropertyName
* name
= stringStubField(nameOffset
)->asAtom().asPropertyName();
725 auto* ins
= MMegamorphicLoadSlot::New(alloc(), obj
, NameToId(name
));
732 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValueResult(
733 ObjOperandId objId
, ValOperandId idId
) {
734 MDefinition
* obj
= getOperand(objId
);
735 MDefinition
* id
= getOperand(idId
);
737 auto* ins
= MMegamorphicLoadSlotByValue::New(alloc(), obj
, id
);
744 bool WarpCacheIRTranspiler::emitMegamorphicStoreSlot(ObjOperandId objId
,
748 MDefinition
* obj
= getOperand(objId
);
749 jsid id
= idStubField(idOffset
);
750 MDefinition
* rhs
= getOperand(rhsId
);
752 auto* ins
= MMegamorphicStoreSlot::New(alloc(), obj
, rhs
, id
, strict
);
755 return resumeAfter(ins
);
758 bool WarpCacheIRTranspiler::emitMegamorphicHasPropResult(ObjOperandId objId
,
761 MDefinition
* obj
= getOperand(objId
);
762 MDefinition
* id
= getOperand(idId
);
764 auto* ins
= MMegamorphicHasProp::New(alloc(), obj
, id
, hasOwn
);
771 bool WarpCacheIRTranspiler::emitSmallObjectVariableKeyHasOwnResult(
772 StringOperandId idId
, uint32_t propNamesOffset
, uint32_t shapeOffset
) {
773 MDefinition
* id
= getOperand(idId
);
774 SharedShape
* shape
= &shapeStubField(shapeOffset
)->asShared();
776 auto* ins
= MSmallObjectVariableKeyHasProp::New(alloc(), id
, shape
);
783 bool WarpCacheIRTranspiler::emitMegamorphicSetElement(ObjOperandId objId
,
787 MDefinition
* obj
= getOperand(objId
);
788 MDefinition
* id
= getOperand(idId
);
789 MDefinition
* rhs
= getOperand(rhsId
);
791 auto* ins
= MMegamorphicSetElement::New(alloc(), obj
, id
, rhs
, strict
);
794 return resumeAfter(ins
);
797 bool WarpCacheIRTranspiler::emitObjectToIteratorResult(
798 ObjOperandId objId
, uint32_t enumeratorsAddrOffset
) {
799 MDefinition
* obj
= getOperand(objId
);
800 NativeIteratorListHead
* enumeratorsAddr
=
801 nativeIteratorListHeadStubField(enumeratorsAddrOffset
);
803 auto* ins
= MObjectToIterator::New(alloc(), obj
, enumeratorsAddr
);
806 if (!resumeAfter(ins
)) {
813 bool WarpCacheIRTranspiler::emitValueToIteratorResult(ValOperandId valId
) {
814 MDefinition
* val
= getOperand(valId
);
816 auto* ins
= MValueToIterator::New(alloc(), val
);
820 return resumeAfter(ins
);
823 bool WarpCacheIRTranspiler::emitGuardIsNotArrayBufferMaybeShared(
824 ObjOperandId objId
) {
825 MDefinition
* obj
= getOperand(objId
);
827 auto* ins
= MGuardIsNotArrayBufferMaybeShared::New(alloc(), obj
);
830 setOperand(objId
, ins
);
834 bool WarpCacheIRTranspiler::emitGuardIsTypedArray(ObjOperandId objId
) {
835 MDefinition
* obj
= getOperand(objId
);
837 auto* ins
= MGuardIsTypedArray::New(alloc(), obj
);
840 setOperand(objId
, ins
);
844 bool WarpCacheIRTranspiler::emitGuardIsFixedLengthTypedArray(
845 ObjOperandId objId
) {
846 MDefinition
* obj
= getOperand(objId
);
848 auto* ins
= MGuardIsFixedLengthTypedArray::New(alloc(), obj
);
851 setOperand(objId
, ins
);
855 bool WarpCacheIRTranspiler::emitGuardIsResizableTypedArray(ObjOperandId objId
) {
856 MDefinition
* obj
= getOperand(objId
);
858 auto* ins
= MGuardIsResizableTypedArray::New(alloc(), obj
);
861 setOperand(objId
, ins
);
865 bool WarpCacheIRTranspiler::emitGuardHasProxyHandler(ObjOperandId objId
,
866 uint32_t handlerOffset
) {
867 MDefinition
* obj
= getOperand(objId
);
868 const void* handler
= rawPointerField(handlerOffset
);
870 auto* ins
= MGuardHasProxyHandler::New(alloc(), obj
, handler
);
873 setOperand(objId
, ins
);
877 bool WarpCacheIRTranspiler::emitGuardProto(ObjOperandId objId
,
878 uint32_t protoOffset
) {
879 MDefinition
* def
= getOperand(objId
);
880 MDefinition
* proto
= objectStubField(protoOffset
);
882 auto* ins
= MGuardProto::New(alloc(), def
, proto
);
885 setOperand(objId
, ins
);
889 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsSpecificObject(
890 ObjOperandId objId
, ObjOperandId expectedId
, uint32_t slotOffset
) {
891 size_t slotIndex
= int32StubField(slotOffset
);
892 MDefinition
* obj
= getOperand(objId
);
893 MDefinition
* expected
= getOperand(expectedId
);
895 auto* slots
= MSlots::New(alloc(), obj
);
898 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
901 auto* unbox
= MUnbox::New(alloc(), load
, MIRType::Object
, MUnbox::Fallible
);
904 auto* guard
= MGuardObjectIdentity::New(alloc(), unbox
, expected
,
905 /* bailOnEquality = */ false);
910 bool WarpCacheIRTranspiler::emitLoadDynamicSlot(ValOperandId resultId
,
912 uint32_t slotOffset
) {
913 size_t slotIndex
= int32StubField(slotOffset
);
914 MDefinition
* obj
= getOperand(objId
);
916 auto* slots
= MSlots::New(alloc(), obj
);
919 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
922 return defineOperand(resultId
, load
);
925 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsNotObject(
926 ObjOperandId objId
, uint32_t slotOffset
) {
927 size_t slotIndex
= int32StubField(slotOffset
);
928 MDefinition
* obj
= getOperand(objId
);
930 auto* slots
= MSlots::New(alloc(), obj
);
933 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
936 auto* guard
= MGuardIsNotObject::New(alloc(), load
);
941 bool WarpCacheIRTranspiler::emitGuardFixedSlotValue(ObjOperandId objId
,
942 uint32_t offsetOffset
,
943 uint32_t valOffset
) {
944 MDefinition
* obj
= getOperand(objId
);
946 size_t offset
= int32StubField(offsetOffset
);
947 Value val
= valueStubField(valOffset
);
949 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
951 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
954 auto* guard
= MGuardValue::New(alloc(), load
, val
);
959 bool WarpCacheIRTranspiler::emitGuardDynamicSlotValue(ObjOperandId objId
,
960 uint32_t offsetOffset
,
961 uint32_t valOffset
) {
962 MDefinition
* obj
= getOperand(objId
);
964 size_t offset
= int32StubField(offsetOffset
);
965 Value val
= valueStubField(valOffset
);
967 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
969 auto* slots
= MSlots::New(alloc(), obj
);
972 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
975 auto* guard
= MGuardValue::New(alloc(), load
, val
);
980 bool WarpCacheIRTranspiler::emitLoadScriptedProxyHandler(ObjOperandId resultId
,
981 ObjOperandId objId
) {
982 MDefinition
* obj
= getOperand(objId
);
984 auto* load
= MLoadScriptedProxyHandler::New(alloc(), obj
);
987 return defineOperand(resultId
, load
);
990 bool WarpCacheIRTranspiler::emitIdToStringOrSymbol(ValOperandId resultId
,
992 MDefinition
* id
= getOperand(idId
);
994 auto* ins
= MIdToStringOrSymbol::New(alloc(), id
);
997 return defineOperand(resultId
, ins
);
1000 bool WarpCacheIRTranspiler::emitGuardSpecificAtom(StringOperandId strId
,
1001 uint32_t expectedOffset
) {
1002 MDefinition
* str
= getOperand(strId
);
1003 JSString
* expected
= stringStubField(expectedOffset
);
1005 auto* ins
= MGuardSpecificAtom::New(alloc(), str
, &expected
->asAtom());
1008 setOperand(strId
, ins
);
1012 bool WarpCacheIRTranspiler::emitGuardSpecificSymbol(SymbolOperandId symId
,
1013 uint32_t expectedOffset
) {
1014 MDefinition
* symbol
= getOperand(symId
);
1015 JS::Symbol
* expected
= symbolStubField(expectedOffset
);
1017 auto* ins
= MGuardSpecificSymbol::New(alloc(), symbol
, expected
);
1020 setOperand(symId
, ins
);
1024 bool WarpCacheIRTranspiler::emitGuardSpecificInt32(Int32OperandId numId
,
1026 MDefinition
* num
= getOperand(numId
);
1028 auto* ins
= MGuardSpecificInt32::New(alloc(), num
, expected
);
1031 setOperand(numId
, ins
);
1035 bool WarpCacheIRTranspiler::emitGuardSpecificObject(ObjOperandId objId
,
1036 uint32_t expectedOffset
) {
1037 MDefinition
* obj
= getOperand(objId
);
1038 MDefinition
* expected
= objectStubField(expectedOffset
);
1040 auto* ins
= MGuardObjectIdentity::New(alloc(), obj
, expected
,
1041 /* bailOnEquality = */ false);
1044 setOperand(objId
, ins
);
1048 bool WarpCacheIRTranspiler::emitGuardSpecificFunction(
1049 ObjOperandId objId
, uint32_t expectedOffset
, uint32_t nargsAndFlagsOffset
) {
1050 MDefinition
* obj
= getOperand(objId
);
1051 MDefinition
* expected
= objectStubField(expectedOffset
);
1052 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
1054 uint16_t nargs
= nargsAndFlags
>> 16;
1055 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
1057 auto* ins
= MGuardSpecificFunction::New(alloc(), obj
, expected
, nargs
, flags
);
1060 setOperand(objId
, ins
);
1064 bool WarpCacheIRTranspiler::emitGuardFunctionScript(
1065 ObjOperandId funId
, uint32_t expectedOffset
, uint32_t nargsAndFlagsOffset
) {
1066 MDefinition
* fun
= getOperand(funId
);
1067 BaseScript
* expected
= baseScriptStubField(expectedOffset
);
1068 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
1070 uint16_t nargs
= nargsAndFlags
>> 16;
1071 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
1073 auto* ins
= MGuardFunctionScript::New(alloc(), fun
, expected
, nargs
, flags
);
1076 setOperand(funId
, ins
);
1080 bool WarpCacheIRTranspiler::emitGuardStringToIndex(StringOperandId strId
,
1081 Int32OperandId resultId
) {
1082 MDefinition
* str
= getOperand(strId
);
1084 auto* ins
= MGuardStringToIndex::New(alloc(), str
);
1087 return defineOperand(resultId
, ins
);
1090 bool WarpCacheIRTranspiler::emitGuardStringToInt32(StringOperandId strId
,
1091 Int32OperandId resultId
) {
1092 MDefinition
* str
= getOperand(strId
);
1094 auto* ins
= MGuardStringToInt32::New(alloc(), str
);
1097 return defineOperand(resultId
, ins
);
1100 bool WarpCacheIRTranspiler::emitGuardStringToNumber(StringOperandId strId
,
1101 NumberOperandId resultId
) {
1102 MDefinition
* str
= getOperand(strId
);
1104 auto* ins
= MGuardStringToDouble::New(alloc(), str
);
1107 return defineOperand(resultId
, ins
);
1110 bool WarpCacheIRTranspiler::emitGuardNoDenseElements(ObjOperandId objId
) {
1111 MDefinition
* obj
= getOperand(objId
);
1113 auto* ins
= MGuardNoDenseElements::New(alloc(), obj
);
1116 setOperand(objId
, ins
);
1120 bool WarpCacheIRTranspiler::emitGuardFunctionHasJitEntry(ObjOperandId funId
,
1121 bool constructing
) {
1122 MDefinition
* fun
= getOperand(funId
);
1123 uint16_t expectedFlags
= FunctionFlags::HasJitEntryFlags(constructing
);
1124 uint16_t unexpectedFlags
= 0;
1127 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1130 setOperand(funId
, ins
);
1134 bool WarpCacheIRTranspiler::emitGuardFunctionHasNoJitEntry(ObjOperandId funId
) {
1135 MDefinition
* fun
= getOperand(funId
);
1136 uint16_t expectedFlags
= 0;
1137 uint16_t unexpectedFlags
=
1138 FunctionFlags::HasJitEntryFlags(/*isConstructing=*/false);
1141 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1144 setOperand(funId
, ins
);
1148 bool WarpCacheIRTranspiler::emitGuardFunctionIsNonBuiltinCtor(
1149 ObjOperandId funId
) {
1150 MDefinition
* fun
= getOperand(funId
);
1152 auto* ins
= MGuardFunctionIsNonBuiltinCtor::New(alloc(), fun
);
1155 setOperand(funId
, ins
);
1159 bool WarpCacheIRTranspiler::emitGuardFunctionIsConstructor(ObjOperandId funId
) {
1160 MDefinition
* fun
= getOperand(funId
);
1161 uint16_t expectedFlags
= FunctionFlags::CONSTRUCTOR
;
1162 uint16_t unexpectedFlags
= 0;
1165 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1168 setOperand(funId
, ins
);
1172 bool WarpCacheIRTranspiler::emitGuardNotClassConstructor(ObjOperandId funId
) {
1173 MDefinition
* fun
= getOperand(funId
);
1176 MGuardFunctionKind::New(alloc(), fun
, FunctionFlags::ClassConstructor
,
1177 /*bailOnEquality=*/true);
1180 setOperand(funId
, ins
);
1184 bool WarpCacheIRTranspiler::emitGuardArrayIsPacked(ObjOperandId arrayId
) {
1185 MDefinition
* array
= getOperand(arrayId
);
1187 auto* ins
= MGuardArrayIsPacked::New(alloc(), array
);
1190 setOperand(arrayId
, ins
);
1194 bool WarpCacheIRTranspiler::emitGuardArgumentsObjectFlags(ObjOperandId objId
,
1196 MDefinition
* obj
= getOperand(objId
);
1198 auto* ins
= MGuardArgumentsObjectFlags::New(alloc(), obj
, flags
);
1201 setOperand(objId
, ins
);
1205 bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId
,
1208 case ValueType::String
:
1209 case ValueType::Symbol
:
1210 case ValueType::BigInt
:
1211 case ValueType::Int32
:
1212 case ValueType::Boolean
:
1213 return emitGuardTo(inputId
, MIRTypeFromValueType(JSValueType(type
)));
1214 case ValueType::Undefined
:
1215 return emitGuardIsUndefined(inputId
);
1216 case ValueType::Null
:
1217 return emitGuardIsNull(inputId
);
1218 case ValueType::Double
:
1219 case ValueType::Magic
:
1220 case ValueType::PrivateGCThing
:
1221 case ValueType::Object
:
1222 #ifdef ENABLE_RECORD_TUPLE
1223 case ValueType::ExtendedPrimitive
:
1228 MOZ_CRASH("unexpected type");
1231 bool WarpCacheIRTranspiler::emitGuardTo(ValOperandId inputId
, MIRType type
) {
1232 MDefinition
* def
= getOperand(inputId
);
1233 if (def
->type() == type
) {
1237 auto* ins
= MUnbox::New(alloc(), def
, type
, MUnbox::Fallible
);
1240 setOperand(inputId
, ins
);
1244 bool WarpCacheIRTranspiler::emitGuardToObject(ValOperandId inputId
) {
1245 return emitGuardTo(inputId
, MIRType::Object
);
1248 bool WarpCacheIRTranspiler::emitGuardToString(ValOperandId inputId
) {
1249 return emitGuardTo(inputId
, MIRType::String
);
1252 bool WarpCacheIRTranspiler::emitGuardToSymbol(ValOperandId inputId
) {
1253 return emitGuardTo(inputId
, MIRType::Symbol
);
1256 bool WarpCacheIRTranspiler::emitGuardToBigInt(ValOperandId inputId
) {
1257 return emitGuardTo(inputId
, MIRType::BigInt
);
1260 bool WarpCacheIRTranspiler::emitGuardToBoolean(ValOperandId inputId
) {
1261 return emitGuardTo(inputId
, MIRType::Boolean
);
1264 bool WarpCacheIRTranspiler::emitGuardToInt32(ValOperandId inputId
) {
1265 return emitGuardTo(inputId
, MIRType::Int32
);
1268 bool WarpCacheIRTranspiler::emitGuardBooleanToInt32(ValOperandId inputId
,
1269 Int32OperandId resultId
) {
1270 if (!emitGuardTo(inputId
, MIRType::Boolean
)) {
1274 MDefinition
* input
= getOperand(inputId
);
1275 MOZ_ASSERT(input
->type() == MIRType::Boolean
);
1277 auto* ins
= MBooleanToInt32::New(alloc(), input
);
1280 return defineOperand(resultId
, ins
);
1283 bool WarpCacheIRTranspiler::emitGuardIsNumber(ValOperandId inputId
) {
1284 // Prefer MToDouble because it gets further optimizations downstream.
1285 MDefinition
* def
= getOperand(inputId
);
1286 if (def
->type() == MIRType::Int32
) {
1287 auto* ins
= MToDouble::New(alloc(), def
);
1290 setOperand(inputId
, ins
);
1294 // MIRType::Double also implies int32 in Ion.
1295 return emitGuardTo(inputId
, MIRType::Double
);
1298 bool WarpCacheIRTranspiler::emitGuardIsNullOrUndefined(ValOperandId inputId
) {
1299 MDefinition
* input
= getOperand(inputId
);
1300 if (input
->type() == MIRType::Null
|| input
->type() == MIRType::Undefined
) {
1304 auto* ins
= MGuardNullOrUndefined::New(alloc(), input
);
1307 setOperand(inputId
, ins
);
1311 bool WarpCacheIRTranspiler::emitGuardIsNull(ValOperandId inputId
) {
1312 MDefinition
* input
= getOperand(inputId
);
1313 if (input
->type() == MIRType::Null
) {
1317 auto* ins
= MGuardValue::New(alloc(), input
, NullValue());
1319 setOperand(inputId
, ins
);
1323 bool WarpCacheIRTranspiler::emitGuardIsUndefined(ValOperandId inputId
) {
1324 MDefinition
* input
= getOperand(inputId
);
1325 if (input
->type() == MIRType::Undefined
) {
1329 auto* ins
= MGuardValue::New(alloc(), input
, UndefinedValue());
1331 setOperand(inputId
, ins
);
1335 bool WarpCacheIRTranspiler::emitGuardIsExtensible(ObjOperandId objId
) {
1336 MDefinition
* obj
= getOperand(objId
);
1338 auto* ins
= MGuardIsExtensible::New(alloc(), obj
);
1340 setOperand(objId
, ins
);
1344 bool WarpCacheIRTranspiler::emitGuardInt32IsNonNegative(
1345 Int32OperandId indexId
) {
1346 MDefinition
* index
= getOperand(indexId
);
1348 auto* ins
= MGuardInt32IsNonNegative::New(alloc(), index
);
1350 setOperand(indexId
, ins
);
1354 bool WarpCacheIRTranspiler::emitGuardIndexIsNotDenseElement(
1355 ObjOperandId objId
, Int32OperandId indexId
) {
1356 MDefinition
* obj
= getOperand(objId
);
1357 MDefinition
* index
= getOperand(indexId
);
1359 auto* ins
= MGuardIndexIsNotDenseElement::New(alloc(), obj
, index
);
1361 setOperand(indexId
, ins
);
1365 bool WarpCacheIRTranspiler::emitGuardIndexIsValidUpdateOrAdd(
1366 ObjOperandId objId
, Int32OperandId indexId
) {
1367 MDefinition
* obj
= getOperand(objId
);
1368 MDefinition
* index
= getOperand(indexId
);
1370 auto* ins
= MGuardIndexIsValidUpdateOrAdd::New(alloc(), obj
, index
);
1372 setOperand(indexId
, ins
);
1376 bool WarpCacheIRTranspiler::emitCallAddOrUpdateSparseElementHelper(
1377 ObjOperandId objId
, Int32OperandId idId
, ValOperandId rhsId
, bool strict
) {
1378 MDefinition
* obj
= getOperand(objId
);
1379 MDefinition
* id
= getOperand(idId
);
1380 MDefinition
* rhs
= getOperand(rhsId
);
1382 auto* ins
= MCallAddOrUpdateSparseElement::New(alloc(), obj
, id
, rhs
, strict
);
1385 return resumeAfter(ins
);
1388 bool WarpCacheIRTranspiler::emitGuardTagNotEqual(ValueTagOperandId lhsId
,
1389 ValueTagOperandId rhsId
) {
1390 MDefinition
* lhs
= getOperand(lhsId
);
1391 MDefinition
* rhs
= getOperand(rhsId
);
1393 auto* ins
= MGuardTagNotEqual::New(alloc(), lhs
, rhs
);
1399 bool WarpCacheIRTranspiler::emitGuardToInt32Index(ValOperandId inputId
,
1400 Int32OperandId resultId
) {
1401 MDefinition
* input
= getOperand(inputId
);
1403 MToNumberInt32::New(alloc(), input
, IntConversionInputKind::NumbersOnly
);
1405 // ToPropertyKey(-0) is "0", so we can silently convert -0 to 0 here.
1406 ins
->setNeedsNegativeZeroCheck(false);
1409 return defineOperand(resultId
, ins
);
1412 bool WarpCacheIRTranspiler::emitTruncateDoubleToUInt32(
1413 NumberOperandId inputId
, Int32OperandId resultId
) {
1414 MDefinition
* input
= getOperand(inputId
);
1415 auto* ins
= MTruncateToInt32::New(alloc(), input
);
1418 return defineOperand(resultId
, ins
);
1421 bool WarpCacheIRTranspiler::emitDoubleToUint8Clamped(NumberOperandId inputId
,
1422 Int32OperandId resultId
) {
1423 MDefinition
* input
= getOperand(inputId
);
1424 auto* ins
= MClampToUint8::New(alloc(), input
);
1427 return defineOperand(resultId
, ins
);
1430 bool WarpCacheIRTranspiler::emitGuardToInt32ModUint32(ValOperandId valId
,
1431 Int32OperandId resultId
) {
1432 MDefinition
* input
= getOperand(valId
);
1433 auto* ins
= MTruncateToInt32::New(alloc(), input
);
1436 return defineOperand(resultId
, ins
);
1439 bool WarpCacheIRTranspiler::emitGuardToUint8Clamped(ValOperandId valId
,
1440 Int32OperandId resultId
) {
1441 MDefinition
* input
= getOperand(valId
);
1442 auto* ins
= MClampToUint8::New(alloc(), input
);
1445 return defineOperand(resultId
, ins
);
1448 bool WarpCacheIRTranspiler::emitToString(OperandId inputId
,
1449 StringOperandId resultId
) {
1450 MDefinition
* input
= getOperand(inputId
);
1452 MToString::New(alloc(), input
, MToString::SideEffectHandling::Bailout
);
1455 return defineOperand(resultId
, ins
);
1458 bool WarpCacheIRTranspiler::emitInt32ToIntPtr(Int32OperandId inputId
,
1459 IntPtrOperandId resultId
) {
1460 MDefinition
* input
= getOperand(inputId
);
1461 auto* ins
= MInt32ToIntPtr::New(alloc(), input
);
1463 return defineOperand(resultId
, ins
);
1466 bool WarpCacheIRTranspiler::emitGuardNumberToIntPtrIndex(
1467 NumberOperandId inputId
, bool supportOOB
, IntPtrOperandId resultId
) {
1468 MDefinition
* input
= getOperand(inputId
);
1469 auto* ins
= MGuardNumberToIntPtrIndex::New(alloc(), input
, supportOOB
);
1471 return defineOperand(resultId
, ins
);
1474 bool WarpCacheIRTranspiler::emitCallInt32ToString(Int32OperandId inputId
,
1475 StringOperandId resultId
) {
1476 return emitToString(inputId
, resultId
);
1479 bool WarpCacheIRTranspiler::emitCallNumberToString(NumberOperandId inputId
,
1480 StringOperandId resultId
) {
1481 return emitToString(inputId
, resultId
);
1484 bool WarpCacheIRTranspiler::emitInt32ToStringWithBaseResult(
1485 Int32OperandId inputId
, Int32OperandId baseId
) {
1486 MDefinition
* input
= getOperand(inputId
);
1487 MDefinition
* base
= getOperand(baseId
);
1489 auto* guardedBase
= MGuardInt32Range::New(alloc(), base
, 2, 36);
1492 // Use lower-case characters by default.
1493 constexpr bool lower
= true;
1495 auto* ins
= MInt32ToStringWithBase::New(alloc(), input
, guardedBase
, lower
);
1502 bool WarpCacheIRTranspiler::emitBooleanToString(BooleanOperandId inputId
,
1503 StringOperandId resultId
) {
1504 return emitToString(inputId
, resultId
);
1507 bool WarpCacheIRTranspiler::emitBooleanToNumber(BooleanOperandId inputId
,
1508 NumberOperandId resultId
) {
1509 MDefinition
* input
= getOperand(inputId
);
1511 auto* ins
= MToDouble::New(alloc(), input
);
1514 return defineOperand(resultId
, ins
);
1517 bool WarpCacheIRTranspiler::emitStringToAtom(StringOperandId strId
) {
1518 MDefinition
* str
= getOperand(strId
);
1520 auto* ins
= MToHashableString::New(alloc(), str
);
1523 setOperand(strId
, ins
);
1527 bool WarpCacheIRTranspiler::emitLoadInt32Result(Int32OperandId valId
) {
1528 MDefinition
* val
= getOperand(valId
);
1529 MOZ_ASSERT(val
->type() == MIRType::Int32
);
1534 bool WarpCacheIRTranspiler::emitLoadDoubleResult(NumberOperandId valId
) {
1535 MDefinition
* val
= getOperand(valId
);
1536 MOZ_ASSERT(val
->type() == MIRType::Double
);
1541 bool WarpCacheIRTranspiler::emitLoadBigIntResult(BigIntOperandId valId
) {
1542 MDefinition
* val
= getOperand(valId
);
1543 MOZ_ASSERT(val
->type() == MIRType::BigInt
);
1548 bool WarpCacheIRTranspiler::emitLoadObjectResult(ObjOperandId objId
) {
1549 MDefinition
* obj
= getOperand(objId
);
1550 MOZ_ASSERT(obj
->type() == MIRType::Object
);
1555 bool WarpCacheIRTranspiler::emitLoadStringResult(StringOperandId strId
) {
1556 MDefinition
* str
= getOperand(strId
);
1557 MOZ_ASSERT(str
->type() == MIRType::String
);
1562 bool WarpCacheIRTranspiler::emitLoadSymbolResult(SymbolOperandId symId
) {
1563 MDefinition
* sym
= getOperand(symId
);
1564 MOZ_ASSERT(sym
->type() == MIRType::Symbol
);
1569 bool WarpCacheIRTranspiler::emitLoadUndefinedResult() {
1570 pushResult(constant(UndefinedValue()));
1574 bool WarpCacheIRTranspiler::emitLoadBooleanResult(bool val
) {
1575 pushResult(constant(BooleanValue(val
)));
1579 bool WarpCacheIRTranspiler::emitLoadInt32Constant(uint32_t valOffset
,
1580 Int32OperandId resultId
) {
1581 int32_t val
= int32StubField(valOffset
);
1582 auto* valConst
= constant(Int32Value(val
));
1583 return defineOperand(resultId
, valConst
);
1586 bool WarpCacheIRTranspiler::emitLoadDoubleConstant(uint32_t valOffset
,
1587 NumberOperandId resultId
) {
1588 double val
= doubleStubField(valOffset
);
1589 auto* valConst
= constant(DoubleValue(val
));
1590 return defineOperand(resultId
, valConst
);
1593 bool WarpCacheIRTranspiler::emitLoadBooleanConstant(bool val
,
1594 BooleanOperandId resultId
) {
1595 auto* valConst
= constant(BooleanValue(val
));
1596 return defineOperand(resultId
, valConst
);
1599 bool WarpCacheIRTranspiler::emitLoadUndefined(ValOperandId resultId
) {
1600 auto* valConst
= constant(UndefinedValue());
1601 return defineOperand(resultId
, valConst
);
1604 bool WarpCacheIRTranspiler::emitLoadConstantString(uint32_t strOffset
,
1605 StringOperandId resultId
) {
1606 JSString
* val
= stringStubField(strOffset
);
1607 auto* valConst
= constant(StringValue(val
));
1608 return defineOperand(resultId
, valConst
);
1611 bool WarpCacheIRTranspiler::emitLoadConstantStringResult(uint32_t strOffset
) {
1612 JSString
* val
= stringStubField(strOffset
);
1613 auto* valConst
= constant(StringValue(val
));
1614 pushResult(valConst
);
1618 bool WarpCacheIRTranspiler::emitLoadTypeOfObjectResult(ObjOperandId objId
) {
1619 MDefinition
* obj
= getOperand(objId
);
1620 auto* typeOf
= MTypeOf::New(alloc(), obj
);
1623 auto* ins
= MTypeOfName::New(alloc(), typeOf
);
1629 bool WarpCacheIRTranspiler::emitLoadEnclosingEnvironment(
1630 ObjOperandId objId
, ObjOperandId resultId
) {
1631 MDefinition
* env
= getOperand(objId
);
1632 auto* ins
= MEnclosingEnvironment::New(alloc(), env
);
1635 return defineOperand(resultId
, ins
);
1638 bool WarpCacheIRTranspiler::emitLoadObject(ObjOperandId resultId
,
1639 uint32_t objOffset
) {
1640 MInstruction
* ins
= objectStubField(objOffset
);
1642 return defineOperand(resultId
, ins
);
1645 bool WarpCacheIRTranspiler::emitLoadProtoObject(ObjOperandId resultId
,
1647 ObjOperandId receiverObjId
) {
1648 MInstruction
* ins
= objectStubField(objOffset
);
1649 if (ins
->isConstant()) {
1650 MDefinition
* receiverObj
= getOperand(receiverObjId
);
1652 ins
= MConstantProto::New(alloc(), ins
, receiverObj
->skipObjectGuards());
1655 return defineOperand(resultId
, ins
);
1658 bool WarpCacheIRTranspiler::emitLoadProto(ObjOperandId objId
,
1659 ObjOperandId resultId
) {
1660 MDefinition
* obj
= getOperand(objId
);
1662 auto* ins
= MObjectStaticProto::New(alloc(), obj
);
1665 return defineOperand(resultId
, ins
);
1668 bool WarpCacheIRTranspiler::emitLoadInstanceOfObjectResult(
1669 ValOperandId lhsId
, ObjOperandId protoId
) {
1670 MDefinition
* lhs
= getOperand(lhsId
);
1671 MDefinition
* proto
= getOperand(protoId
);
1673 auto* instanceOf
= MInstanceOf::New(alloc(), lhs
, proto
);
1674 addEffectful(instanceOf
);
1676 pushResult(instanceOf
);
1677 return resumeAfter(instanceOf
);
1680 bool WarpCacheIRTranspiler::emitLoadValueTag(ValOperandId valId
,
1681 ValueTagOperandId resultId
) {
1682 MDefinition
* val
= getOperand(valId
);
1684 auto* ins
= MLoadValueTag::New(alloc(), val
);
1687 return defineOperand(resultId
, ins
);
1690 bool WarpCacheIRTranspiler::emitLoadDynamicSlotResult(ObjOperandId objId
,
1691 uint32_t offsetOffset
) {
1692 int32_t offset
= int32StubField(offsetOffset
);
1694 MDefinition
* obj
= getOperand(objId
);
1695 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
1697 auto* slots
= MSlots::New(alloc(), obj
);
1700 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
1707 bool WarpCacheIRTranspiler::emitLoadFixedSlot(ValOperandId resultId
,
1709 uint32_t offsetOffset
) {
1710 MDefinition
* obj
= getOperand(objId
);
1712 size_t offset
= int32StubField(offsetOffset
);
1713 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1715 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1718 return defineOperand(resultId
, load
);
1721 bool WarpCacheIRTranspiler::emitLoadFixedSlotResult(ObjOperandId objId
,
1722 uint32_t offsetOffset
) {
1723 int32_t offset
= int32StubField(offsetOffset
);
1725 MDefinition
* obj
= getOperand(objId
);
1726 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1728 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1735 bool WarpCacheIRTranspiler::emitLoadFixedSlotTypedResult(ObjOperandId objId
,
1736 uint32_t offsetOffset
,
1738 int32_t offset
= int32StubField(offsetOffset
);
1740 MDefinition
* obj
= getOperand(objId
);
1741 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1743 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1744 load
->setResultType(MIRTypeFromValueType(JSValueType(type
)));
1751 bool WarpCacheIRTranspiler::emitGuardIsNotUninitializedLexical(
1752 ValOperandId valId
) {
1753 MDefinition
* val
= getOperand(valId
);
1755 auto* lexicalCheck
= MLexicalCheck::New(alloc(), val
);
1758 if (snapshot().bailoutInfo().failedLexicalCheck()) {
1759 lexicalCheck
->setNotMovable();
1762 setOperand(valId
, lexicalCheck
);
1766 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLengthResult(ObjOperandId objId
) {
1767 MDefinition
* obj
= getOperand(objId
);
1769 auto* elements
= MElements::New(alloc(), obj
);
1772 auto* length
= MArrayLength::New(alloc(), elements
);
1779 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLength(ObjOperandId objId
,
1780 Int32OperandId resultId
) {
1781 MDefinition
* obj
= getOperand(objId
);
1783 auto* elements
= MElements::New(alloc(), obj
);
1786 auto* length
= MArrayLength::New(alloc(), elements
);
1789 return defineOperand(resultId
, length
);
1792 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgResult(
1793 ObjOperandId objId
, Int32OperandId indexId
) {
1794 MDefinition
* obj
= getOperand(objId
);
1795 MDefinition
* index
= getOperand(indexId
);
1797 auto* load
= MLoadArgumentsObjectArg::New(alloc(), obj
, index
);
1804 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgHoleResult(
1805 ObjOperandId objId
, Int32OperandId indexId
) {
1806 MDefinition
* obj
= getOperand(objId
);
1807 MDefinition
* index
= getOperand(indexId
);
1809 auto* load
= MLoadArgumentsObjectArgHole::New(alloc(), obj
, index
);
1816 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgExistsResult(
1817 ObjOperandId objId
, Int32OperandId indexId
) {
1818 MDefinition
* obj
= getOperand(objId
);
1819 MDefinition
* index
= getOperand(indexId
);
1821 auto* ins
= MInArgumentsObjectArg::New(alloc(), obj
, index
);
1828 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLengthResult(
1829 ObjOperandId objId
) {
1830 MDefinition
* obj
= getOperand(objId
);
1832 auto* length
= MArgumentsObjectLength::New(alloc(), obj
);
1839 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLength(
1840 ObjOperandId objId
, Int32OperandId resultId
) {
1841 MDefinition
* obj
= getOperand(objId
);
1843 auto* length
= MArgumentsObjectLength::New(alloc(), obj
);
1846 return defineOperand(resultId
, length
);
1849 bool WarpCacheIRTranspiler::emitLoadBoundFunctionNumArgs(
1850 ObjOperandId objId
, Int32OperandId resultId
) {
1851 MDefinition
* obj
= getOperand(objId
);
1853 auto* numArgs
= MBoundFunctionNumArgs::New(alloc(), obj
);
1856 return defineOperand(resultId
, numArgs
);
1859 bool WarpCacheIRTranspiler::emitLoadBoundFunctionTarget(ObjOperandId objId
,
1860 ObjOperandId resultId
) {
1861 MDefinition
* obj
= getOperand(objId
);
1863 auto* target
= MLoadFixedSlotAndUnbox::New(
1864 alloc(), obj
, BoundFunctionObject::targetSlot(), MUnbox::Mode::Infallible
,
1868 return defineOperand(resultId
, target
);
1871 bool WarpCacheIRTranspiler::emitGuardBoundFunctionIsConstructor(
1872 ObjOperandId objId
) {
1873 MDefinition
* obj
= getOperand(objId
);
1875 auto* guard
= MGuardBoundFunctionIsConstructor::New(alloc(), obj
);
1878 setOperand(objId
, guard
);
1882 bool WarpCacheIRTranspiler::emitGuardObjectIdentity(ObjOperandId obj1Id
,
1883 ObjOperandId obj2Id
) {
1884 MDefinition
* obj1
= getOperand(obj1Id
);
1885 MDefinition
* obj2
= getOperand(obj2Id
);
1887 auto* guard
= MGuardObjectIdentity::New(alloc(), obj1
, obj2
,
1888 /* bailOnEquality = */ false);
1893 bool WarpCacheIRTranspiler::emitArrayFromArgumentsObjectResult(
1894 ObjOperandId objId
, uint32_t shapeOffset
) {
1895 MDefinition
* obj
= getOperand(objId
);
1896 Shape
* shape
= shapeStubField(shapeOffset
);
1899 auto* array
= MArrayFromArgumentsObject::New(alloc(), obj
, shape
);
1900 addEffectful(array
);
1903 return resumeAfter(array
);
1906 bool WarpCacheIRTranspiler::emitLoadFunctionLengthResult(ObjOperandId objId
) {
1907 MDefinition
* obj
= getOperand(objId
);
1909 auto* length
= MFunctionLength::New(alloc(), obj
);
1916 bool WarpCacheIRTranspiler::emitLoadFunctionNameResult(ObjOperandId objId
) {
1917 MDefinition
* obj
= getOperand(objId
);
1919 auto* name
= MFunctionName::New(alloc(), obj
);
1926 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthInt32Result(
1927 ObjOperandId objId
) {
1928 MDefinition
* obj
= getOperand(objId
);
1930 auto* length
= MArrayBufferByteLength::New(alloc(), obj
);
1933 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
1936 pushResult(lengthInt32
);
1940 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthDoubleResult(
1941 ObjOperandId objId
) {
1942 MDefinition
* obj
= getOperand(objId
);
1944 auto* length
= MArrayBufferByteLength::New(alloc(), obj
);
1947 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
1950 pushResult(lengthDouble
);
1954 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthInt32Result(
1955 ObjOperandId objId
) {
1956 MDefinition
* obj
= getOperand(objId
);
1958 // Use a separate instruction for converting the length to Int32, so that we
1959 // can fold the MArrayBufferViewLength instruction with length instructions
1960 // added for bounds checks.
1962 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
1965 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
1968 pushResult(lengthInt32
);
1972 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthDoubleResult(
1973 ObjOperandId objId
) {
1974 MDefinition
* obj
= getOperand(objId
);
1976 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
1979 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
1982 pushResult(lengthDouble
);
1986 bool WarpCacheIRTranspiler::emitLoadStringLengthResult(StringOperandId strId
) {
1987 MDefinition
* str
= getOperand(strId
);
1989 auto* length
= MStringLength::New(alloc(), str
);
1996 MInstruction
* WarpCacheIRTranspiler::addBoundsCheck(MDefinition
* index
,
1997 MDefinition
* length
) {
1998 MInstruction
* check
= MBoundsCheck::New(alloc(), index
, length
);
2001 if (snapshot().bailoutInfo().failedBoundsCheck()) {
2002 check
->setNotMovable();
2005 if (JitOptions
.spectreIndexMasking
) {
2006 // Use a separate MIR instruction for the index masking. Doing this as
2007 // part of MBoundsCheck would be unsound because bounds checks can be
2008 // optimized or eliminated completely. Consider this:
2010 // for (var i = 0; i < x; i++)
2013 // If we can prove |x < arr.length|, we are able to eliminate the bounds
2014 // check, but we should not get rid of the index masking because the
2015 // |i < x| branch could still be mispredicted.
2017 // Using a separate instruction lets us eliminate the bounds check
2018 // without affecting the index masking.
2019 check
= MSpectreMaskIndex::New(alloc(), check
, length
);
2026 bool WarpCacheIRTranspiler::emitLoadDenseElementResult(ObjOperandId objId
,
2027 Int32OperandId indexId
) {
2028 MDefinition
* obj
= getOperand(objId
);
2029 MDefinition
* index
= getOperand(indexId
);
2031 auto* elements
= MElements::New(alloc(), obj
);
2034 auto* length
= MInitializedLength::New(alloc(), elements
);
2037 index
= addBoundsCheck(index
, length
);
2039 auto* load
= MLoadElement::New(alloc(), elements
, index
);
2046 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleResult(
2047 ObjOperandId objId
, Int32OperandId indexId
) {
2048 MDefinition
* obj
= getOperand(objId
);
2049 MDefinition
* index
= getOperand(indexId
);
2051 auto* elements
= MElements::New(alloc(), obj
);
2054 auto* length
= MInitializedLength::New(alloc(), elements
);
2057 auto* load
= MLoadElementHole::New(alloc(), elements
, index
, length
);
2064 bool WarpCacheIRTranspiler::emitCallGetSparseElementResult(
2065 ObjOperandId objId
, Int32OperandId indexId
) {
2066 MDefinition
* obj
= getOperand(objId
);
2067 MDefinition
* index
= getOperand(indexId
);
2069 auto* call
= MCallGetSparseElement::New(alloc(), obj
, index
);
2073 return resumeAfter(call
);
2076 bool WarpCacheIRTranspiler::emitCallNativeGetElementResult(
2077 ObjOperandId objId
, Int32OperandId indexId
) {
2078 MDefinition
* obj
= getOperand(objId
);
2079 MDefinition
* index
= getOperand(indexId
);
2081 auto* call
= MCallNativeGetElement::New(alloc(), obj
, index
);
2085 return resumeAfter(call
);
2088 bool WarpCacheIRTranspiler::emitCallNativeGetElementSuperResult(
2089 ObjOperandId objId
, Int32OperandId indexId
, ValOperandId receiverId
) {
2090 MDefinition
* obj
= getOperand(objId
);
2091 MDefinition
* index
= getOperand(indexId
);
2092 MDefinition
* receiver
= getOperand(receiverId
);
2094 auto* call
= MCallNativeGetElementSuper::New(alloc(), obj
, index
, receiver
);
2098 return resumeAfter(call
);
2101 bool WarpCacheIRTranspiler::emitLoadDenseElementExistsResult(
2102 ObjOperandId objId
, Int32OperandId indexId
) {
2103 MDefinition
* obj
= getOperand(objId
);
2104 MDefinition
* index
= getOperand(indexId
);
2106 // Get the elements vector.
2107 auto* elements
= MElements::New(alloc(), obj
);
2110 auto* length
= MInitializedLength::New(alloc(), elements
);
2113 // Check if id < initLength.
2114 index
= addBoundsCheck(index
, length
);
2116 // And check elem[id] is not a hole.
2117 auto* guard
= MGuardElementNotHole::New(alloc(), elements
, index
);
2120 pushResult(constant(BooleanValue(true)));
2124 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleExistsResult(
2125 ObjOperandId objId
, Int32OperandId indexId
) {
2126 MDefinition
* obj
= getOperand(objId
);
2127 MDefinition
* index
= getOperand(indexId
);
2129 // Get the elements vector.
2130 auto* elements
= MElements::New(alloc(), obj
);
2133 auto* length
= MInitializedLength::New(alloc(), elements
);
2136 // Check if id < initLength and elem[id] not a hole.
2137 auto* ins
= MInArray::New(alloc(), elements
, index
, length
);
2144 bool WarpCacheIRTranspiler::emitCallObjectHasSparseElementResult(
2145 ObjOperandId objId
, Int32OperandId indexId
) {
2146 MDefinition
* obj
= getOperand(objId
);
2147 MDefinition
* index
= getOperand(indexId
);
2149 auto* ins
= MCallObjectHasSparseElement::New(alloc(), obj
, index
);
2156 MInstruction
* WarpCacheIRTranspiler::emitTypedArrayLength(
2157 ArrayBufferViewKind viewKind
, MDefinition
* obj
) {
2158 if (viewKind
== ArrayBufferViewKind::FixedLength
) {
2159 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
2165 // Bounds check doesn't require a memory barrier. See IsValidIntegerIndex
2166 // abstract operation which reads the underlying buffer byte length using
2167 // "unordered" memory order.
2168 auto barrier
= MemoryBarrierRequirement::NotRequired
;
2170 // Movable and removable because no memory barrier is needed.
2171 auto* length
= MResizableTypedArrayLength::New(alloc(), obj
, barrier
);
2172 length
->setMovable();
2173 length
->setNotGuard();
2179 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementExistsResult(
2180 ObjOperandId objId
, IntPtrOperandId indexId
, ArrayBufferViewKind viewKind
) {
2181 MDefinition
* obj
= getOperand(objId
);
2182 MDefinition
* index
= getOperand(indexId
);
2184 auto* length
= emitTypedArrayLength(viewKind
, obj
);
2186 // Unsigned comparison to catch negative indices.
2187 auto* ins
= MCompare::New(alloc(), index
, length
, JSOp::Lt
,
2188 MCompare::Compare_UIntPtr
);
2195 static MIRType
MIRTypeForArrayBufferViewRead(Scalar::Type arrayType
,
2196 bool forceDoubleForUint32
) {
2197 switch (arrayType
) {
2200 case Scalar::Uint8Clamped
:
2202 case Scalar::Uint16
:
2204 return MIRType::Int32
;
2205 case Scalar::Uint32
:
2206 return forceDoubleForUint32
? MIRType::Double
: MIRType::Int32
;
2207 case Scalar::Float32
:
2208 return MIRType::Float32
;
2209 case Scalar::Float64
:
2210 return MIRType::Double
;
2211 case Scalar::BigInt64
:
2212 case Scalar::BigUint64
:
2213 return MIRType::BigInt
;
2217 MOZ_CRASH("Unknown typed array type");
2220 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementResult(
2221 ObjOperandId objId
, IntPtrOperandId indexId
, Scalar::Type elementType
,
2222 bool handleOOB
, bool forceDoubleForUint32
, ArrayBufferViewKind viewKind
) {
2223 MDefinition
* obj
= getOperand(objId
);
2224 MDefinition
* index
= getOperand(indexId
);
2226 auto* length
= emitTypedArrayLength(viewKind
, obj
);
2229 // MLoadTypedArrayElementHole does the bounds checking.
2230 index
= addBoundsCheck(index
, length
);
2233 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
2237 auto* load
= MLoadTypedArrayElementHole::New(
2238 alloc(), elements
, index
, length
, elementType
, forceDoubleForUint32
);
2245 auto* load
= MLoadUnboxedScalar::New(alloc(), elements
, index
, elementType
);
2246 load
->setResultType(
2247 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
));
2254 bool WarpCacheIRTranspiler::emitLinearizeForCharAccess(
2255 StringOperandId strId
, Int32OperandId indexId
, StringOperandId resultId
) {
2256 MDefinition
* str
= getOperand(strId
);
2257 MDefinition
* index
= getOperand(indexId
);
2259 auto* ins
= MLinearizeForCharAccess::New(alloc(), str
, index
);
2262 return defineOperand(resultId
, ins
);
2265 bool WarpCacheIRTranspiler::emitLinearizeForCodePointAccess(
2266 StringOperandId strId
, Int32OperandId indexId
, StringOperandId resultId
) {
2267 MDefinition
* str
= getOperand(strId
);
2268 MDefinition
* index
= getOperand(indexId
);
2270 auto* ins
= MLinearizeForCodePointAccess::New(alloc(), str
, index
);
2273 return defineOperand(resultId
, ins
);
2276 bool WarpCacheIRTranspiler::emitToRelativeStringIndex(Int32OperandId indexId
,
2277 StringOperandId strId
,
2278 Int32OperandId resultId
) {
2279 MDefinition
* str
= getOperand(strId
);
2280 MDefinition
* index
= getOperand(indexId
);
2282 auto* length
= MStringLength::New(alloc(), str
);
2285 auto* ins
= MToRelativeStringIndex::New(alloc(), index
, length
);
2288 return defineOperand(resultId
, ins
);
2291 bool WarpCacheIRTranspiler::emitLoadStringCharResult(StringOperandId strId
,
2292 Int32OperandId indexId
,
2294 MDefinition
* str
= getOperand(strId
);
2295 MDefinition
* index
= getOperand(indexId
);
2298 auto* charCode
= MCharCodeAtOrNegative::New(alloc(), str
, index
);
2301 auto* fromCharCode
= MFromCharCodeEmptyIfNegative::New(alloc(), charCode
);
2304 pushResult(fromCharCode
);
2308 auto* length
= MStringLength::New(alloc(), str
);
2311 index
= addBoundsCheck(index
, length
);
2313 auto* charCode
= MCharCodeAt::New(alloc(), str
, index
);
2316 auto* fromCharCode
= MFromCharCode::New(alloc(), charCode
);
2319 pushResult(fromCharCode
);
2323 bool WarpCacheIRTranspiler::emitLoadStringAtResult(StringOperandId strId
,
2324 Int32OperandId indexId
,
2326 MDefinition
* str
= getOperand(strId
);
2327 MDefinition
* index
= getOperand(indexId
);
2330 auto* charCode
= MCharCodeAtOrNegative::New(alloc(), str
, index
);
2333 auto* fromCharCode
=
2334 MFromCharCodeUndefinedIfNegative::New(alloc(), charCode
);
2337 pushResult(fromCharCode
);
2341 auto* length
= MStringLength::New(alloc(), str
);
2344 index
= addBoundsCheck(index
, length
);
2346 auto* charCode
= MCharCodeAt::New(alloc(), str
, index
);
2349 auto* fromCharCode
= MFromCharCode::New(alloc(), charCode
);
2352 pushResult(fromCharCode
);
2356 bool WarpCacheIRTranspiler::emitLoadStringCharCodeResult(StringOperandId strId
,
2357 Int32OperandId indexId
,
2359 MDefinition
* str
= getOperand(strId
);
2360 MDefinition
* index
= getOperand(indexId
);
2363 auto* charCode
= MCharCodeAtOrNegative::New(alloc(), str
, index
);
2366 auto* ins
= MNegativeToNaN::New(alloc(), charCode
);
2373 auto* length
= MStringLength::New(alloc(), str
);
2376 index
= addBoundsCheck(index
, length
);
2378 auto* charCode
= MCharCodeAt::New(alloc(), str
, index
);
2381 pushResult(charCode
);
2385 bool WarpCacheIRTranspiler::emitLoadStringCodePointResult(
2386 StringOperandId strId
, Int32OperandId indexId
, bool handleOOB
) {
2387 MDefinition
* str
= getOperand(strId
);
2388 MDefinition
* index
= getOperand(indexId
);
2391 auto* codePoint
= MCodePointAtOrNegative::New(alloc(), str
, index
);
2394 auto* ins
= MNegativeToUndefined::New(alloc(), codePoint
);
2401 auto* length
= MStringLength::New(alloc(), str
);
2404 index
= addBoundsCheck(index
, length
);
2406 auto* codePoint
= MCodePointAt::New(alloc(), str
, index
);
2409 pushResult(codePoint
);
2413 bool WarpCacheIRTranspiler::emitNewStringObjectResult(
2414 uint32_t templateObjectOffset
, StringOperandId strId
) {
2415 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
2416 MDefinition
* string
= getOperand(strId
);
2418 auto* obj
= MNewStringObject::New(alloc(), string
, templateObj
);
2422 return resumeAfter(obj
);
2425 bool WarpCacheIRTranspiler::emitStringFromCharCodeResult(
2426 Int32OperandId codeId
) {
2427 MDefinition
* code
= getOperand(codeId
);
2429 auto* fromCharCode
= MFromCharCode::New(alloc(), code
);
2432 pushResult(fromCharCode
);
2436 bool WarpCacheIRTranspiler::emitStringFromCodePointResult(
2437 Int32OperandId codeId
) {
2438 MDefinition
* code
= getOperand(codeId
);
2440 auto* fromCodePoint
= MFromCodePoint::New(alloc(), code
);
2443 pushResult(fromCodePoint
);
2447 bool WarpCacheIRTranspiler::emitStringIncludesResult(
2448 StringOperandId strId
, StringOperandId searchStrId
) {
2449 MDefinition
* str
= getOperand(strId
);
2450 MDefinition
* searchStr
= getOperand(searchStrId
);
2452 auto* includes
= MStringIncludes::New(alloc(), str
, searchStr
);
2455 pushResult(includes
);
2459 bool WarpCacheIRTranspiler::emitStringIndexOfResult(
2460 StringOperandId strId
, StringOperandId searchStrId
) {
2461 MDefinition
* str
= getOperand(strId
);
2462 MDefinition
* searchStr
= getOperand(searchStrId
);
2464 auto* indexOf
= MStringIndexOf::New(alloc(), str
, searchStr
);
2467 pushResult(indexOf
);
2471 bool WarpCacheIRTranspiler::emitStringLastIndexOfResult(
2472 StringOperandId strId
, StringOperandId searchStrId
) {
2473 MDefinition
* str
= getOperand(strId
);
2474 MDefinition
* searchStr
= getOperand(searchStrId
);
2476 auto* lastIndexOf
= MStringLastIndexOf::New(alloc(), str
, searchStr
);
2479 pushResult(lastIndexOf
);
2483 bool WarpCacheIRTranspiler::emitStringStartsWithResult(
2484 StringOperandId strId
, StringOperandId searchStrId
) {
2485 MDefinition
* str
= getOperand(strId
);
2486 MDefinition
* searchStr
= getOperand(searchStrId
);
2488 auto* startsWith
= MStringStartsWith::New(alloc(), str
, searchStr
);
2491 pushResult(startsWith
);
2495 bool WarpCacheIRTranspiler::emitStringEndsWithResult(
2496 StringOperandId strId
, StringOperandId searchStrId
) {
2497 MDefinition
* str
= getOperand(strId
);
2498 MDefinition
* searchStr
= getOperand(searchStrId
);
2500 auto* endsWith
= MStringEndsWith::New(alloc(), str
, searchStr
);
2503 pushResult(endsWith
);
2507 bool WarpCacheIRTranspiler::emitStringToLowerCaseResult(StringOperandId strId
) {
2508 MDefinition
* str
= getOperand(strId
);
2511 MStringConvertCase::New(alloc(), str
, MStringConvertCase::LowerCase
);
2514 pushResult(convert
);
2518 bool WarpCacheIRTranspiler::emitStringToUpperCaseResult(StringOperandId strId
) {
2519 MDefinition
* str
= getOperand(strId
);
2522 MStringConvertCase::New(alloc(), str
, MStringConvertCase::UpperCase
);
2525 pushResult(convert
);
2529 bool WarpCacheIRTranspiler::emitStringTrimResult(StringOperandId strId
) {
2530 MDefinition
* str
= getOperand(strId
);
2532 auto* linear
= MLinearizeString::New(alloc(), str
);
2535 auto* start
= MStringTrimStartIndex::New(alloc(), linear
);
2538 auto* end
= MStringTrimEndIndex::New(alloc(), linear
, start
);
2541 // Safe to truncate because both operands are positive and end >= start.
2542 auto* length
= MSub::New(alloc(), end
, start
, MIRType::Int32
);
2543 length
->setTruncateKind(TruncateKind::Truncate
);
2546 auto* substr
= MSubstr::New(alloc(), linear
, start
, length
);
2553 bool WarpCacheIRTranspiler::emitStringTrimStartResult(StringOperandId strId
) {
2554 MDefinition
* str
= getOperand(strId
);
2556 auto* linear
= MLinearizeString::New(alloc(), str
);
2559 auto* start
= MStringTrimStartIndex::New(alloc(), linear
);
2562 auto* end
= MStringLength::New(alloc(), linear
);
2565 // Safe to truncate because both operands are positive and end >= start.
2566 auto* length
= MSub::New(alloc(), end
, start
, MIRType::Int32
);
2567 length
->setTruncateKind(TruncateKind::Truncate
);
2570 auto* substr
= MSubstr::New(alloc(), linear
, start
, length
);
2577 bool WarpCacheIRTranspiler::emitStringTrimEndResult(StringOperandId strId
) {
2578 MDefinition
* str
= getOperand(strId
);
2580 auto* linear
= MLinearizeString::New(alloc(), str
);
2583 auto* start
= constant(Int32Value(0));
2585 auto* length
= MStringTrimEndIndex::New(alloc(), linear
, start
);
2588 auto* substr
= MSubstr::New(alloc(), linear
, start
, length
);
2595 bool WarpCacheIRTranspiler::emitStoreDynamicSlot(ObjOperandId objId
,
2596 uint32_t offsetOffset
,
2597 ValOperandId rhsId
) {
2598 int32_t offset
= int32StubField(offsetOffset
);
2600 MDefinition
* obj
= getOperand(objId
);
2601 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
2602 MDefinition
* rhs
= getOperand(rhsId
);
2604 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2607 auto* slots
= MSlots::New(alloc(), obj
);
2610 auto* store
= MStoreDynamicSlot::NewBarriered(alloc(), slots
, slotIndex
, rhs
);
2611 addEffectful(store
);
2612 return resumeAfter(store
);
2615 bool WarpCacheIRTranspiler::emitStoreFixedSlot(ObjOperandId objId
,
2616 uint32_t offsetOffset
,
2617 ValOperandId rhsId
) {
2618 int32_t offset
= int32StubField(offsetOffset
);
2620 MDefinition
* obj
= getOperand(objId
);
2621 size_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
2622 MDefinition
* rhs
= getOperand(rhsId
);
2624 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2627 auto* store
= MStoreFixedSlot::NewBarriered(alloc(), obj
, slotIndex
, rhs
);
2628 addEffectful(store
);
2629 return resumeAfter(store
);
2632 bool WarpCacheIRTranspiler::emitStoreFixedSlotUndefinedResult(
2633 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
) {
2634 int32_t offset
= int32StubField(offsetOffset
);
2636 MDefinition
* obj
= getOperand(objId
);
2637 size_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
2638 MDefinition
* rhs
= getOperand(rhsId
);
2640 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2643 auto* store
= MStoreFixedSlot::NewBarriered(alloc(), obj
, slotIndex
, rhs
);
2644 addEffectful(store
);
2646 auto* undef
= constant(UndefinedValue());
2649 return resumeAfter(store
);
2652 bool WarpCacheIRTranspiler::emitAddAndStoreSlotShared(
2653 MAddAndStoreSlot::Kind kind
, ObjOperandId objId
, uint32_t offsetOffset
,
2654 ValOperandId rhsId
, uint32_t newShapeOffset
) {
2655 int32_t offset
= int32StubField(offsetOffset
);
2656 Shape
* shape
= shapeStubField(newShapeOffset
);
2658 MDefinition
* obj
= getOperand(objId
);
2659 MDefinition
* rhs
= getOperand(rhsId
);
2661 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2665 MAddAndStoreSlot::New(alloc(), obj
, rhs
, kind
, offset
, shape
);
2666 addEffectful(addAndStore
);
2668 return resumeAfter(addAndStore
);
2671 bool WarpCacheIRTranspiler::emitAddAndStoreFixedSlot(ObjOperandId objId
,
2672 uint32_t offsetOffset
,
2674 uint32_t newShapeOffset
) {
2675 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::FixedSlot
, objId
,
2676 offsetOffset
, rhsId
, newShapeOffset
);
2679 bool WarpCacheIRTranspiler::emitAddAndStoreDynamicSlot(
2680 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
,
2681 uint32_t newShapeOffset
) {
2682 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::DynamicSlot
, objId
,
2683 offsetOffset
, rhsId
, newShapeOffset
);
2686 bool WarpCacheIRTranspiler::emitAllocateAndStoreDynamicSlot(
2687 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
,
2688 uint32_t newShapeOffset
, uint32_t numNewSlotsOffset
) {
2689 int32_t offset
= int32StubField(offsetOffset
);
2690 Shape
* shape
= shapeStubField(newShapeOffset
);
2691 uint32_t numNewSlots
= uint32StubField(numNewSlotsOffset
);
2693 MDefinition
* obj
= getOperand(objId
);
2694 MDefinition
* rhs
= getOperand(rhsId
);
2696 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2699 auto* allocateAndStore
=
2700 MAllocateAndStoreSlot::New(alloc(), obj
, rhs
, offset
, shape
, numNewSlots
);
2701 addEffectful(allocateAndStore
);
2703 return resumeAfter(allocateAndStore
);
2706 bool WarpCacheIRTranspiler::emitAddSlotAndCallAddPropHook(
2707 ObjOperandId objId
, ValOperandId rhsId
, uint32_t newShapeOffset
) {
2708 Shape
* shape
= shapeStubField(newShapeOffset
);
2709 MDefinition
* obj
= getOperand(objId
);
2710 MDefinition
* rhs
= getOperand(rhsId
);
2712 auto* addProp
= MAddSlotAndCallAddPropHook::New(alloc(), obj
, rhs
, shape
);
2713 addEffectful(addProp
);
2715 return resumeAfter(addProp
);
2718 bool WarpCacheIRTranspiler::emitStoreDenseElement(ObjOperandId objId
,
2719 Int32OperandId indexId
,
2720 ValOperandId rhsId
) {
2721 MDefinition
* obj
= getOperand(objId
);
2722 MDefinition
* index
= getOperand(indexId
);
2723 MDefinition
* rhs
= getOperand(rhsId
);
2725 auto* elements
= MElements::New(alloc(), obj
);
2728 auto* length
= MInitializedLength::New(alloc(), elements
);
2731 index
= addBoundsCheck(index
, length
);
2733 auto* barrier
= MPostWriteElementBarrier::New(alloc(), obj
, rhs
, index
);
2736 bool needsHoleCheck
= true;
2737 auto* store
= MStoreElement::NewBarriered(alloc(), elements
, index
, rhs
,
2739 addEffectful(store
);
2740 return resumeAfter(store
);
2743 bool WarpCacheIRTranspiler::emitStoreDenseElementHole(ObjOperandId objId
,
2744 Int32OperandId indexId
,
2747 MDefinition
* obj
= getOperand(objId
);
2748 MDefinition
* index
= getOperand(indexId
);
2749 MDefinition
* rhs
= getOperand(rhsId
);
2751 auto* elements
= MElements::New(alloc(), obj
);
2754 MInstruction
* store
;
2756 // TODO(post-Warp): Consider changing MStoreElementHole to match IC code.
2757 store
= MStoreElementHole::New(alloc(), obj
, elements
, index
, rhs
);
2759 auto* length
= MInitializedLength::New(alloc(), elements
);
2762 index
= addBoundsCheck(index
, length
);
2764 auto* barrier
= MPostWriteElementBarrier::New(alloc(), obj
, rhs
, index
);
2767 bool needsHoleCheck
= false;
2768 store
= MStoreElement::NewBarriered(alloc(), elements
, index
, rhs
,
2771 addEffectful(store
);
2773 return resumeAfter(store
);
2776 bool WarpCacheIRTranspiler::emitStoreTypedArrayElement(
2777 ObjOperandId objId
, Scalar::Type elementType
, IntPtrOperandId indexId
,
2778 uint32_t rhsId
, bool handleOOB
, ArrayBufferViewKind viewKind
) {
2779 MDefinition
* obj
= getOperand(objId
);
2780 MDefinition
* index
= getOperand(indexId
);
2781 MDefinition
* rhs
= getOperand(ValOperandId(rhsId
));
2783 auto* length
= emitTypedArrayLength(viewKind
, obj
);
2786 // MStoreTypedArrayElementHole does the bounds checking.
2787 index
= addBoundsCheck(index
, length
);
2790 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
2793 MInstruction
* store
;
2795 store
= MStoreTypedArrayElementHole::New(alloc(), elements
, length
, index
,
2799 MStoreUnboxedScalar::New(alloc(), elements
, index
, rhs
, elementType
);
2801 addEffectful(store
);
2802 return resumeAfter(store
);
2805 MInstruction
* WarpCacheIRTranspiler::emitDataViewLength(
2806 ArrayBufferViewKind viewKind
, MDefinition
* obj
) {
2807 if (viewKind
== ArrayBufferViewKind::FixedLength
) {
2808 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
2814 // Bounds check doesn't require a memory barrier. See GetViewValue and
2815 // SetViewValue abstract operations which read the underlying buffer byte
2816 // length using "unordered" memory order.
2817 auto barrier
= MemoryBarrierRequirement::NotRequired
;
2819 // Movable and removable because no memory barrier is needed.
2820 auto* length
= MResizableDataViewByteLength::New(alloc(), obj
, barrier
);
2821 length
->setMovable();
2822 length
->setNotGuard();
2828 void WarpCacheIRTranspiler::addDataViewData(ArrayBufferViewKind viewKind
,
2829 MDefinition
* obj
, Scalar::Type type
,
2830 MDefinition
** offset
,
2831 MInstruction
** elements
) {
2832 auto* length
= emitDataViewLength(viewKind
, obj
);
2834 // Adjust the length to account for accesses near the end of the dataview.
2835 if (size_t byteSize
= Scalar::byteSize(type
); byteSize
> 1) {
2836 // To ensure |0 <= offset && offset + byteSize <= length|, first adjust the
2837 // length by subtracting |byteSize - 1| (bailing out if that becomes
2839 length
= MAdjustDataViewLength::New(alloc(), length
, byteSize
);
2843 *offset
= addBoundsCheck(*offset
, length
);
2845 *elements
= MArrayBufferViewElements::New(alloc(), obj
);
2849 bool WarpCacheIRTranspiler::emitLoadDataViewValueResult(
2850 ObjOperandId objId
, IntPtrOperandId offsetId
,
2851 BooleanOperandId littleEndianId
, Scalar::Type elementType
,
2852 bool forceDoubleForUint32
, ArrayBufferViewKind viewKind
) {
2853 MDefinition
* obj
= getOperand(objId
);
2854 MDefinition
* offset
= getOperand(offsetId
);
2855 MDefinition
* littleEndian
= getOperand(littleEndianId
);
2857 // Add bounds check and get the DataViewObject's elements.
2858 MInstruction
* elements
;
2859 addDataViewData(viewKind
, obj
, elementType
, &offset
, &elements
);
2861 // Load the element.
2863 if (Scalar::byteSize(elementType
) == 1) {
2864 load
= MLoadUnboxedScalar::New(alloc(), elements
, offset
, elementType
);
2866 load
= MLoadDataViewElement::New(alloc(), elements
, offset
, littleEndian
,
2872 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
2873 load
->setResultType(knownType
);
2879 bool WarpCacheIRTranspiler::emitStoreDataViewValueResult(
2880 ObjOperandId objId
, IntPtrOperandId offsetId
, uint32_t valueId
,
2881 BooleanOperandId littleEndianId
, Scalar::Type elementType
,
2882 ArrayBufferViewKind viewKind
) {
2883 MDefinition
* obj
= getOperand(objId
);
2884 MDefinition
* offset
= getOperand(offsetId
);
2885 MDefinition
* value
= getOperand(ValOperandId(valueId
));
2886 MDefinition
* littleEndian
= getOperand(littleEndianId
);
2888 // Add bounds check and get the DataViewObject's elements.
2889 MInstruction
* elements
;
2890 addDataViewData(viewKind
, obj
, elementType
, &offset
, &elements
);
2892 // Store the element.
2893 MInstruction
* store
;
2894 if (Scalar::byteSize(elementType
) == 1) {
2896 MStoreUnboxedScalar::New(alloc(), elements
, offset
, value
, elementType
);
2898 store
= MStoreDataViewElement::New(alloc(), elements
, offset
, value
,
2899 littleEndian
, elementType
);
2901 addEffectful(store
);
2903 pushResult(constant(UndefinedValue()));
2905 return resumeAfter(store
);
2908 bool WarpCacheIRTranspiler::emitInt32IncResult(Int32OperandId inputId
) {
2909 MDefinition
* input
= getOperand(inputId
);
2911 auto* constOne
= MConstant::New(alloc(), Int32Value(1));
2914 auto* ins
= MAdd::New(alloc(), input
, constOne
, MIRType::Int32
);
2921 bool WarpCacheIRTranspiler::emitDoubleIncResult(NumberOperandId inputId
) {
2922 MDefinition
* input
= getOperand(inputId
);
2924 auto* constOne
= MConstant::New(alloc(), DoubleValue(1.0));
2927 auto* ins
= MAdd::New(alloc(), input
, constOne
, MIRType::Double
);
2934 bool WarpCacheIRTranspiler::emitInt32DecResult(Int32OperandId inputId
) {
2935 MDefinition
* input
= getOperand(inputId
);
2937 auto* constOne
= MConstant::New(alloc(), Int32Value(1));
2940 auto* ins
= MSub::New(alloc(), input
, constOne
, MIRType::Int32
);
2947 bool WarpCacheIRTranspiler::emitDoubleDecResult(NumberOperandId inputId
) {
2948 MDefinition
* input
= getOperand(inputId
);
2950 auto* constOne
= MConstant::New(alloc(), DoubleValue(1.0));
2953 auto* ins
= MSub::New(alloc(), input
, constOne
, MIRType::Double
);
2960 bool WarpCacheIRTranspiler::emitInt32NegationResult(Int32OperandId inputId
) {
2961 MDefinition
* input
= getOperand(inputId
);
2963 auto* constNegOne
= MConstant::New(alloc(), Int32Value(-1));
2966 auto* ins
= MMul::New(alloc(), input
, constNegOne
, MIRType::Int32
);
2973 bool WarpCacheIRTranspiler::emitDoubleNegationResult(NumberOperandId inputId
) {
2974 MDefinition
* input
= getOperand(inputId
);
2976 auto* constNegOne
= MConstant::New(alloc(), DoubleValue(-1.0));
2979 auto* ins
= MMul::New(alloc(), input
, constNegOne
, MIRType::Double
);
2986 bool WarpCacheIRTranspiler::emitInt32NotResult(Int32OperandId inputId
) {
2987 MDefinition
* input
= getOperand(inputId
);
2989 auto* ins
= MBitNot::New(alloc(), input
);
2996 template <typename T
>
2997 bool WarpCacheIRTranspiler::emitDoubleBinaryArithResult(NumberOperandId lhsId
,
2998 NumberOperandId rhsId
) {
2999 MDefinition
* lhs
= getOperand(lhsId
);
3000 MDefinition
* rhs
= getOperand(rhsId
);
3002 auto* ins
= T::New(alloc(), lhs
, rhs
, MIRType::Double
);
3009 bool WarpCacheIRTranspiler::emitDoubleAddResult(NumberOperandId lhsId
,
3010 NumberOperandId rhsId
) {
3011 return emitDoubleBinaryArithResult
<MAdd
>(lhsId
, rhsId
);
3014 bool WarpCacheIRTranspiler::emitDoubleSubResult(NumberOperandId lhsId
,
3015 NumberOperandId rhsId
) {
3016 return emitDoubleBinaryArithResult
<MSub
>(lhsId
, rhsId
);
3019 bool WarpCacheIRTranspiler::emitDoubleMulResult(NumberOperandId lhsId
,
3020 NumberOperandId rhsId
) {
3021 return emitDoubleBinaryArithResult
<MMul
>(lhsId
, rhsId
);
3024 bool WarpCacheIRTranspiler::emitDoubleDivResult(NumberOperandId lhsId
,
3025 NumberOperandId rhsId
) {
3026 return emitDoubleBinaryArithResult
<MDiv
>(lhsId
, rhsId
);
3029 bool WarpCacheIRTranspiler::emitDoubleModResult(NumberOperandId lhsId
,
3030 NumberOperandId rhsId
) {
3031 return emitDoubleBinaryArithResult
<MMod
>(lhsId
, rhsId
);
3034 bool WarpCacheIRTranspiler::emitDoublePowResult(NumberOperandId lhsId
,
3035 NumberOperandId rhsId
) {
3036 return emitDoubleBinaryArithResult
<MPow
>(lhsId
, rhsId
);
3039 template <typename T
>
3040 bool WarpCacheIRTranspiler::emitInt32BinaryArithResult(Int32OperandId lhsId
,
3041 Int32OperandId rhsId
) {
3042 MDefinition
* lhs
= getOperand(lhsId
);
3043 MDefinition
* rhs
= getOperand(rhsId
);
3045 auto* ins
= T::New(alloc(), lhs
, rhs
, MIRType::Int32
);
3052 bool WarpCacheIRTranspiler::emitInt32AddResult(Int32OperandId lhsId
,
3053 Int32OperandId rhsId
) {
3054 return emitInt32BinaryArithResult
<MAdd
>(lhsId
, rhsId
);
3057 bool WarpCacheIRTranspiler::emitInt32SubResult(Int32OperandId lhsId
,
3058 Int32OperandId rhsId
) {
3059 return emitInt32BinaryArithResult
<MSub
>(lhsId
, rhsId
);
3062 bool WarpCacheIRTranspiler::emitInt32MulResult(Int32OperandId lhsId
,
3063 Int32OperandId rhsId
) {
3064 return emitInt32BinaryArithResult
<MMul
>(lhsId
, rhsId
);
3067 bool WarpCacheIRTranspiler::emitInt32DivResult(Int32OperandId lhsId
,
3068 Int32OperandId rhsId
) {
3069 return emitInt32BinaryArithResult
<MDiv
>(lhsId
, rhsId
);
3072 bool WarpCacheIRTranspiler::emitInt32ModResult(Int32OperandId lhsId
,
3073 Int32OperandId rhsId
) {
3074 return emitInt32BinaryArithResult
<MMod
>(lhsId
, rhsId
);
3077 bool WarpCacheIRTranspiler::emitInt32PowResult(Int32OperandId lhsId
,
3078 Int32OperandId rhsId
) {
3079 return emitInt32BinaryArithResult
<MPow
>(lhsId
, rhsId
);
3082 bool WarpCacheIRTranspiler::emitInt32BitOrResult(Int32OperandId lhsId
,
3083 Int32OperandId rhsId
) {
3084 return emitInt32BinaryArithResult
<MBitOr
>(lhsId
, rhsId
);
3087 bool WarpCacheIRTranspiler::emitInt32BitXorResult(Int32OperandId lhsId
,
3088 Int32OperandId rhsId
) {
3089 return emitInt32BinaryArithResult
<MBitXor
>(lhsId
, rhsId
);
3092 bool WarpCacheIRTranspiler::emitInt32BitAndResult(Int32OperandId lhsId
,
3093 Int32OperandId rhsId
) {
3094 return emitInt32BinaryArithResult
<MBitAnd
>(lhsId
, rhsId
);
3097 bool WarpCacheIRTranspiler::emitInt32LeftShiftResult(Int32OperandId lhsId
,
3098 Int32OperandId rhsId
) {
3099 return emitInt32BinaryArithResult
<MLsh
>(lhsId
, rhsId
);
3102 bool WarpCacheIRTranspiler::emitInt32RightShiftResult(Int32OperandId lhsId
,
3103 Int32OperandId rhsId
) {
3104 return emitInt32BinaryArithResult
<MRsh
>(lhsId
, rhsId
);
3107 bool WarpCacheIRTranspiler::emitInt32URightShiftResult(Int32OperandId lhsId
,
3108 Int32OperandId rhsId
,
3110 MDefinition
* lhs
= getOperand(lhsId
);
3111 MDefinition
* rhs
= getOperand(rhsId
);
3113 MIRType specialization
= forceDouble
? MIRType::Double
: MIRType::Int32
;
3114 auto* ins
= MUrsh::New(alloc(), lhs
, rhs
, specialization
);
3121 template <typename T
>
3122 bool WarpCacheIRTranspiler::emitBigIntBinaryArithResult(BigIntOperandId lhsId
,
3123 BigIntOperandId rhsId
) {
3124 MDefinition
* lhs
= getOperand(lhsId
);
3125 MDefinition
* rhs
= getOperand(rhsId
);
3127 auto* ins
= T::New(alloc(), lhs
, rhs
);
3134 bool WarpCacheIRTranspiler::emitBigIntAddResult(BigIntOperandId lhsId
,
3135 BigIntOperandId rhsId
) {
3136 return emitBigIntBinaryArithResult
<MBigIntAdd
>(lhsId
, rhsId
);
3139 bool WarpCacheIRTranspiler::emitBigIntSubResult(BigIntOperandId lhsId
,
3140 BigIntOperandId rhsId
) {
3141 return emitBigIntBinaryArithResult
<MBigIntSub
>(lhsId
, rhsId
);
3144 bool WarpCacheIRTranspiler::emitBigIntMulResult(BigIntOperandId lhsId
,
3145 BigIntOperandId rhsId
) {
3146 return emitBigIntBinaryArithResult
<MBigIntMul
>(lhsId
, rhsId
);
3149 template <typename T
>
3150 bool WarpCacheIRTranspiler::emitBigIntBinaryArithEffectfulResult(
3151 BigIntOperandId lhsId
, BigIntOperandId rhsId
) {
3152 MDefinition
* lhs
= getOperand(lhsId
);
3153 MDefinition
* rhs
= getOperand(rhsId
);
3155 auto* ins
= T::New(alloc(), lhs
, rhs
);
3157 if (ins
->isEffectful()) {
3161 return resumeAfter(ins
);
3170 bool WarpCacheIRTranspiler::emitBigIntDivResult(BigIntOperandId lhsId
,
3171 BigIntOperandId rhsId
) {
3172 return emitBigIntBinaryArithEffectfulResult
<MBigIntDiv
>(lhsId
, rhsId
);
3175 bool WarpCacheIRTranspiler::emitBigIntModResult(BigIntOperandId lhsId
,
3176 BigIntOperandId rhsId
) {
3177 return emitBigIntBinaryArithEffectfulResult
<MBigIntMod
>(lhsId
, rhsId
);
3180 bool WarpCacheIRTranspiler::emitBigIntPowResult(BigIntOperandId lhsId
,
3181 BigIntOperandId rhsId
) {
3182 return emitBigIntBinaryArithEffectfulResult
<MBigIntPow
>(lhsId
, rhsId
);
3185 bool WarpCacheIRTranspiler::emitBigIntBitAndResult(BigIntOperandId lhsId
,
3186 BigIntOperandId rhsId
) {
3187 return emitBigIntBinaryArithResult
<MBigIntBitAnd
>(lhsId
, rhsId
);
3190 bool WarpCacheIRTranspiler::emitBigIntBitOrResult(BigIntOperandId lhsId
,
3191 BigIntOperandId rhsId
) {
3192 return emitBigIntBinaryArithResult
<MBigIntBitOr
>(lhsId
, rhsId
);
3195 bool WarpCacheIRTranspiler::emitBigIntBitXorResult(BigIntOperandId lhsId
,
3196 BigIntOperandId rhsId
) {
3197 return emitBigIntBinaryArithResult
<MBigIntBitXor
>(lhsId
, rhsId
);
3200 bool WarpCacheIRTranspiler::emitBigIntLeftShiftResult(BigIntOperandId lhsId
,
3201 BigIntOperandId rhsId
) {
3202 return emitBigIntBinaryArithResult
<MBigIntLsh
>(lhsId
, rhsId
);
3205 bool WarpCacheIRTranspiler::emitBigIntRightShiftResult(BigIntOperandId lhsId
,
3206 BigIntOperandId rhsId
) {
3207 return emitBigIntBinaryArithResult
<MBigIntRsh
>(lhsId
, rhsId
);
3210 template <typename T
>
3211 bool WarpCacheIRTranspiler::emitBigIntUnaryArithResult(
3212 BigIntOperandId inputId
) {
3213 MDefinition
* input
= getOperand(inputId
);
3215 auto* ins
= T::New(alloc(), input
);
3222 bool WarpCacheIRTranspiler::emitBigIntIncResult(BigIntOperandId inputId
) {
3223 return emitBigIntUnaryArithResult
<MBigIntIncrement
>(inputId
);
3226 bool WarpCacheIRTranspiler::emitBigIntDecResult(BigIntOperandId inputId
) {
3227 return emitBigIntUnaryArithResult
<MBigIntDecrement
>(inputId
);
3230 bool WarpCacheIRTranspiler::emitBigIntNegationResult(BigIntOperandId inputId
) {
3231 return emitBigIntUnaryArithResult
<MBigIntNegate
>(inputId
);
3234 bool WarpCacheIRTranspiler::emitBigIntNotResult(BigIntOperandId inputId
) {
3235 return emitBigIntUnaryArithResult
<MBigIntBitNot
>(inputId
);
3238 bool WarpCacheIRTranspiler::emitCallStringConcatResult(StringOperandId lhsId
,
3239 StringOperandId rhsId
) {
3240 MDefinition
* lhs
= getOperand(lhsId
);
3241 MDefinition
* rhs
= getOperand(rhsId
);
3243 auto* ins
= MConcat::New(alloc(), lhs
, rhs
);
3250 bool WarpCacheIRTranspiler::emitCompareResult(
3251 JSOp op
, OperandId lhsId
, OperandId rhsId
,
3252 MCompare::CompareType compareType
) {
3253 MDefinition
* lhs
= getOperand(lhsId
);
3254 MDefinition
* rhs
= getOperand(rhsId
);
3256 auto* ins
= MCompare::New(alloc(), lhs
, rhs
, op
, compareType
);
3263 bool WarpCacheIRTranspiler::emitCompareInt32Result(JSOp op
,
3264 Int32OperandId lhsId
,
3265 Int32OperandId rhsId
) {
3266 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Int32
);
3269 bool WarpCacheIRTranspiler::emitCompareDoubleResult(JSOp op
,
3270 NumberOperandId lhsId
,
3271 NumberOperandId rhsId
) {
3272 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Double
);
3275 bool WarpCacheIRTranspiler::emitCompareObjectResult(JSOp op
, ObjOperandId lhsId
,
3276 ObjOperandId rhsId
) {
3277 MOZ_ASSERT(IsEqualityOp(op
));
3278 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Object
);
3281 bool WarpCacheIRTranspiler::emitCompareStringResult(JSOp op
,
3282 StringOperandId lhsId
,
3283 StringOperandId rhsId
) {
3284 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_String
);
3287 bool WarpCacheIRTranspiler::emitCompareSymbolResult(JSOp op
,
3288 SymbolOperandId lhsId
,
3289 SymbolOperandId rhsId
) {
3290 MOZ_ASSERT(IsEqualityOp(op
));
3291 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Symbol
);
3294 bool WarpCacheIRTranspiler::emitCompareBigIntResult(JSOp op
,
3295 BigIntOperandId lhsId
,
3296 BigIntOperandId rhsId
) {
3297 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt
);
3300 bool WarpCacheIRTranspiler::emitCompareBigIntInt32Result(JSOp op
,
3301 BigIntOperandId lhsId
,
3302 Int32OperandId rhsId
) {
3303 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_Int32
);
3306 bool WarpCacheIRTranspiler::emitCompareBigIntNumberResult(
3307 JSOp op
, BigIntOperandId lhsId
, NumberOperandId rhsId
) {
3308 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_Double
);
3311 bool WarpCacheIRTranspiler::emitCompareBigIntStringResult(
3312 JSOp op
, BigIntOperandId lhsId
, StringOperandId rhsId
) {
3313 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_String
);
3316 bool WarpCacheIRTranspiler::emitCompareNullUndefinedResult(
3317 JSOp op
, bool isUndefined
, ValOperandId inputId
) {
3318 MDefinition
* input
= getOperand(inputId
);
3320 MOZ_ASSERT(IsEqualityOp(op
));
3322 // A previously emitted guard ensures that one side of the comparison
3323 // is null or undefined.
3325 isUndefined
? constant(UndefinedValue()) : constant(NullValue());
3327 isUndefined
? MCompare::Compare_Undefined
: MCompare::Compare_Null
;
3328 auto* ins
= MCompare::New(alloc(), input
, cst
, op
, compareType
);
3335 bool WarpCacheIRTranspiler::emitCompareDoubleSameValueResult(
3336 NumberOperandId lhsId
, NumberOperandId rhsId
) {
3337 MDefinition
* lhs
= getOperand(lhsId
);
3338 MDefinition
* rhs
= getOperand(rhsId
);
3340 auto* sameValue
= MSameValueDouble::New(alloc(), lhs
, rhs
);
3343 pushResult(sameValue
);
3347 bool WarpCacheIRTranspiler::emitSameValueResult(ValOperandId lhsId
,
3348 ValOperandId rhsId
) {
3349 MDefinition
* lhs
= getOperand(lhsId
);
3350 MDefinition
* rhs
= getOperand(rhsId
);
3352 auto* sameValue
= MSameValue::New(alloc(), lhs
, rhs
);
3355 pushResult(sameValue
);
3359 bool WarpCacheIRTranspiler::emitIndirectTruncateInt32Result(
3360 Int32OperandId valId
) {
3361 MDefinition
* val
= getOperand(valId
);
3362 MOZ_ASSERT(val
->type() == MIRType::Int32
);
3365 MLimitedTruncate::New(alloc(), val
, TruncateKind::IndirectTruncate
);
3368 pushResult(truncate
);
3372 bool WarpCacheIRTranspiler::emitMathHypot2NumberResult(
3373 NumberOperandId firstId
, NumberOperandId secondId
) {
3374 MDefinitionVector
vector(alloc());
3375 if (!vector
.reserve(2)) {
3379 vector
.infallibleAppend(getOperand(firstId
));
3380 vector
.infallibleAppend(getOperand(secondId
));
3382 auto* ins
= MHypot::New(alloc(), vector
);
3392 bool WarpCacheIRTranspiler::emitMathHypot3NumberResult(
3393 NumberOperandId firstId
, NumberOperandId secondId
,
3394 NumberOperandId thirdId
) {
3395 MDefinitionVector
vector(alloc());
3396 if (!vector
.reserve(3)) {
3400 vector
.infallibleAppend(getOperand(firstId
));
3401 vector
.infallibleAppend(getOperand(secondId
));
3402 vector
.infallibleAppend(getOperand(thirdId
));
3404 auto* ins
= MHypot::New(alloc(), vector
);
3414 bool WarpCacheIRTranspiler::emitMathHypot4NumberResult(
3415 NumberOperandId firstId
, NumberOperandId secondId
, NumberOperandId thirdId
,
3416 NumberOperandId fourthId
) {
3417 MDefinitionVector
vector(alloc());
3418 if (!vector
.reserve(4)) {
3422 vector
.infallibleAppend(getOperand(firstId
));
3423 vector
.infallibleAppend(getOperand(secondId
));
3424 vector
.infallibleAppend(getOperand(thirdId
));
3425 vector
.infallibleAppend(getOperand(fourthId
));
3427 auto* ins
= MHypot::New(alloc(), vector
);
3437 bool WarpCacheIRTranspiler::emitMathRandomResult(uint32_t rngOffset
) {
3439 // CodeGenerator uses CompileRealm::addressOfRandomNumberGenerator. Assert it
3440 // matches the RNG pointer stored in the stub field.
3441 const void* rng
= rawPointerField(rngOffset
);
3442 MOZ_ASSERT(rng
== mirGen().realm
->addressOfRandomNumberGenerator());
3445 auto* ins
= MRandom::New(alloc());
3449 return resumeAfter(ins
);
3452 bool WarpCacheIRTranspiler::emitInt32MinMax(bool isMax
, Int32OperandId firstId
,
3453 Int32OperandId secondId
,
3454 Int32OperandId resultId
) {
3455 MDefinition
* first
= getOperand(firstId
);
3456 MDefinition
* second
= getOperand(secondId
);
3458 auto* ins
= MMinMax::New(alloc(), first
, second
, MIRType::Int32
, isMax
);
3461 return defineOperand(resultId
, ins
);
3464 bool WarpCacheIRTranspiler::emitNumberMinMax(bool isMax
,
3465 NumberOperandId firstId
,
3466 NumberOperandId secondId
,
3467 NumberOperandId resultId
) {
3468 MDefinition
* first
= getOperand(firstId
);
3469 MDefinition
* second
= getOperand(secondId
);
3471 auto* ins
= MMinMax::New(alloc(), first
, second
, MIRType::Double
, isMax
);
3474 return defineOperand(resultId
, ins
);
3477 bool WarpCacheIRTranspiler::emitInt32MinMaxArrayResult(ObjOperandId arrayId
,
3479 MDefinition
* array
= getOperand(arrayId
);
3481 auto* ins
= MMinMaxArray::New(alloc(), array
, MIRType::Int32
, isMax
);
3488 bool WarpCacheIRTranspiler::emitNumberMinMaxArrayResult(ObjOperandId arrayId
,
3490 MDefinition
* array
= getOperand(arrayId
);
3492 auto* ins
= MMinMaxArray::New(alloc(), array
, MIRType::Double
, isMax
);
3499 bool WarpCacheIRTranspiler::emitMathAbsInt32Result(Int32OperandId inputId
) {
3500 MDefinition
* input
= getOperand(inputId
);
3502 auto* ins
= MAbs::New(alloc(), input
, MIRType::Int32
);
3509 bool WarpCacheIRTranspiler::emitMathAbsNumberResult(NumberOperandId inputId
) {
3510 MDefinition
* input
= getOperand(inputId
);
3512 auto* ins
= MAbs::New(alloc(), input
, MIRType::Double
);
3519 bool WarpCacheIRTranspiler::emitMathClz32Result(Int32OperandId inputId
) {
3520 MDefinition
* input
= getOperand(inputId
);
3522 auto* ins
= MClz::New(alloc(), input
, MIRType::Int32
);
3529 bool WarpCacheIRTranspiler::emitMathSignInt32Result(Int32OperandId inputId
) {
3530 MDefinition
* input
= getOperand(inputId
);
3532 auto* ins
= MSign::New(alloc(), input
, MIRType::Int32
);
3539 bool WarpCacheIRTranspiler::emitMathSignNumberResult(NumberOperandId inputId
) {
3540 MDefinition
* input
= getOperand(inputId
);
3542 auto* ins
= MSign::New(alloc(), input
, MIRType::Double
);
3549 bool WarpCacheIRTranspiler::emitMathSignNumberToInt32Result(
3550 NumberOperandId inputId
) {
3551 MDefinition
* input
= getOperand(inputId
);
3553 auto* ins
= MSign::New(alloc(), input
, MIRType::Int32
);
3560 bool WarpCacheIRTranspiler::emitMathImulResult(Int32OperandId lhsId
,
3561 Int32OperandId rhsId
) {
3562 MDefinition
* lhs
= getOperand(lhsId
);
3563 MDefinition
* rhs
= getOperand(rhsId
);
3565 auto* ins
= MMul::New(alloc(), lhs
, rhs
, MIRType::Int32
, MMul::Integer
);
3572 bool WarpCacheIRTranspiler::emitMathFloorToInt32Result(
3573 NumberOperandId inputId
) {
3574 MDefinition
* input
= getOperand(inputId
);
3576 auto* ins
= MFloor::New(alloc(), input
);
3583 bool WarpCacheIRTranspiler::emitMathCeilToInt32Result(NumberOperandId inputId
) {
3584 MDefinition
* input
= getOperand(inputId
);
3586 auto* ins
= MCeil::New(alloc(), input
);
3593 bool WarpCacheIRTranspiler::emitMathTruncToInt32Result(
3594 NumberOperandId inputId
) {
3595 MDefinition
* input
= getOperand(inputId
);
3597 auto* ins
= MTrunc::New(alloc(), input
);
3604 bool WarpCacheIRTranspiler::emitMathRoundToInt32Result(
3605 NumberOperandId inputId
) {
3606 MDefinition
* input
= getOperand(inputId
);
3608 auto* ins
= MRound::New(alloc(), input
);
3615 bool WarpCacheIRTranspiler::emitMathSqrtNumberResult(NumberOperandId inputId
) {
3616 MDefinition
* input
= getOperand(inputId
);
3618 auto* ins
= MSqrt::New(alloc(), input
, MIRType::Double
);
3625 bool WarpCacheIRTranspiler::emitMathFRoundNumberResult(
3626 NumberOperandId inputId
) {
3627 MDefinition
* input
= getOperand(inputId
);
3629 auto* ins
= MToFloat32::New(alloc(), input
);
3636 bool WarpCacheIRTranspiler::emitMathAtan2NumberResult(NumberOperandId yId
,
3637 NumberOperandId xId
) {
3638 MDefinition
* y
= getOperand(yId
);
3639 MDefinition
* x
= getOperand(xId
);
3641 auto* ins
= MAtan2::New(alloc(), y
, x
);
3648 bool WarpCacheIRTranspiler::emitMathFunctionNumberResult(
3649 NumberOperandId inputId
, UnaryMathFunction fun
) {
3650 MDefinition
* input
= getOperand(inputId
);
3652 auto* ins
= MMathFunction::New(alloc(), input
, fun
);
3659 bool WarpCacheIRTranspiler::emitMathFloorNumberResult(NumberOperandId inputId
) {
3660 MDefinition
* input
= getOperand(inputId
);
3663 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down
)) {
3664 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
, RoundingMode::Down
);
3666 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Floor
);
3674 bool WarpCacheIRTranspiler::emitMathCeilNumberResult(NumberOperandId inputId
) {
3675 MDefinition
* input
= getOperand(inputId
);
3678 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up
)) {
3679 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
, RoundingMode::Up
);
3681 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Ceil
);
3689 bool WarpCacheIRTranspiler::emitMathTruncNumberResult(NumberOperandId inputId
) {
3690 MDefinition
* input
= getOperand(inputId
);
3693 if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero
)) {
3694 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
,
3695 RoundingMode::TowardsZero
);
3697 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Trunc
);
3705 bool WarpCacheIRTranspiler::emitNumberParseIntResult(StringOperandId strId
,
3706 Int32OperandId radixId
) {
3707 MDefinition
* str
= getOperand(strId
);
3708 MDefinition
* radix
= getOperand(radixId
);
3710 auto* ins
= MNumberParseInt::New(alloc(), str
, radix
);
3717 bool WarpCacheIRTranspiler::emitDoubleParseIntResult(NumberOperandId numId
) {
3718 MDefinition
* num
= getOperand(numId
);
3720 auto* ins
= MDoubleParseInt::New(alloc(), num
);
3727 bool WarpCacheIRTranspiler::emitObjectToStringResult(ObjOperandId objId
) {
3728 MDefinition
* obj
= getOperand(objId
);
3730 auto* ins
= MObjectClassToString::New(alloc(), obj
);
3737 bool WarpCacheIRTranspiler::emitReflectGetPrototypeOfResult(
3738 ObjOperandId objId
) {
3739 MDefinition
* obj
= getOperand(objId
);
3741 auto* ins
= MGetPrototypeOf::New(alloc(), obj
);
3745 return resumeAfter(ins
);
3748 bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId
,
3749 ValOperandId rhsId
) {
3750 MDefinition
* obj
= getOperand(objId
);
3751 MDefinition
* value
= getOperand(rhsId
);
3753 auto* ins
= MArrayPush::New(alloc(), obj
, value
);
3757 return resumeAfter(ins
);
3760 bool WarpCacheIRTranspiler::emitArrayJoinResult(ObjOperandId objId
,
3761 StringOperandId sepId
) {
3762 MDefinition
* obj
= getOperand(objId
);
3763 MDefinition
* sep
= getOperand(sepId
);
3765 auto* join
= MArrayJoin::New(alloc(), obj
, sep
);
3769 return resumeAfter(join
);
3772 bool WarpCacheIRTranspiler::emitObjectKeysResult(ObjOperandId objId
) {
3773 MDefinition
* obj
= getOperand(objId
);
3775 auto* join
= MObjectKeys::New(alloc(), obj
);
3779 return resumeAfter(join
);
3782 bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId
) {
3783 MDefinition
* array
= getOperand(arrayId
);
3785 auto* ins
= MArrayPopShift::New(alloc(), array
, MArrayPopShift::Pop
);
3789 return resumeAfter(ins
);
3792 bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId
) {
3793 MDefinition
* array
= getOperand(arrayId
);
3795 auto* ins
= MArrayPopShift::New(alloc(), array
, MArrayPopShift::Shift
);
3799 return resumeAfter(ins
);
3802 bool WarpCacheIRTranspiler::emitPackedArraySliceResult(
3803 uint32_t templateObjectOffset
, ObjOperandId arrayId
, Int32OperandId beginId
,
3804 Int32OperandId endId
) {
3805 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3807 MDefinition
* array
= getOperand(arrayId
);
3808 MDefinition
* begin
= getOperand(beginId
);
3809 MDefinition
* end
= getOperand(endId
);
3811 // TODO: support pre-tenuring.
3812 gc::Heap heap
= gc::Heap::Default
;
3814 auto* ins
= MArraySlice::New(alloc(), array
, begin
, end
, templateObj
, heap
);
3818 return resumeAfter(ins
);
3821 bool WarpCacheIRTranspiler::emitArgumentsSliceResult(
3822 uint32_t templateObjectOffset
, ObjOperandId argsId
, Int32OperandId beginId
,
3823 Int32OperandId endId
) {
3824 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3826 MDefinition
* args
= getOperand(argsId
);
3827 MDefinition
* begin
= getOperand(beginId
);
3828 MDefinition
* end
= getOperand(endId
);
3830 // TODO: support pre-tenuring.
3831 gc::Heap heap
= gc::Heap::Default
;
3834 MArgumentsSlice::New(alloc(), args
, begin
, end
, templateObj
, heap
);
3838 return resumeAfter(ins
);
3841 bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId
,
3842 uint32_t claspOffset
) {
3843 MDefinition
* obj
= getOperand(objId
);
3844 const JSClass
* clasp
= classStubField(claspOffset
);
3846 auto* hasClass
= MHasClass::New(alloc(), obj
, clasp
);
3849 pushResult(hasClass
);
3853 bool WarpCacheIRTranspiler::emitCallRegExpMatcherResult(
3854 ObjOperandId regexpId
, StringOperandId inputId
, Int32OperandId lastIndexId
,
3855 uint32_t stubOffset
) {
3856 MDefinition
* regexp
= getOperand(regexpId
);
3857 MDefinition
* input
= getOperand(inputId
);
3858 MDefinition
* lastIndex
= getOperand(lastIndexId
);
3860 auto* matcher
= MRegExpMatcher::New(alloc(), regexp
, input
, lastIndex
);
3861 addEffectful(matcher
);
3862 pushResult(matcher
);
3864 return resumeAfter(matcher
);
3867 bool WarpCacheIRTranspiler::emitCallRegExpSearcherResult(
3868 ObjOperandId regexpId
, StringOperandId inputId
, Int32OperandId lastIndexId
,
3869 uint32_t stubOffset
) {
3870 MDefinition
* regexp
= getOperand(regexpId
);
3871 MDefinition
* input
= getOperand(inputId
);
3872 MDefinition
* lastIndex
= getOperand(lastIndexId
);
3874 auto* searcher
= MRegExpSearcher::New(alloc(), regexp
, input
, lastIndex
);
3875 addEffectful(searcher
);
3876 pushResult(searcher
);
3878 return resumeAfter(searcher
);
3881 bool WarpCacheIRTranspiler::emitRegExpSearcherLastLimitResult() {
3882 auto* limit
= MRegExpSearcherLastLimit::New(alloc());
3883 addEffectful(limit
);
3886 return resumeAfter(limit
);
3889 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecMatchResult(
3890 ObjOperandId regexpId
, StringOperandId inputId
, uint32_t stubOffset
) {
3891 MDefinition
* regexp
= getOperand(regexpId
);
3892 MDefinition
* input
= getOperand(inputId
);
3894 auto* ins
= MRegExpExecMatch::New(alloc(), regexp
, input
);
3898 return resumeAfter(ins
);
3901 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecTestResult(
3902 ObjOperandId regexpId
, StringOperandId inputId
, uint32_t stubOffset
) {
3903 MDefinition
* regexp
= getOperand(regexpId
);
3904 MDefinition
* input
= getOperand(inputId
);
3906 auto* ins
= MRegExpExecTest::New(alloc(), regexp
, input
);
3910 return resumeAfter(ins
);
3913 bool WarpCacheIRTranspiler::emitRegExpHasCaptureGroupsResult(
3914 ObjOperandId regexpId
, StringOperandId inputId
) {
3915 MDefinition
* regexp
= getOperand(regexpId
);
3916 MDefinition
* input
= getOperand(inputId
);
3918 auto* result
= MRegExpHasCaptureGroups::New(alloc(), regexp
, input
);
3919 addEffectful(result
);
3922 return resumeAfter(result
);
3925 MInstruction
* WarpCacheIRTranspiler::convertToBoolean(MDefinition
* input
) {
3926 // Convert to bool with the '!!' idiom.
3928 // The FoldTests and GVN passes both specifically handle this pattern. If you
3929 // change this code, make sure to update FoldTests and GVN, too.
3931 auto* resultInverted
= MNot::New(alloc(), input
);
3932 add(resultInverted
);
3933 auto* result
= MNot::New(alloc(), resultInverted
);
3939 bool WarpCacheIRTranspiler::emitRegExpFlagResult(ObjOperandId regexpId
,
3940 int32_t flagsMask
) {
3941 MDefinition
* regexp
= getOperand(regexpId
);
3943 auto* flags
= MLoadFixedSlot::New(alloc(), regexp
, RegExpObject::flagsSlot());
3944 flags
->setResultType(MIRType::Int32
);
3947 auto* mask
= MConstant::New(alloc(), Int32Value(flagsMask
));
3950 auto* maskedFlag
= MBitAnd::New(alloc(), flags
, mask
, MIRType::Int32
);
3953 auto* result
= convertToBoolean(maskedFlag
);
3959 bool WarpCacheIRTranspiler::emitCallSubstringKernelResult(
3960 StringOperandId strId
, Int32OperandId beginId
, Int32OperandId lengthId
) {
3961 MDefinition
* str
= getOperand(strId
);
3962 MDefinition
* begin
= getOperand(beginId
);
3963 MDefinition
* length
= getOperand(lengthId
);
3965 auto* substr
= MSubstr::New(alloc(), str
, begin
, length
);
3972 bool WarpCacheIRTranspiler::emitStringReplaceStringResult(
3973 StringOperandId strId
, StringOperandId patternId
,
3974 StringOperandId replacementId
) {
3975 MDefinition
* str
= getOperand(strId
);
3976 MDefinition
* pattern
= getOperand(patternId
);
3977 MDefinition
* replacement
= getOperand(replacementId
);
3979 auto* replace
= MStringReplace::New(alloc(), str
, pattern
, replacement
);
3982 pushResult(replace
);
3986 bool WarpCacheIRTranspiler::emitStringSplitStringResult(
3987 StringOperandId strId
, StringOperandId separatorId
) {
3988 MDefinition
* str
= getOperand(strId
);
3989 MDefinition
* separator
= getOperand(separatorId
);
3991 auto* split
= MStringSplit::New(alloc(), str
, separator
);
3998 bool WarpCacheIRTranspiler::emitRegExpPrototypeOptimizableResult(
3999 ObjOperandId protoId
) {
4000 MDefinition
* proto
= getOperand(protoId
);
4002 auto* optimizable
= MRegExpPrototypeOptimizable::New(alloc(), proto
);
4005 pushResult(optimizable
);
4009 bool WarpCacheIRTranspiler::emitRegExpInstanceOptimizableResult(
4010 ObjOperandId regexpId
, ObjOperandId protoId
) {
4011 MDefinition
* regexp
= getOperand(regexpId
);
4012 MDefinition
* proto
= getOperand(protoId
);
4014 auto* optimizable
= MRegExpInstanceOptimizable::New(alloc(), regexp
, proto
);
4017 pushResult(optimizable
);
4021 bool WarpCacheIRTranspiler::emitGetFirstDollarIndexResult(
4022 StringOperandId strId
) {
4023 MDefinition
* str
= getOperand(strId
);
4025 auto* firstDollarIndex
= MGetFirstDollarIndex::New(alloc(), str
);
4026 add(firstDollarIndex
);
4028 pushResult(firstDollarIndex
);
4032 bool WarpCacheIRTranspiler::emitIsArrayResult(ValOperandId inputId
) {
4033 MDefinition
* value
= getOperand(inputId
);
4035 auto* isArray
= MIsArray::New(alloc(), value
);
4036 addEffectful(isArray
);
4037 pushResult(isArray
);
4039 return resumeAfter(isArray
);
4042 bool WarpCacheIRTranspiler::emitIsObjectResult(ValOperandId inputId
) {
4043 MDefinition
* value
= getOperand(inputId
);
4045 if (value
->type() == MIRType::Object
) {
4046 pushResult(constant(BooleanValue(true)));
4048 auto* isObject
= MIsObject::New(alloc(), value
);
4050 pushResult(isObject
);
4056 bool WarpCacheIRTranspiler::emitIsPackedArrayResult(ObjOperandId objId
) {
4057 MDefinition
* obj
= getOperand(objId
);
4059 auto* isPackedArray
= MIsPackedArray::New(alloc(), obj
);
4062 pushResult(isPackedArray
);
4066 bool WarpCacheIRTranspiler::emitIsCallableResult(ValOperandId inputId
) {
4067 MDefinition
* value
= getOperand(inputId
);
4069 auto* isCallable
= MIsCallable::New(alloc(), value
);
4072 pushResult(isCallable
);
4076 bool WarpCacheIRTranspiler::emitIsConstructorResult(ObjOperandId objId
) {
4077 MDefinition
* obj
= getOperand(objId
);
4079 auto* isConstructor
= MIsConstructor::New(alloc(), obj
);
4082 pushResult(isConstructor
);
4086 bool WarpCacheIRTranspiler::emitIsCrossRealmArrayConstructorResult(
4087 ObjOperandId objId
) {
4088 MDefinition
* obj
= getOperand(objId
);
4090 auto* ins
= MIsCrossRealmArrayConstructor::New(alloc(), obj
);
4097 bool WarpCacheIRTranspiler::emitIsTypedArrayResult(ObjOperandId objId
,
4098 bool isPossiblyWrapped
) {
4099 MDefinition
* obj
= getOperand(objId
);
4101 auto* ins
= MIsTypedArray::New(alloc(), obj
, isPossiblyWrapped
);
4102 if (isPossiblyWrapped
) {
4110 if (isPossiblyWrapped
) {
4111 if (!resumeAfter(ins
)) {
4119 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetInt32Result(
4120 ObjOperandId objId
) {
4121 MDefinition
* obj
= getOperand(objId
);
4123 auto* byteOffset
= MArrayBufferViewByteOffset::New(alloc(), obj
);
4126 auto* byteOffsetInt32
= MNonNegativeIntPtrToInt32::New(alloc(), byteOffset
);
4127 add(byteOffsetInt32
);
4129 pushResult(byteOffsetInt32
);
4133 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetDoubleResult(
4134 ObjOperandId objId
) {
4135 MDefinition
* obj
= getOperand(objId
);
4137 auto* byteOffset
= MArrayBufferViewByteOffset::New(alloc(), obj
);
4140 auto* byteOffsetDouble
= MIntPtrToDouble::New(alloc(), byteOffset
);
4141 add(byteOffsetDouble
);
4143 pushResult(byteOffsetDouble
);
4147 bool WarpCacheIRTranspiler::
4148 emitResizableTypedArrayByteOffsetMaybeOutOfBoundsInt32Result(
4149 ObjOperandId objId
) {
4150 MDefinition
* obj
= getOperand(objId
);
4153 MResizableTypedArrayByteOffsetMaybeOutOfBounds::New(alloc(), obj
);
4156 auto* byteOffsetInt32
= MNonNegativeIntPtrToInt32::New(alloc(), byteOffset
);
4157 add(byteOffsetInt32
);
4159 pushResult(byteOffsetInt32
);
4163 bool WarpCacheIRTranspiler::
4164 emitResizableTypedArrayByteOffsetMaybeOutOfBoundsDoubleResult(
4165 ObjOperandId objId
) {
4166 MDefinition
* obj
= getOperand(objId
);
4169 MResizableTypedArrayByteOffsetMaybeOutOfBounds::New(alloc(), obj
);
4172 auto* byteOffsetDouble
= MIntPtrToDouble::New(alloc(), byteOffset
);
4173 add(byteOffsetDouble
);
4175 pushResult(byteOffsetDouble
);
4179 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthInt32Result(
4180 ObjOperandId objId
) {
4181 MDefinition
* obj
= getOperand(objId
);
4183 // Explicit |length| accesses are seq-consistent atomic loads.
4184 auto barrier
= MemoryBarrierRequirement::Required
;
4186 auto* length
= MResizableTypedArrayLength::New(alloc(), obj
, barrier
);
4187 addEffectful(length
);
4189 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
4192 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthInt32
);
4193 add(postConversion
);
4195 pushResult(postConversion
);
4196 return resumeAfterUnchecked(postConversion
);
4199 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthDoubleResult(
4200 ObjOperandId objId
) {
4201 MDefinition
* obj
= getOperand(objId
);
4203 // Explicit |length| accesses are seq-consistent atomic loads.
4204 auto barrier
= MemoryBarrierRequirement::Required
;
4206 auto* length
= MResizableTypedArrayLength::New(alloc(), obj
, barrier
);
4207 addEffectful(length
);
4209 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
4212 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthDouble
);
4213 add(postConversion
);
4215 pushResult(postConversion
);
4216 return resumeAfterUnchecked(postConversion
);
4219 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthInt32Result(
4220 ObjOperandId objId
) {
4221 MDefinition
* obj
= getOperand(objId
);
4223 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4226 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
4229 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
4232 auto* mul
= MMul::New(alloc(), lengthInt32
, size
, MIRType::Int32
);
4233 mul
->setCanBeNegativeZero(false);
4240 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthDoubleResult(
4241 ObjOperandId objId
) {
4242 MDefinition
* obj
= getOperand(objId
);
4244 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4247 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
4250 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
4253 auto* sizeDouble
= MToDouble::New(alloc(), size
);
4256 auto* mul
= MMul::New(alloc(), lengthDouble
, sizeDouble
, MIRType::Double
);
4257 mul
->setCanBeNegativeZero(false);
4264 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthInt32Result(
4265 ObjOperandId objId
) {
4266 MDefinition
* obj
= getOperand(objId
);
4268 // Explicit |byteLength| accesses are seq-consistent atomic loads.
4269 auto barrier
= MemoryBarrierRequirement::Required
;
4271 auto* length
= MResizableTypedArrayLength::New(alloc(), obj
, barrier
);
4272 addEffectful(length
);
4274 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
4277 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
4280 auto* mul
= MMul::New(alloc(), lengthInt32
, size
, MIRType::Int32
);
4281 mul
->setCanBeNegativeZero(false);
4284 auto* postConversion
= MPostIntPtrConversion::New(alloc(), mul
);
4285 add(postConversion
);
4287 pushResult(postConversion
);
4288 return resumeAfterUnchecked(postConversion
);
4291 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthDoubleResult(
4292 ObjOperandId objId
) {
4293 MDefinition
* obj
= getOperand(objId
);
4295 // Explicit |byteLength| accesses are seq-consistent atomic loads.
4296 auto barrier
= MemoryBarrierRequirement::Required
;
4298 auto* length
= MResizableTypedArrayLength::New(alloc(), obj
, barrier
);
4299 addEffectful(length
);
4301 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
4304 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
4307 auto* sizeDouble
= MToDouble::New(alloc(), size
);
4310 auto* mul
= MMul::New(alloc(), lengthDouble
, sizeDouble
, MIRType::Double
);
4311 mul
->setCanBeNegativeZero(false);
4314 auto* postConversion
= MPostIntPtrConversion::New(alloc(), mul
);
4315 add(postConversion
);
4317 pushResult(postConversion
);
4318 return resumeAfterUnchecked(postConversion
);
4321 bool WarpCacheIRTranspiler::emitTypedArrayElementSizeResult(
4322 ObjOperandId objId
) {
4323 MDefinition
* obj
= getOperand(objId
);
4325 auto* ins
= MTypedArrayElementSize::New(alloc(), obj
);
4332 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthInt32Result(
4333 ObjOperandId objId
) {
4334 MDefinition
* obj
= getOperand(objId
);
4336 // Explicit |byteLength| accesses are seq-consistent atomic loads.
4337 auto barrier
= MemoryBarrierRequirement::Required
;
4339 auto* length
= MResizableDataViewByteLength::New(alloc(), obj
, barrier
);
4340 addEffectful(length
);
4342 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
4345 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthInt32
);
4346 add(postConversion
);
4348 pushResult(postConversion
);
4349 return resumeAfterUnchecked(postConversion
);
4352 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthDoubleResult(
4353 ObjOperandId objId
) {
4354 MDefinition
* obj
= getOperand(objId
);
4356 // Explicit |byteLength| accesses are seq-consistent atomic loads.
4357 auto barrier
= MemoryBarrierRequirement::Required
;
4359 auto* length
= MResizableDataViewByteLength::New(alloc(), obj
, barrier
);
4360 addEffectful(length
);
4362 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
4365 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthDouble
);
4366 add(postConversion
);
4368 pushResult(postConversion
);
4369 return resumeAfterUnchecked(postConversion
);
4372 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthInt32Result(
4373 ObjOperandId objId
) {
4374 MDefinition
* obj
= getOperand(objId
);
4376 auto* length
= MGrowableSharedArrayBufferByteLength::New(alloc(), obj
);
4377 addEffectful(length
);
4379 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
4382 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthInt32
);
4383 add(postConversion
);
4385 pushResult(postConversion
);
4386 return resumeAfterUnchecked(postConversion
);
4389 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthDoubleResult(
4390 ObjOperandId objId
) {
4391 MDefinition
* obj
= getOperand(objId
);
4393 auto* length
= MGrowableSharedArrayBufferByteLength::New(alloc(), obj
);
4394 addEffectful(length
);
4396 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
4399 auto* postConversion
= MPostIntPtrConversion::New(alloc(), lengthDouble
);
4400 add(postConversion
);
4402 pushResult(postConversion
);
4403 return resumeAfterUnchecked(postConversion
);
4406 bool WarpCacheIRTranspiler::emitGuardHasAttachedArrayBuffer(
4407 ObjOperandId objId
) {
4408 MDefinition
* obj
= getOperand(objId
);
4410 auto* ins
= MGuardHasAttachedArrayBuffer::New(alloc(), obj
);
4413 setOperand(objId
, ins
);
4417 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBounds(
4418 ObjOperandId objId
) {
4419 MDefinition
* obj
= getOperand(objId
);
4421 auto* ins
= MGuardResizableArrayBufferViewInBounds::New(alloc(), obj
);
4424 setOperand(objId
, ins
);
4428 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBoundsOrDetached(
4429 ObjOperandId objId
) {
4430 MDefinition
* obj
= getOperand(objId
);
4433 MGuardResizableArrayBufferViewInBoundsOrDetached::New(alloc(), obj
);
4436 setOperand(objId
, ins
);
4440 bool WarpCacheIRTranspiler::emitIsTypedArrayConstructorResult(
4441 ObjOperandId objId
) {
4442 MDefinition
* obj
= getOperand(objId
);
4444 auto* ins
= MIsTypedArrayConstructor::New(alloc(), obj
);
4451 bool WarpCacheIRTranspiler::emitGetNextMapSetEntryForIteratorResult(
4452 ObjOperandId iterId
, ObjOperandId resultArrId
, bool isMap
) {
4453 MDefinition
* iter
= getOperand(iterId
);
4454 MDefinition
* resultArr
= getOperand(resultArrId
);
4456 MGetNextEntryForIterator::Mode mode
=
4457 isMap
? MGetNextEntryForIterator::Map
: MGetNextEntryForIterator::Set
;
4458 auto* ins
= MGetNextEntryForIterator::New(alloc(), iter
, resultArr
, mode
);
4462 return resumeAfter(ins
);
4465 bool WarpCacheIRTranspiler::emitFrameIsConstructingResult() {
4466 if (const CallInfo
* callInfo
= builder_
->inlineCallInfo()) {
4467 auto* ins
= constant(BooleanValue(callInfo
->constructing()));
4472 auto* ins
= MIsConstructing::New(alloc());
4478 bool WarpCacheIRTranspiler::emitNewIteratorResult(
4479 MNewIterator::Type type
, uint32_t templateObjectOffset
) {
4480 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4482 auto* templateConst
= constant(ObjectValue(*templateObj
));
4483 auto* iter
= MNewIterator::New(alloc(), templateConst
, type
);
4490 bool WarpCacheIRTranspiler::emitNewArrayIteratorResult(
4491 uint32_t templateObjectOffset
) {
4492 return emitNewIteratorResult(MNewIterator::ArrayIterator
,
4493 templateObjectOffset
);
4496 bool WarpCacheIRTranspiler::emitNewStringIteratorResult(
4497 uint32_t templateObjectOffset
) {
4498 return emitNewIteratorResult(MNewIterator::StringIterator
,
4499 templateObjectOffset
);
4502 bool WarpCacheIRTranspiler::emitNewRegExpStringIteratorResult(
4503 uint32_t templateObjectOffset
) {
4504 return emitNewIteratorResult(MNewIterator::RegExpStringIterator
,
4505 templateObjectOffset
);
4508 bool WarpCacheIRTranspiler::emitObjectCreateResult(
4509 uint32_t templateObjectOffset
) {
4510 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4512 auto* templateConst
= constant(ObjectValue(*templateObj
));
4514 // TODO: support pre-tenuring.
4515 gc::Heap heap
= gc::Heap::Default
;
4517 MNewObject::New(alloc(), templateConst
, heap
, MNewObject::ObjectCreate
);
4521 return resumeAfter(obj
);
4524 bool WarpCacheIRTranspiler::emitNewArrayFromLengthResult(
4525 uint32_t templateObjectOffset
, Int32OperandId lengthId
) {
4526 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4527 MDefinition
* length
= getOperand(lengthId
);
4529 // TODO: support pre-tenuring.
4530 gc::Heap heap
= gc::Heap::Default
;
4532 if (length
->isConstant()) {
4533 int32_t lenInt32
= length
->toConstant()->toInt32();
4534 if (lenInt32
>= 0 &&
4535 uint32_t(lenInt32
) == templateObj
->as
<ArrayObject
>().length()) {
4536 uint32_t len
= uint32_t(lenInt32
);
4537 auto* templateConst
= constant(ObjectValue(*templateObj
));
4539 size_t inlineLength
=
4540 gc::GetGCKindSlots(templateObj
->asTenured().getAllocKind()) -
4541 ObjectElements::VALUES_PER_HEADER
;
4544 if (len
> inlineLength
) {
4545 obj
= MNewArray::NewVM(alloc(), len
, templateConst
, heap
);
4547 obj
= MNewArray::New(alloc(), len
, templateConst
, heap
);
4555 auto* obj
= MNewArrayDynamicLength::New(alloc(), length
, templateObj
, heap
);
4558 return resumeAfter(obj
);
4561 bool WarpCacheIRTranspiler::emitNewTypedArrayFromLengthResult(
4562 uint32_t templateObjectOffset
, Int32OperandId lengthId
) {
4563 auto* templateObj
= &tenuredObjectStubField(templateObjectOffset
)
4564 ->as
<FixedLengthTypedArrayObject
>();
4565 MDefinition
* length
= getOperand(lengthId
);
4567 // TODO: support pre-tenuring.
4568 gc::Heap heap
= gc::Heap::Default
;
4570 if (length
->isConstant()) {
4571 int32_t len
= length
->toConstant()->toInt32();
4572 if (len
> 0 && uint32_t(len
) == templateObj
->length()) {
4573 auto* templateConst
= constant(ObjectValue(*templateObj
));
4574 auto* obj
= MNewTypedArray::New(alloc(), templateConst
, heap
);
4582 MNewTypedArrayDynamicLength::New(alloc(), length
, templateObj
, heap
);
4585 return resumeAfter(obj
);
4588 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayBufferResult(
4589 uint32_t templateObjectOffset
, ObjOperandId bufferId
,
4590 ValOperandId byteOffsetId
, ValOperandId lengthId
) {
4591 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4592 MDefinition
* buffer
= getOperand(bufferId
);
4593 MDefinition
* byteOffset
= getOperand(byteOffsetId
);
4594 MDefinition
* length
= getOperand(lengthId
);
4596 // TODO: support pre-tenuring.
4597 gc::Heap heap
= gc::Heap::Default
;
4599 auto* obj
= MNewTypedArrayFromArrayBuffer::New(alloc(), buffer
, byteOffset
,
4600 length
, templateObj
, heap
);
4604 return resumeAfter(obj
);
4607 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayResult(
4608 uint32_t templateObjectOffset
, ObjOperandId arrayId
) {
4609 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4610 MDefinition
* array
= getOperand(arrayId
);
4612 // TODO: support pre-tenuring.
4613 gc::Heap heap
= gc::Heap::Default
;
4615 auto* obj
= MNewTypedArrayFromArray::New(alloc(), array
, templateObj
, heap
);
4619 return resumeAfter(obj
);
4622 bool WarpCacheIRTranspiler::emitAtomicsCompareExchangeResult(
4623 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t expectedId
,
4624 uint32_t replacementId
, Scalar::Type elementType
,
4625 ArrayBufferViewKind viewKind
) {
4626 MDefinition
* obj
= getOperand(objId
);
4627 MDefinition
* index
= getOperand(indexId
);
4628 MDefinition
* expected
= getOperand(ValOperandId(expectedId
));
4629 MDefinition
* replacement
= getOperand(ValOperandId(replacementId
));
4631 auto* length
= emitTypedArrayLength(viewKind
, obj
);
4633 index
= addBoundsCheck(index
, length
);
4635 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4638 bool forceDoubleForUint32
= true;
4640 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4642 auto* cas
= MCompareExchangeTypedArrayElement::New(
4643 alloc(), elements
, index
, elementType
, expected
, replacement
);
4644 cas
->setResultType(knownType
);
4648 return resumeAfter(cas
);
4651 bool WarpCacheIRTranspiler::emitAtomicsExchangeResult(
4652 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4653 Scalar::Type elementType
, ArrayBufferViewKind viewKind
) {
4654 MDefinition
* obj
= getOperand(objId
);
4655 MDefinition
* index
= getOperand(indexId
);
4656 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4658 auto* length
= emitTypedArrayLength(viewKind
, obj
);
4660 index
= addBoundsCheck(index
, length
);
4662 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4665 bool forceDoubleForUint32
= true;
4667 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4669 auto* exchange
= MAtomicExchangeTypedArrayElement::New(
4670 alloc(), elements
, index
, value
, elementType
);
4671 exchange
->setResultType(knownType
);
4672 addEffectful(exchange
);
4674 pushResult(exchange
);
4675 return resumeAfter(exchange
);
4678 bool WarpCacheIRTranspiler::emitAtomicsBinaryOp(
4679 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4680 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
,
4682 MDefinition
* obj
= getOperand(objId
);
4683 MDefinition
* index
= getOperand(indexId
);
4684 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4686 auto* length
= emitTypedArrayLength(viewKind
, obj
);
4688 index
= addBoundsCheck(index
, length
);
4690 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4693 bool forceDoubleForUint32
= true;
4695 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4697 auto* binop
= MAtomicTypedArrayElementBinop::New(
4698 alloc(), op
, elements
, index
, elementType
, value
, forEffect
);
4700 binop
->setResultType(knownType
);
4702 addEffectful(binop
);
4707 pushResult(constant(UndefinedValue()));
4709 return resumeAfter(binop
);
4712 bool WarpCacheIRTranspiler::emitAtomicsAddResult(
4713 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4714 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
) {
4715 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4716 viewKind
, AtomicOp::Add
);
4719 bool WarpCacheIRTranspiler::emitAtomicsSubResult(
4720 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4721 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
) {
4722 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4723 viewKind
, AtomicOp::Sub
);
4726 bool WarpCacheIRTranspiler::emitAtomicsAndResult(
4727 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4728 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
) {
4729 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4730 viewKind
, AtomicOp::And
);
4733 bool WarpCacheIRTranspiler::emitAtomicsOrResult(
4734 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4735 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
) {
4736 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4737 viewKind
, AtomicOp::Or
);
4740 bool WarpCacheIRTranspiler::emitAtomicsXorResult(
4741 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4742 Scalar::Type elementType
, bool forEffect
, ArrayBufferViewKind viewKind
) {
4743 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4744 viewKind
, AtomicOp::Xor
);
4747 bool WarpCacheIRTranspiler::emitAtomicsLoadResult(
4748 ObjOperandId objId
, IntPtrOperandId indexId
, Scalar::Type elementType
,
4749 ArrayBufferViewKind viewKind
) {
4750 MDefinition
* obj
= getOperand(objId
);
4751 MDefinition
* index
= getOperand(indexId
);
4753 auto* length
= emitTypedArrayLength(viewKind
, obj
);
4755 index
= addBoundsCheck(index
, length
);
4757 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4760 bool forceDoubleForUint32
= true;
4762 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4764 auto* load
= MLoadUnboxedScalar::New(alloc(), elements
, index
, elementType
,
4765 MemoryBarrierRequirement::Required
);
4766 load
->setResultType(knownType
);
4770 return resumeAfter(load
);
4773 bool WarpCacheIRTranspiler::emitAtomicsStoreResult(
4774 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4775 Scalar::Type elementType
, ArrayBufferViewKind viewKind
) {
4776 MDefinition
* obj
= getOperand(objId
);
4777 MDefinition
* index
= getOperand(indexId
);
4778 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4780 auto* length
= emitTypedArrayLength(viewKind
, obj
);
4782 index
= addBoundsCheck(index
, length
);
4784 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4788 MStoreUnboxedScalar::New(alloc(), elements
, index
, value
, elementType
,
4789 MemoryBarrierRequirement::Required
);
4790 addEffectful(store
);
4793 return resumeAfter(store
);
4796 bool WarpCacheIRTranspiler::emitAtomicsIsLockFreeResult(
4797 Int32OperandId valueId
) {
4798 MDefinition
* value
= getOperand(valueId
);
4800 auto* ilf
= MAtomicIsLockFree::New(alloc(), value
);
4807 bool WarpCacheIRTranspiler::emitBigIntAsIntNResult(Int32OperandId bitsId
,
4808 BigIntOperandId bigIntId
) {
4809 MDefinition
* bits
= getOperand(bitsId
);
4810 MDefinition
* bigInt
= getOperand(bigIntId
);
4812 auto* ins
= MBigIntAsIntN::New(alloc(), bits
, bigInt
);
4819 bool WarpCacheIRTranspiler::emitBigIntAsUintNResult(Int32OperandId bitsId
,
4820 BigIntOperandId bigIntId
) {
4821 MDefinition
* bits
= getOperand(bitsId
);
4822 MDefinition
* bigInt
= getOperand(bigIntId
);
4824 auto* ins
= MBigIntAsUintN::New(alloc(), bits
, bigInt
);
4831 bool WarpCacheIRTranspiler::emitGuardToNonGCThing(ValOperandId inputId
) {
4832 MDefinition
* def
= getOperand(inputId
);
4833 if (IsNonGCThing(def
->type())) {
4837 auto* ins
= MGuardNonGCThing::New(alloc(), def
);
4840 setOperand(inputId
, ins
);
4844 bool WarpCacheIRTranspiler::emitSetHasNonGCThingResult(ObjOperandId setId
,
4845 ValOperandId valId
) {
4846 MDefinition
* set
= getOperand(setId
);
4847 MDefinition
* val
= getOperand(valId
);
4849 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
4852 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
4855 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, hashValue
, hash
);
4862 bool WarpCacheIRTranspiler::emitSetHasStringResult(ObjOperandId setId
,
4863 StringOperandId strId
) {
4864 MDefinition
* set
= getOperand(setId
);
4865 MDefinition
* str
= getOperand(strId
);
4867 auto* hashValue
= MToHashableString::New(alloc(), str
);
4870 auto* hash
= MHashString::New(alloc(), hashValue
);
4873 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, hashValue
, hash
);
4880 bool WarpCacheIRTranspiler::emitSetHasSymbolResult(ObjOperandId setId
,
4881 SymbolOperandId symId
) {
4882 MDefinition
* set
= getOperand(setId
);
4883 MDefinition
* sym
= getOperand(symId
);
4885 auto* hash
= MHashSymbol::New(alloc(), sym
);
4888 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, sym
, hash
);
4895 bool WarpCacheIRTranspiler::emitSetHasBigIntResult(ObjOperandId setId
,
4896 BigIntOperandId bigIntId
) {
4897 MDefinition
* set
= getOperand(setId
);
4898 MDefinition
* bigInt
= getOperand(bigIntId
);
4900 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
4903 auto* ins
= MSetObjectHasBigInt::New(alloc(), set
, bigInt
, hash
);
4910 bool WarpCacheIRTranspiler::emitSetHasObjectResult(ObjOperandId setId
,
4911 ObjOperandId objId
) {
4912 MDefinition
* set
= getOperand(setId
);
4913 MDefinition
* obj
= getOperand(objId
);
4915 auto* hash
= MHashObject::New(alloc(), set
, obj
);
4918 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, obj
, hash
);
4925 bool WarpCacheIRTranspiler::emitSetHasResult(ObjOperandId setId
,
4926 ValOperandId valId
) {
4927 MDefinition
* set
= getOperand(setId
);
4928 MDefinition
* val
= getOperand(valId
);
4931 auto* hashValue
= MToHashableValue::New(alloc(), val
);
4934 auto* hash
= MHashValue::New(alloc(), set
, hashValue
);
4937 auto* ins
= MSetObjectHasValue::New(alloc(), set
, hashValue
, hash
);
4940 auto* ins
= MSetObjectHasValueVMCall::New(alloc(), set
, val
);
4948 bool WarpCacheIRTranspiler::emitSetSizeResult(ObjOperandId setId
) {
4949 MDefinition
* set
= getOperand(setId
);
4951 auto* ins
= MSetObjectSize::New(alloc(), set
);
4958 bool WarpCacheIRTranspiler::emitMapHasNonGCThingResult(ObjOperandId mapId
,
4959 ValOperandId valId
) {
4960 MDefinition
* map
= getOperand(mapId
);
4961 MDefinition
* val
= getOperand(valId
);
4963 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
4966 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
4969 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, hashValue
, hash
);
4976 bool WarpCacheIRTranspiler::emitMapHasStringResult(ObjOperandId mapId
,
4977 StringOperandId strId
) {
4978 MDefinition
* map
= getOperand(mapId
);
4979 MDefinition
* str
= getOperand(strId
);
4981 auto* hashValue
= MToHashableString::New(alloc(), str
);
4984 auto* hash
= MHashString::New(alloc(), hashValue
);
4987 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, hashValue
, hash
);
4994 bool WarpCacheIRTranspiler::emitMapHasSymbolResult(ObjOperandId mapId
,
4995 SymbolOperandId symId
) {
4996 MDefinition
* map
= getOperand(mapId
);
4997 MDefinition
* sym
= getOperand(symId
);
4999 auto* hash
= MHashSymbol::New(alloc(), sym
);
5002 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, sym
, hash
);
5009 bool WarpCacheIRTranspiler::emitMapHasBigIntResult(ObjOperandId mapId
,
5010 BigIntOperandId bigIntId
) {
5011 MDefinition
* map
= getOperand(mapId
);
5012 MDefinition
* bigInt
= getOperand(bigIntId
);
5014 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
5017 auto* ins
= MMapObjectHasBigInt::New(alloc(), map
, bigInt
, hash
);
5024 bool WarpCacheIRTranspiler::emitMapHasObjectResult(ObjOperandId mapId
,
5025 ObjOperandId objId
) {
5026 MDefinition
* map
= getOperand(mapId
);
5027 MDefinition
* obj
= getOperand(objId
);
5029 auto* hash
= MHashObject::New(alloc(), map
, obj
);
5032 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, obj
, hash
);
5039 bool WarpCacheIRTranspiler::emitMapHasResult(ObjOperandId mapId
,
5040 ValOperandId valId
) {
5041 MDefinition
* map
= getOperand(mapId
);
5042 MDefinition
* val
= getOperand(valId
);
5045 auto* hashValue
= MToHashableValue::New(alloc(), val
);
5048 auto* hash
= MHashValue::New(alloc(), map
, hashValue
);
5051 auto* ins
= MMapObjectHasValue::New(alloc(), map
, hashValue
, hash
);
5054 auto* ins
= MMapObjectHasValueVMCall::New(alloc(), map
, val
);
5062 bool WarpCacheIRTranspiler::emitMapGetNonGCThingResult(ObjOperandId mapId
,
5063 ValOperandId valId
) {
5064 MDefinition
* map
= getOperand(mapId
);
5065 MDefinition
* val
= getOperand(valId
);
5067 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
5070 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
5073 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, hashValue
, hash
);
5080 bool WarpCacheIRTranspiler::emitMapGetStringResult(ObjOperandId mapId
,
5081 StringOperandId strId
) {
5082 MDefinition
* map
= getOperand(mapId
);
5083 MDefinition
* str
= getOperand(strId
);
5085 auto* hashValue
= MToHashableString::New(alloc(), str
);
5088 auto* hash
= MHashString::New(alloc(), hashValue
);
5091 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, hashValue
, hash
);
5098 bool WarpCacheIRTranspiler::emitMapGetSymbolResult(ObjOperandId mapId
,
5099 SymbolOperandId symId
) {
5100 MDefinition
* map
= getOperand(mapId
);
5101 MDefinition
* sym
= getOperand(symId
);
5103 auto* hash
= MHashSymbol::New(alloc(), sym
);
5106 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, sym
, hash
);
5113 bool WarpCacheIRTranspiler::emitMapGetBigIntResult(ObjOperandId mapId
,
5114 BigIntOperandId bigIntId
) {
5115 MDefinition
* map
= getOperand(mapId
);
5116 MDefinition
* bigInt
= getOperand(bigIntId
);
5118 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
5121 auto* ins
= MMapObjectGetBigInt::New(alloc(), map
, bigInt
, hash
);
5128 bool WarpCacheIRTranspiler::emitMapGetObjectResult(ObjOperandId mapId
,
5129 ObjOperandId objId
) {
5130 MDefinition
* map
= getOperand(mapId
);
5131 MDefinition
* obj
= getOperand(objId
);
5133 auto* hash
= MHashObject::New(alloc(), map
, obj
);
5136 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, obj
, hash
);
5143 bool WarpCacheIRTranspiler::emitMapGetResult(ObjOperandId mapId
,
5144 ValOperandId valId
) {
5145 MDefinition
* map
= getOperand(mapId
);
5146 MDefinition
* val
= getOperand(valId
);
5149 auto* hashValue
= MToHashableValue::New(alloc(), val
);
5152 auto* hash
= MHashValue::New(alloc(), map
, hashValue
);
5155 auto* ins
= MMapObjectGetValue::New(alloc(), map
, hashValue
, hash
);
5158 auto* ins
= MMapObjectGetValueVMCall::New(alloc(), map
, val
);
5166 bool WarpCacheIRTranspiler::emitMapSizeResult(ObjOperandId mapId
) {
5167 MDefinition
* map
= getOperand(mapId
);
5169 auto* ins
= MMapObjectSize::New(alloc(), map
);
5176 bool WarpCacheIRTranspiler::emitTruthyResult(OperandId inputId
) {
5177 MDefinition
* input
= getOperand(inputId
);
5179 auto* result
= convertToBoolean(input
);
5185 bool WarpCacheIRTranspiler::emitLoadInt32TruthyResult(ValOperandId inputId
) {
5186 return emitTruthyResult(inputId
);
5189 bool WarpCacheIRTranspiler::emitLoadDoubleTruthyResult(
5190 NumberOperandId inputId
) {
5191 return emitTruthyResult(inputId
);
5194 bool WarpCacheIRTranspiler::emitLoadStringTruthyResult(
5195 StringOperandId inputId
) {
5196 return emitTruthyResult(inputId
);
5199 bool WarpCacheIRTranspiler::emitLoadObjectTruthyResult(ObjOperandId inputId
) {
5200 return emitTruthyResult(inputId
);
5203 bool WarpCacheIRTranspiler::emitLoadBigIntTruthyResult(
5204 BigIntOperandId inputId
) {
5205 return emitTruthyResult(inputId
);
5208 bool WarpCacheIRTranspiler::emitLoadValueTruthyResult(ValOperandId inputId
) {
5209 return emitTruthyResult(inputId
);
5212 bool WarpCacheIRTranspiler::emitLoadOperandResult(ValOperandId inputId
) {
5213 MDefinition
* input
= getOperand(inputId
);
5218 bool WarpCacheIRTranspiler::emitLoadWrapperTarget(ObjOperandId objId
,
5219 ObjOperandId resultId
,
5221 MDefinition
* obj
= getOperand(objId
);
5223 auto* ins
= MLoadWrapperTarget::New(alloc(), obj
, fallible
);
5229 return defineOperand(resultId
, ins
);
5232 // When we transpile a call, we may generate guards for some
5233 // arguments. To make sure the call instruction depends on those
5234 // guards, when the transpiler creates an operand for an argument, we
5235 // register the OperandId of that argument in argumentIds_. (See
5236 // emitLoadArgumentSlot.) Before generating the call, we update the
5237 // CallInfo to use the appropriate value from operands_.
5238 // Note: The callee is an explicit argument to the call op, and is
5239 // tracked separately.
5240 void WarpCacheIRTranspiler::updateArgumentsFromOperands() {
5241 for (uint32_t i
= 0; i
< uint32_t(ArgumentKind::NumKinds
); i
++) {
5242 ArgumentKind kind
= ArgumentKind(i
);
5243 OperandId id
= argumentOperandIds_
[kind
];
5246 case ArgumentKind::This
:
5247 callInfo_
->setThis(getOperand(id
));
5249 case ArgumentKind::NewTarget
:
5250 callInfo_
->setNewTarget(getOperand(id
));
5252 case ArgumentKind::Arg0
:
5253 callInfo_
->setArg(0, getOperand(id
));
5255 case ArgumentKind::Arg1
:
5256 callInfo_
->setArg(1, getOperand(id
));
5258 case ArgumentKind::Arg2
:
5259 callInfo_
->setArg(2, getOperand(id
));
5261 case ArgumentKind::Arg3
:
5262 callInfo_
->setArg(3, getOperand(id
));
5264 case ArgumentKind::Arg4
:
5265 callInfo_
->setArg(4, getOperand(id
));
5267 case ArgumentKind::Arg5
:
5268 callInfo_
->setArg(5, getOperand(id
));
5270 case ArgumentKind::Arg6
:
5271 callInfo_
->setArg(6, getOperand(id
));
5273 case ArgumentKind::Arg7
:
5274 callInfo_
->setArg(7, getOperand(id
));
5276 case ArgumentKind::Callee
:
5277 case ArgumentKind::NumKinds
:
5278 MOZ_CRASH("Unexpected argument kind");
5284 bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId
,
5285 uint32_t slotIndex
) {
5286 // Reverse of GetIndexOfArgument.
5289 // NewTarget | Args.. (reversed) | ThisValue | Callee
5290 // 0 | ArgC .. Arg1 Arg0 (+1) | argc (+1) | argc + 1 (+ 1)
5291 // ^ (if constructing)
5293 // NewTarget (optional)
5294 if (callInfo_
->constructing()) {
5295 if (slotIndex
== 0) {
5296 setArgumentId(ArgumentKind::NewTarget
, resultId
);
5297 return defineOperand(resultId
, callInfo_
->getNewTarget());
5300 slotIndex
-= 1; // Adjust slot index to match non-constructing calls.
5304 if (slotIndex
< callInfo_
->argc()) {
5305 uint32_t arg
= callInfo_
->argc() - 1 - slotIndex
;
5306 ArgumentKind kind
= ArgumentKindForArgIndex(arg
);
5307 MOZ_ASSERT(kind
< ArgumentKind::NumKinds
);
5308 setArgumentId(kind
, resultId
);
5309 return defineOperand(resultId
, callInfo_
->getArg(arg
));
5313 if (slotIndex
== callInfo_
->argc()) {
5314 setArgumentId(ArgumentKind::This
, resultId
);
5315 return defineOperand(resultId
, callInfo_
->thisArg());
5319 MOZ_ASSERT(slotIndex
== callInfo_
->argc() + 1);
5320 return defineOperand(resultId
, callInfo_
->callee());
5323 bool WarpCacheIRTranspiler::emitLoadArgumentFixedSlot(ValOperandId resultId
,
5324 uint8_t slotIndex
) {
5325 return emitLoadArgumentSlot(resultId
, slotIndex
);
5328 bool WarpCacheIRTranspiler::emitLoadArgumentDynamicSlot(ValOperandId resultId
,
5329 Int32OperandId argcId
,
5330 uint8_t slotIndex
) {
5332 MDefinition
* argc
= getOperand(argcId
);
5333 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5334 static_cast<int32_t>(callInfo_
->argc()));
5337 return emitLoadArgumentSlot(resultId
, callInfo_
->argc() + slotIndex
);
5340 WrappedFunction
* WarpCacheIRTranspiler::maybeWrappedFunction(
5341 MDefinition
* callee
, CallKind kind
, uint16_t nargs
, FunctionFlags flags
) {
5342 MOZ_ASSERT(callee
->isConstant() || callee
->isNurseryObject());
5344 // If this is a native without a JitEntry, WrappedFunction needs to know the
5345 // target JSFunction.
5346 // TODO: support nursery-allocated natives with WrappedFunction, maybe by
5347 // storing the JSNative in the Baseline stub like flags/nargs.
5348 bool isNative
= flags
.isNativeWithoutJitEntry();
5349 if (isNative
&& !callee
->isConstant()) {
5353 JSFunction
* nativeTarget
= nullptr;
5355 nativeTarget
= &callee
->toConstant()->toObject().as
<JSFunction
>();
5358 WrappedFunction
* wrappedTarget
=
5359 new (alloc()) WrappedFunction(nativeTarget
, nargs
, flags
);
5360 MOZ_ASSERT_IF(kind
== CallKind::Native
|| kind
== CallKind::DOM
,
5361 wrappedTarget
->isNativeWithoutJitEntry());
5362 MOZ_ASSERT_IF(kind
== CallKind::Scripted
, wrappedTarget
->hasJitEntry());
5363 return wrappedTarget
;
5366 WrappedFunction
* WarpCacheIRTranspiler::maybeCallTarget(MDefinition
* callee
,
5368 // CacheIR emits the following for specialized calls:
5369 // GuardSpecificFunction <callee> <func> ..
5370 // Call(Native|Scripted)Function <callee> ..
5372 // GuardClass <callee> ..
5373 // GuardFunctionScript <callee> <script> ..
5374 // CallScriptedFunction <callee> ..
5376 // We can use the <func> JSFunction or <script> BaseScript to specialize this
5378 if (callee
->isGuardSpecificFunction()) {
5379 auto* guard
= callee
->toGuardSpecificFunction();
5380 return maybeWrappedFunction(guard
->expected(), kind
, guard
->nargs(),
5383 if (callee
->isGuardFunctionScript()) {
5384 MOZ_ASSERT(kind
== CallKind::Scripted
);
5385 auto* guard
= callee
->toGuardFunctionScript();
5386 WrappedFunction
* wrappedTarget
= new (alloc()) WrappedFunction(
5387 /* nativeFun = */ nullptr, guard
->nargs(), guard
->flags());
5388 MOZ_ASSERT(wrappedTarget
->hasJitEntry());
5389 return wrappedTarget
;
5394 // If it is possible to use MCall for this call, update callInfo_ to use
5395 // the correct arguments. Otherwise, update the ArgFormat of callInfo_.
5396 bool WarpCacheIRTranspiler::updateCallInfo(MDefinition
* callee
,
5398 // The transpilation will add various guards to the callee.
5399 // We replace the callee referenced by the CallInfo, so that
5400 // the resulting call instruction depends on these guards.
5401 callInfo_
->setCallee(callee
);
5403 // The transpilation may also add guards to other arguments.
5404 // We replace those arguments in the CallInfo here.
5405 updateArgumentsFromOperands();
5407 switch (flags
.getArgFormat()) {
5408 case CallFlags::Standard
:
5409 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5411 case CallFlags::Spread
:
5412 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Array
);
5414 case CallFlags::FunCall
:
5415 // Note: We already changed the callee to the target
5416 // function instead of the |call| function.
5417 MOZ_ASSERT(!callInfo_
->constructing());
5418 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5420 if (callInfo_
->argc() == 0) {
5421 // Special case for fun.call() with no arguments.
5422 auto* undef
= constant(UndefinedValue());
5423 callInfo_
->setThis(undef
);
5425 // The first argument for |call| is the new this value.
5426 callInfo_
->setThis(callInfo_
->getArg(0));
5428 // Shift down all other arguments by removing the first.
5429 callInfo_
->removeArg(0);
5432 case CallFlags::FunApplyArgsObj
:
5433 MOZ_ASSERT(!callInfo_
->constructing());
5434 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5436 callInfo_
->setArgFormat(CallInfo::ArgFormat::FunApplyArgsObj
);
5438 case CallFlags::FunApplyArray
: {
5439 MDefinition
* argFunc
= callInfo_
->thisArg();
5440 MDefinition
* argThis
= callInfo_
->getArg(0);
5441 callInfo_
->setCallee(argFunc
);
5442 callInfo_
->setThis(argThis
);
5443 callInfo_
->setArgFormat(CallInfo::ArgFormat::Array
);
5446 case CallFlags::FunApplyNullUndefined
:
5447 // Note: We already changed the callee to the target
5448 // function instead of the |apply| function.
5449 MOZ_ASSERT(callInfo_
->argc() == 2);
5450 MOZ_ASSERT(!callInfo_
->constructing());
5451 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5452 callInfo_
->setThis(callInfo_
->getArg(0));
5453 callInfo_
->getArg(1)->setImplicitlyUsedUnchecked();
5454 callInfo_
->removeArg(1);
5455 callInfo_
->removeArg(0);
5458 MOZ_CRASH("Unsupported arg format");
5463 // Returns true if we are generating a call to CreateThisFromIon and
5464 // must check its return value.
5465 bool WarpCacheIRTranspiler::maybeCreateThis(MDefinition
* callee
,
5466 CallFlags flags
, CallKind kind
) {
5467 MOZ_ASSERT(kind
!= CallKind::DOM
, "DOM functions are not constructors");
5468 MDefinition
* thisArg
= callInfo_
->thisArg();
5470 if (kind
== CallKind::Native
) {
5471 // Native functions keep the is-constructing MagicValue as |this|.
5472 // If one of the arguments uses spread syntax this can be a loop phi with
5474 MOZ_ASSERT(thisArg
->type() == MIRType::MagicIsConstructing
||
5478 MOZ_ASSERT(kind
== CallKind::Scripted
);
5480 if (thisArg
->isNewPlainObject()) {
5481 // We have already updated |this| based on MetaScriptedThisShape. We do
5482 // not need to generate a check.
5485 if (flags
.needsUninitializedThis()) {
5486 MConstant
* uninit
= constant(MagicValue(JS_UNINITIALIZED_LEXICAL
));
5487 thisArg
->setImplicitlyUsedUnchecked();
5488 callInfo_
->setThis(uninit
);
5491 // See the Native case above.
5492 MOZ_ASSERT(thisArg
->type() == MIRType::MagicIsConstructing
||
5495 auto* newTarget
= unboxObjectInfallible(callInfo_
->getNewTarget());
5496 auto* createThis
= MCreateThis::New(alloc(), callee
, newTarget
);
5499 thisArg
->setImplicitlyUsedUnchecked();
5500 callInfo_
->setThis(createThis
);
5505 bool WarpCacheIRTranspiler::emitCallFunction(
5506 ObjOperandId calleeId
, Int32OperandId argcId
,
5507 mozilla::Maybe
<ObjOperandId
> thisObjId
, CallFlags flags
, CallKind kind
) {
5508 MDefinition
* callee
= getOperand(calleeId
);
5509 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
5510 // We are transpiling to generate the correct guards. We also
5511 // update the CallInfo to use the correct arguments. Code for the
5512 // inlined function itself will be generated in
5513 // WarpBuilder::buildInlinedCall.
5514 if (!updateCallInfo(callee
, flags
)) {
5517 if (callInfo_
->constructing()) {
5518 MOZ_ASSERT(flags
.isConstructing());
5520 // We call maybeCreateThis to update |this|, but inlined constructors
5521 // never need a VM call. CallIRGenerator::getThisForScripted ensures that
5522 // we don't attach a specialized stub unless we have a template object or
5523 // know that the constructor needs uninitialized this.
5524 MOZ_ALWAYS_FALSE(maybeCreateThis(callee
, flags
, CallKind::Scripted
));
5525 mozilla::DebugOnly
<MDefinition
*> thisArg
= callInfo_
->thisArg();
5526 MOZ_ASSERT(thisArg
->isNewPlainObject() ||
5527 thisArg
->type() == MIRType::MagicUninitializedLexical
);
5530 if (flags
.getArgFormat() == CallFlags::FunCall
) {
5531 callInfo_
->setInliningResumeMode(ResumeMode::InlinedFunCall
);
5533 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::Standard
);
5534 callInfo_
->setInliningResumeMode(ResumeMode::InlinedStandardCall
);
5537 switch (callInfo_
->argFormat()) {
5538 case CallInfo::ArgFormat::Standard
:
5541 MOZ_CRASH("Unsupported arg format");
5547 MDefinition
* argc
= getOperand(argcId
);
5548 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5549 static_cast<int32_t>(callInfo_
->argc()));
5552 if (!updateCallInfo(callee
, flags
)) {
5556 if (kind
== CallKind::DOM
) {
5557 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::Standard
);
5558 // For DOM calls |this| has a class guard.
5559 MDefinition
* thisObj
= getOperand(*thisObjId
);
5560 callInfo_
->setThis(thisObj
);
5563 WrappedFunction
* wrappedTarget
= maybeCallTarget(callee
, kind
);
5565 bool needsThisCheck
= false;
5566 if (callInfo_
->constructing()) {
5567 MOZ_ASSERT(flags
.isConstructing());
5568 needsThisCheck
= maybeCreateThis(callee
, flags
, kind
);
5569 if (needsThisCheck
) {
5570 wrappedTarget
= nullptr;
5574 switch (callInfo_
->argFormat()) {
5575 case CallInfo::ArgFormat::Standard
: {
5576 MCall
* call
= makeCall(*callInfo_
, needsThisCheck
, wrappedTarget
,
5577 kind
== CallKind::DOM
);
5582 if (flags
.isSameRealm()) {
5583 call
->setNotCrossRealm();
5586 if (call
->isEffectful()) {
5589 return resumeAfter(call
);
5592 MOZ_ASSERT(kind
== CallKind::DOM
);
5597 case CallInfo::ArgFormat::Array
: {
5598 MInstruction
* call
= makeSpreadCall(*callInfo_
, needsThisCheck
,
5599 flags
.isSameRealm(), wrappedTarget
);
5606 return resumeAfter(call
);
5608 case CallInfo::ArgFormat::FunApplyArgsObj
: {
5609 return emitFunApplyArgsObj(wrappedTarget
, flags
);
5612 MOZ_CRASH("unreachable");
5615 bool WarpCacheIRTranspiler::emitFunApplyArgsObj(WrappedFunction
* wrappedTarget
,
5617 MOZ_ASSERT(!callInfo_
->constructing());
5619 MDefinition
* callee
= callInfo_
->thisArg();
5620 MDefinition
* thisArg
= callInfo_
->getArg(0);
5621 MDefinition
* argsObj
= callInfo_
->getArg(1);
5623 MApplyArgsObj
* apply
=
5624 MApplyArgsObj::New(alloc(), wrappedTarget
, callee
, argsObj
, thisArg
);
5626 if (flags
.isSameRealm()) {
5627 apply
->setNotCrossRealm();
5629 if (callInfo_
->ignoresReturnValue()) {
5630 apply
->setIgnoresReturnValue();
5633 addEffectful(apply
);
5636 return resumeAfter(apply
);
5639 #ifndef JS_SIMULATOR
5640 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId
,
5641 Int32OperandId argcId
,
5644 bool ignoresReturnValue
) {
5645 // Instead of ignoresReturnValue we use CallInfo::ignoresReturnValue.
5646 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5650 bool WarpCacheIRTranspiler::emitCallDOMFunction(ObjOperandId calleeId
,
5651 Int32OperandId argcId
,
5652 ObjOperandId thisObjId
,
5654 uint32_t argcFixed
) {
5655 return emitCallFunction(calleeId
, argcId
, mozilla::Some(thisObjId
), flags
,
5659 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId
,
5660 Int32OperandId argcId
,
5663 uint32_t targetOffset
) {
5664 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5668 bool WarpCacheIRTranspiler::emitCallDOMFunction(
5669 ObjOperandId calleeId
, Int32OperandId argcId
, ObjOperandId thisObjId
,
5670 CallFlags flags
, uint32_t argcFixed
, uint32_t targetOffset
) {
5671 return emitCallFunction(calleeId
, argcId
, mozilla::Some(thisObjId
), flags
,
5676 bool WarpCacheIRTranspiler::emitCallScriptedFunction(ObjOperandId calleeId
,
5677 Int32OperandId argcId
,
5679 uint32_t argcFixed
) {
5680 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5681 CallKind::Scripted
);
5684 bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId
,
5685 Int32OperandId argcId
,
5686 uint32_t icScriptOffset
,
5688 uint32_t argcFixed
) {
5689 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5690 CallKind::Scripted
);
5694 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetShared(
5695 MDefinition
* target
, MDefinition
* receiver
, MDefinition
* handler
,
5696 MDefinition
* id
, MDefinition
* trapDef
, WrappedFunction
* trap
) {
5697 CallInfo
callInfo(alloc(), /* constructing = */ false,
5698 /* ignoresRval = */ false);
5699 callInfo
.initForProxyGet(trapDef
, handler
, target
, id
, receiver
);
5701 MCall
* call
= makeCall(callInfo
, /* needsThisCheck = */ false, trap
);
5708 if (!current
->ensureHasSlots(3)) {
5711 current
->push(call
);
5713 current
->push(target
);
5715 MResumePoint
* resumePoint
=
5716 MResumePoint::New(alloc(), current
, loc_
.toRawBytecode(),
5717 ResumeMode::ResumeAfterCheckProxyGetResult
);
5721 call
->setResumePoint(resumePoint
);
5726 MCheckScriptedProxyGetResult
* check
=
5727 MCheckScriptedProxyGetResult::New(alloc(), target
, id
, call
);
5728 addEffectfulUnsafe(check
);
5730 return resumeAfterUnchecked(check
);
5733 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetResult(
5734 ValOperandId targetId
, ObjOperandId receiverId
, ObjOperandId handlerId
,
5735 uint32_t trapOffset
, uint32_t idOffset
, uint32_t nargsAndFlags
) {
5736 MDefinition
* target
= getOperand(targetId
);
5737 MDefinition
* receiver
= getOperand(receiverId
);
5738 MDefinition
* handler
= getOperand(handlerId
);
5739 MDefinition
* trap
= objectStubField(trapOffset
);
5740 jsid id
= idStubField(idOffset
);
5741 MDefinition
* idDef
= constant(StringValue(id
.toAtom()));
5742 uint16_t nargs
= nargsAndFlags
>> 16;
5743 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
5744 WrappedFunction
* wrappedTarget
=
5745 maybeWrappedFunction(trap
, CallKind::Scripted
, nargs
, flags
);
5746 return emitCallScriptedProxyGetShared(target
, receiver
, handler
, idDef
, trap
,
5750 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetByValueResult(
5751 ValOperandId targetId
, ObjOperandId receiverId
, ObjOperandId handlerId
,
5752 ValOperandId idId
, uint32_t trapOffset
, uint32_t nargsAndFlags
) {
5753 MDefinition
* target
= getOperand(targetId
);
5754 MDefinition
* receiver
= getOperand(receiverId
);
5755 MDefinition
* handler
= getOperand(handlerId
);
5756 MDefinition
* trap
= objectStubField(trapOffset
);
5757 MDefinition
* idDef
= getOperand(idId
);
5758 uint16_t nargs
= nargsAndFlags
>> 16;
5759 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
5760 WrappedFunction
* wrappedTarget
=
5761 maybeWrappedFunction(trap
, CallKind::Scripted
, nargs
, flags
);
5762 return emitCallScriptedProxyGetShared(target
, receiver
, handler
, idDef
, trap
,
5767 bool WarpCacheIRTranspiler::emitCallClassHook(ObjOperandId calleeId
,
5768 Int32OperandId argcId
,
5771 uint32_t targetOffset
) {
5772 MDefinition
* callee
= getOperand(calleeId
);
5773 JSNative target
= jsnativeStubField(targetOffset
);
5776 MDefinition
* argc
= getOperand(argcId
);
5777 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5778 static_cast<int32_t>(callInfo_
->argc()));
5781 if (!updateCallInfo(callee
, flags
)) {
5785 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5786 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::ArgFormat::Standard
);
5788 // Callees can be from any realm. If this changes, we should update
5789 // MCallClassHook::maybeCrossRealm.
5790 MOZ_ASSERT(!flags
.isSameRealm());
5792 auto* call
= MCallClassHook::New(alloc(), target
, callInfo_
->argc(),
5793 callInfo_
->constructing());
5798 if (callInfo_
->ignoresReturnValue()) {
5799 call
->setIgnoresReturnValue();
5802 call
->initCallee(callInfo_
->callee());
5803 call
->addArg(0, callInfo_
->thisArg());
5805 for (uint32_t i
= 0; i
< callInfo_
->argc(); i
++) {
5806 call
->addArg(i
+ 1, callInfo_
->getArg(i
));
5809 if (callInfo_
->constructing()) {
5810 call
->addArg(1 + callInfo_
->argc(), callInfo_
->getNewTarget());
5816 return resumeAfter(call
);
5819 bool WarpCacheIRTranspiler::emitCallBoundScriptedFunction(
5820 ObjOperandId calleeId
, ObjOperandId targetId
, Int32OperandId argcId
,
5821 CallFlags flags
, uint32_t numBoundArgs
) {
5822 MDefinition
* callee
= getOperand(calleeId
);
5823 MDefinition
* target
= getOperand(targetId
);
5825 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5826 MOZ_ASSERT(callInfo_
->constructing() == flags
.isConstructing());
5828 callInfo_
->setCallee(target
);
5829 updateArgumentsFromOperands();
5831 WrappedFunction
* wrappedTarget
= maybeCallTarget(target
, CallKind::Scripted
);
5833 bool needsThisCheck
= false;
5834 if (callInfo_
->constructing()) {
5835 callInfo_
->setNewTarget(target
);
5836 needsThisCheck
= maybeCreateThis(target
, flags
, CallKind::Scripted
);
5837 if (needsThisCheck
) {
5838 wrappedTarget
= nullptr;
5841 auto* thisv
= MLoadFixedSlot::New(alloc(), callee
,
5842 BoundFunctionObject::boundThisSlot());
5844 callInfo_
->thisArg()->setImplicitlyUsedUnchecked();
5845 callInfo_
->setThis(thisv
);
5848 bool usingInlineBoundArgs
=
5849 numBoundArgs
<= BoundFunctionObject::MaxInlineBoundArgs
;
5851 MElements
* elements
= nullptr;
5852 if (!usingInlineBoundArgs
) {
5853 auto* boundArgs
= MLoadFixedSlot::New(
5854 alloc(), callee
, BoundFunctionObject::firstInlineBoundArgSlot());
5856 auto* boundArgsObj
= unboxObjectInfallible(boundArgs
, IsMovable::Yes
);
5857 elements
= MElements::New(alloc(), boundArgsObj
);
5861 auto loadBoundArg
= [&](size_t index
) {
5863 if (usingInlineBoundArgs
) {
5864 size_t slot
= BoundFunctionObject::firstInlineBoundArgSlot() + index
;
5865 arg
= MLoadFixedSlot::New(alloc(), callee
, slot
);
5867 arg
= MLoadElement::New(alloc(), elements
, constant(Int32Value(index
)));
5872 if (!callInfo_
->prependArgs(numBoundArgs
, loadBoundArg
)) {
5876 MCall
* call
= makeCall(*callInfo_
, needsThisCheck
, wrappedTarget
);
5881 if (flags
.isSameRealm()) {
5882 call
->setNotCrossRealm();
5887 return resumeAfter(call
);
5890 bool WarpCacheIRTranspiler::emitBindFunctionResult(
5891 ObjOperandId targetId
, uint32_t argc
, uint32_t templateObjectOffset
) {
5892 MDefinition
* target
= getOperand(targetId
);
5893 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
5895 MOZ_ASSERT(callInfo_
->argc() == argc
);
5897 auto* bound
= MBindFunction::New(alloc(), target
, argc
, templateObj
);
5901 addEffectful(bound
);
5903 for (uint32_t i
= 0; i
< argc
; i
++) {
5904 bound
->initArg(i
, callInfo_
->getArg(i
));
5908 return resumeAfter(bound
);
5911 bool WarpCacheIRTranspiler::emitSpecializedBindFunctionResult(
5912 ObjOperandId targetId
, uint32_t argc
, uint32_t templateObjectOffset
) {
5913 MDefinition
* target
= getOperand(targetId
);
5914 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
5916 MOZ_ASSERT(callInfo_
->argc() == argc
);
5918 auto* bound
= MNewBoundFunction::New(alloc(), templateObj
);
5921 size_t numBoundArgs
= argc
> 0 ? argc
- 1 : 0;
5922 MOZ_ASSERT(numBoundArgs
<= BoundFunctionObject::MaxInlineBoundArgs
);
5924 auto initSlot
= [&](size_t slot
, MDefinition
* value
) {
5926 // Assert we can elide the post write barrier. See also the comment in
5927 // WarpBuilder::buildNamedLambdaEnv.
5928 add(MAssertCanElidePostWriteBarrier::New(alloc(), bound
, value
));
5930 addUnchecked(MStoreFixedSlot::NewUnbarriered(alloc(), bound
, slot
, value
));
5933 initSlot(BoundFunctionObject::targetSlot(), target
);
5935 initSlot(BoundFunctionObject::boundThisSlot(), callInfo_
->getArg(0));
5937 for (size_t i
= 0; i
< numBoundArgs
; i
++) {
5938 size_t slot
= BoundFunctionObject::firstInlineBoundArgSlot() + i
;
5939 initSlot(slot
, callInfo_
->getArg(1 + i
));
5946 bool WarpCacheIRTranspiler::emitCallWasmFunction(
5947 ObjOperandId calleeId
, Int32OperandId argcId
, CallFlags flags
,
5948 uint32_t argcFixed
, uint32_t funcExportOffset
, uint32_t instanceOffset
) {
5949 MDefinition
* callee
= getOperand(calleeId
);
5951 MDefinition
* argc
= getOperand(argcId
);
5952 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5953 static_cast<int32_t>(callInfo_
->argc()));
5955 JSObject
* instanceObject
= tenuredObjectStubField(instanceOffset
);
5956 auto* wasmInstanceObj
= &instanceObject
->as
<WasmInstanceObject
>();
5957 const wasm::FuncExport
* funcExport
= wasmFuncExportField(funcExportOffset
);
5958 const wasm::FuncType
& sig
=
5959 wasmInstanceObj
->instance().metadata().getFuncExportType(*funcExport
);
5961 if (!updateCallInfo(callee
, flags
)) {
5965 static_assert(wasm::MaxArgsForJitInlineCall
<= MaxNumLInstructionOperands
,
5966 "arguments must fit in LIR operands");
5967 MOZ_ASSERT(sig
.args().length() <= wasm::MaxArgsForJitInlineCall
);
5969 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5971 auto* call
= MIonToWasmCall::New(alloc(), wasmInstanceObj
, *funcExport
);
5976 mozilla::Maybe
<MDefinition
*> undefined
;
5977 for (size_t i
= 0; i
< sig
.args().length(); i
++) {
5978 if (!alloc().ensureBallast()) {
5983 if (i
< callInfo_
->argc()) {
5984 arg
= callInfo_
->getArg(i
);
5987 undefined
.emplace(constant(UndefinedValue()));
5989 arg
= convertWasmArg(*undefined
, sig
.args()[i
].kind());
5991 call
->initArg(i
, arg
);
5996 // Add any post-function call conversions that are necessary.
5997 MInstruction
* postConversion
= call
;
5998 const wasm::ValTypeVector
& results
= sig
.results();
5999 MOZ_ASSERT(results
.length() <= 1, "Multi-value returns not supported.");
6000 if (results
.length() == 0) {
6001 // No results to convert.
6003 switch (results
[0].kind()) {
6004 case wasm::ValType::I64
:
6005 // JS expects a BigInt from I64 types.
6006 postConversion
= MInt64ToBigInt::New(alloc(), call
);
6008 // Make non-movable so we can attach a resume point.
6009 postConversion
->setNotMovable();
6011 add(postConversion
);
6014 // No spectre.index_masking of i32 results required, as the generated
6015 // stub takes care of that.
6020 // The resume point has to be attached to the post-conversion instruction
6021 // (if present) instead of to the call. This way, if the call triggers an
6022 // invalidation bailout, we will have the BigInt value on the Baseline stack.
6023 // Potential alternative solution: attach the resume point to the call and
6024 // have bailouts turn the Int64 value into a BigInt, maybe with a recover
6026 pushResult(postConversion
);
6027 return resumeAfterUnchecked(postConversion
);
6030 MDefinition
* WarpCacheIRTranspiler::convertWasmArg(MDefinition
* arg
,
6031 wasm::ValType::Kind kind
) {
6032 // An invariant in this code is that any type conversion operation that has
6033 // externally visible effects, such as invoking valueOf on an object argument,
6034 // must bailout so that we don't have to worry about replaying effects during
6035 // argument conversion.
6036 MInstruction
* conversion
= nullptr;
6038 case wasm::ValType::I32
:
6039 conversion
= MTruncateToInt32::New(alloc(), arg
);
6041 case wasm::ValType::I64
:
6042 conversion
= MToInt64::New(alloc(), arg
);
6044 case wasm::ValType::F32
:
6045 conversion
= MToFloat32::New(alloc(), arg
);
6047 case wasm::ValType::F64
:
6048 conversion
= MToDouble::New(alloc(), arg
);
6050 case wasm::ValType::V128
:
6051 MOZ_CRASH("Unexpected type for Wasm JitEntry");
6052 case wasm::ValType::Ref
:
6053 // Transform the JS representation into an AnyRef representation.
6054 // The resulting type is MIRType::WasmAnyRef. These cases are all
6056 switch (arg
->type()) {
6057 case MIRType::Object
:
6058 conversion
= MWasmAnyRefFromJSObject::New(alloc(), arg
);
6060 case MIRType::String
:
6061 conversion
= MWasmAnyRefFromJSString::New(alloc(), arg
);
6064 arg
->setImplicitlyUsedUnchecked();
6065 conversion
= MWasmNullConstant::New(alloc());
6068 conversion
= MWasmAnyRefFromJSValue::New(alloc(), arg
);
6078 bool WarpCacheIRTranspiler::emitGuardWasmArg(ValOperandId argId
,
6079 wasm::ValType::Kind kind
) {
6080 MDefinition
* arg
= getOperand(argId
);
6081 MDefinition
* conversion
= convertWasmArg(arg
, kind
);
6083 setOperand(argId
, conversion
);
6087 bool WarpCacheIRTranspiler::emitCallGetterResult(CallKind kind
,
6088 ValOperandId receiverId
,
6089 uint32_t getterOffset
,
6091 uint32_t nargsAndFlagsOffset
) {
6092 MDefinition
* receiver
= getOperand(receiverId
);
6093 MDefinition
* getter
= objectStubField(getterOffset
);
6094 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
6095 // We are transpiling to generate the correct guards. We also update the
6096 // CallInfo to use the correct arguments. Code for the inlined getter
6097 // itself will be generated in WarpBuilder::buildInlinedCall.
6098 callInfo_
->initForGetterCall(getter
, receiver
);
6099 callInfo_
->setInliningResumeMode(ResumeMode::InlinedAccessor
);
6101 // Make sure there's enough room to push the arguments on the stack.
6102 if (!current
->ensureHasSlots(2)) {
6109 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
6110 uint16_t nargs
= nargsAndFlags
>> 16;
6111 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
6112 WrappedFunction
* wrappedTarget
=
6113 maybeWrappedFunction(getter
, kind
, nargs
, flags
);
6115 bool ignoresRval
= loc_
.resultIsPopped();
6116 CallInfo
callInfo(alloc(), /* constructing = */ false, ignoresRval
);
6117 callInfo
.initForGetterCall(getter
, receiver
);
6119 MCall
* call
= makeCall(callInfo
, /* needsThisCheck = */ false, wrappedTarget
);
6125 call
->setNotCrossRealm();
6131 return resumeAfter(call
);
6134 bool WarpCacheIRTranspiler::emitCallScriptedGetterResult(
6135 ValOperandId receiverId
, uint32_t getterOffset
, bool sameRealm
,
6136 uint32_t nargsAndFlagsOffset
) {
6137 return emitCallGetterResult(CallKind::Scripted
, receiverId
, getterOffset
,
6138 sameRealm
, nargsAndFlagsOffset
);
6141 bool WarpCacheIRTranspiler::emitCallInlinedGetterResult(
6142 ValOperandId receiverId
, uint32_t getterOffset
, uint32_t icScriptOffset
,
6143 bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
6144 return emitCallGetterResult(CallKind::Scripted
, receiverId
, getterOffset
,
6145 sameRealm
, nargsAndFlagsOffset
);
6148 bool WarpCacheIRTranspiler::emitCallNativeGetterResult(
6149 ValOperandId receiverId
, uint32_t getterOffset
, bool sameRealm
,
6150 uint32_t nargsAndFlagsOffset
) {
6151 return emitCallGetterResult(CallKind::Native
, receiverId
, getterOffset
,
6152 sameRealm
, nargsAndFlagsOffset
);
6155 bool WarpCacheIRTranspiler::emitCallSetter(CallKind kind
,
6156 ObjOperandId receiverId
,
6157 uint32_t setterOffset
,
6158 ValOperandId rhsId
, bool sameRealm
,
6159 uint32_t nargsAndFlagsOffset
) {
6160 MDefinition
* receiver
= getOperand(receiverId
);
6161 MDefinition
* setter
= objectStubField(setterOffset
);
6162 MDefinition
* rhs
= getOperand(rhsId
);
6163 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
6164 // We are transpiling to generate the correct guards. We also update the
6165 // CallInfo to use the correct arguments. Code for the inlined setter
6166 // itself will be generated in WarpBuilder::buildInlinedCall.
6167 callInfo_
->initForSetterCall(setter
, receiver
, rhs
);
6168 callInfo_
->setInliningResumeMode(ResumeMode::InlinedAccessor
);
6170 // Make sure there's enough room to push the arguments on the stack.
6171 if (!current
->ensureHasSlots(3)) {
6178 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
6179 uint16_t nargs
= nargsAndFlags
>> 16;
6180 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
6181 WrappedFunction
* wrappedTarget
=
6182 maybeWrappedFunction(setter
, kind
, nargs
, flags
);
6184 CallInfo
callInfo(alloc(), /* constructing = */ false,
6185 /* ignoresReturnValue = */ true);
6186 callInfo
.initForSetterCall(setter
, receiver
, rhs
);
6188 MCall
* call
= makeCall(callInfo
, /* needsThisCheck = */ false, wrappedTarget
);
6194 call
->setNotCrossRealm();
6198 return resumeAfter(call
);
6201 bool WarpCacheIRTranspiler::emitCallScriptedSetter(
6202 ObjOperandId receiverId
, uint32_t setterOffset
, ValOperandId rhsId
,
6203 bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
6204 return emitCallSetter(CallKind::Scripted
, receiverId
, setterOffset
, rhsId
,
6205 sameRealm
, nargsAndFlagsOffset
);
6208 bool WarpCacheIRTranspiler::emitCallInlinedSetter(
6209 ObjOperandId receiverId
, uint32_t setterOffset
, ValOperandId rhsId
,
6210 uint32_t icScriptOffset
, bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
6211 return emitCallSetter(CallKind::Scripted
, receiverId
, setterOffset
, rhsId
,
6212 sameRealm
, nargsAndFlagsOffset
);
6215 bool WarpCacheIRTranspiler::emitCallNativeSetter(ObjOperandId receiverId
,
6216 uint32_t setterOffset
,
6219 uint32_t nargsAndFlagsOffset
) {
6220 return emitCallSetter(CallKind::Native
, receiverId
, setterOffset
, rhsId
,
6221 sameRealm
, nargsAndFlagsOffset
);
6224 bool WarpCacheIRTranspiler::emitMetaScriptedThisShape(
6225 uint32_t thisShapeOffset
) {
6226 SharedShape
* shape
= &shapeStubField(thisShapeOffset
)->asShared();
6227 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
6229 MConstant
* shapeConst
= MConstant::NewShape(alloc(), shape
);
6232 // TODO: support pre-tenuring.
6233 gc::Heap heap
= gc::Heap::Default
;
6235 uint32_t numFixedSlots
= shape
->numFixedSlots();
6236 uint32_t numDynamicSlots
= NativeObject::calculateDynamicSlots(shape
);
6237 gc::AllocKind kind
= gc::GetGCObjectKind(numFixedSlots
);
6238 MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind
, &PlainObject::class_
));
6239 kind
= gc::ForegroundToBackgroundAllocKind(kind
);
6241 auto* createThis
= MNewPlainObject::New(alloc(), shapeConst
, numFixedSlots
,
6242 numDynamicSlots
, kind
, heap
);
6245 callInfo_
->thisArg()->setImplicitlyUsedUnchecked();
6246 callInfo_
->setThis(createThis
);
6250 bool WarpCacheIRTranspiler::emitReturnFromIC() { return true; }
6252 bool WarpCacheIRTranspiler::emitBailout() {
6253 auto* bail
= MBail::New(alloc());
6259 bool WarpCacheIRTranspiler::emitAssertPropertyLookup(ObjOperandId objId
,
6261 uint32_t slotOffset
) {
6262 // We currently only emit checks in baseline.
6266 bool WarpCacheIRTranspiler::emitAssertRecoveredOnBailoutResult(
6267 ValOperandId valId
, bool mustBeRecovered
) {
6268 MDefinition
* val
= getOperand(valId
);
6270 // Don't assert for recovered instructions when recovering is disabled.
6271 if (JitOptions
.disableRecoverIns
) {
6272 pushResult(constant(UndefinedValue()));
6276 if (JitOptions
.checkRangeAnalysis
) {
6277 // If we are checking the range of all instructions, then the guards
6278 // inserted by Range Analysis prevent the use of recover instruction. Thus,
6279 // we just disable these checks.
6280 pushResult(constant(UndefinedValue()));
6284 auto* assert = MAssertRecoveredOnBailout::New(alloc(), val
, mustBeRecovered
);
6285 addEffectfulUnsafe(assert);
6286 current
->push(assert);
6288 // Create an instruction sequence which implies that the argument of the
6289 // assertRecoveredOnBailout function would be encoded at least in one
6291 auto* nop
= MNop::New(alloc());
6294 auto* resumePoint
= MResumePoint::New(
6295 alloc(), nop
->block(), loc_
.toRawBytecode(), ResumeMode::ResumeAfter
);
6299 nop
->setResumePoint(resumePoint
);
6301 auto* encode
= MEncodeSnapshot::New(alloc());
6302 addEffectfulUnsafe(encode
);
6306 pushResult(constant(UndefinedValue()));
6310 bool WarpCacheIRTranspiler::emitGuardNoAllocationMetadataBuilder(
6311 uint32_t builderAddrOffset
) {
6312 // This is a no-op because we discard all JIT code when set an allocation
6313 // metadata callback.
6317 bool WarpCacheIRTranspiler::emitNewPlainObjectResult(uint32_t numFixedSlots
,
6318 uint32_t numDynamicSlots
,
6319 gc::AllocKind allocKind
,
6320 uint32_t shapeOffset
,
6321 uint32_t siteOffset
) {
6322 Shape
* shape
= shapeStubField(shapeOffset
);
6323 gc::Heap heap
= allocSiteInitialHeapField(siteOffset
);
6325 auto* shapeConstant
= MConstant::NewShape(alloc(), shape
);
6328 auto* obj
= MNewPlainObject::New(alloc(), shapeConstant
, numFixedSlots
,
6329 numDynamicSlots
, allocKind
, heap
);
6336 bool WarpCacheIRTranspiler::emitNewArrayObjectResult(uint32_t length
,
6337 uint32_t shapeOffset
,
6338 uint32_t siteOffset
) {
6339 Shape
* shape
= shapeStubField(shapeOffset
);
6340 gc::Heap heap
= allocSiteInitialHeapField(siteOffset
);
6342 auto* shapeConstant
= MConstant::NewShape(alloc(), shape
);
6345 auto* obj
= MNewArrayObject::New(alloc(), shapeConstant
, length
, heap
);
6352 bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId
,
6353 ObjOperandId calleeId
,
6354 CompletionKind kind
,
6355 uint32_t calleeNargs
) {
6356 MDefinition
* iter
= getOperand(iterId
);
6357 MDefinition
* callee
= getOperand(calleeId
);
6359 WrappedFunction
* wrappedTarget
= maybeCallTarget(callee
, CallKind::Scripted
);
6360 MOZ_ASSERT(wrappedTarget
);
6361 MOZ_ASSERT(wrappedTarget
->nargs() == calleeNargs
);
6362 MOZ_ASSERT(wrappedTarget
->hasJitEntry());
6364 bool constructing
= false;
6365 bool ignoresRval
= false;
6366 bool needsThisCheck
= false;
6367 bool isDOMCall
= false;
6368 CallInfo
callInfo(alloc(), constructing
, ignoresRval
);
6369 callInfo
.initForCloseIter(iter
, callee
);
6370 MCall
* call
= makeCall(callInfo
, needsThisCheck
, wrappedTarget
, isDOMCall
);
6375 if (kind
== CompletionKind::Throw
) {
6376 return resumeAfter(call
);
6379 // If we bail out here, after the call but before the CheckIsObj, we
6380 // can't simply resume in the baseline interpreter. If we resume
6381 // after the CloseIter, we won't check the return value. If we
6382 // resume at the CloseIter, we will call the |return| method twice.
6383 // Instead, we use a special resume mode that captures the
6384 // intermediate value, and then checks that it's an object while
6386 current
->push(call
);
6387 MResumePoint
* resumePoint
=
6388 MResumePoint::New(alloc(), current
, loc_
.toRawBytecode(),
6389 ResumeMode::ResumeAfterCheckIsObject
);
6393 call
->setResumePoint(resumePoint
);
6396 MCheckIsObj
* check
= MCheckIsObj::New(
6397 alloc(), call
, uint8_t(CheckIsObjectKind::IteratorReturn
));
6398 addEffectfulUnsafe(check
);
6400 return resumeAfterUnchecked(check
);
6403 bool WarpCacheIRTranspiler::emitGuardGlobalGeneration(
6404 uint32_t expectedOffset
, uint32_t generationAddrOffset
) {
6405 uint32_t expected
= uint32StubField(expectedOffset
);
6406 const void* generationAddr
= rawPointerField(generationAddrOffset
);
6408 auto guard
= MGuardGlobalGeneration::New(alloc(), expected
, generationAddr
);
6414 #ifdef FUZZING_JS_FUZZILLI
6415 bool WarpCacheIRTranspiler::emitFuzzilliHashResult(ValOperandId valId
) {
6416 MDefinition
* input
= getOperand(valId
);
6418 auto* hash
= MFuzzilliHash::New(alloc(), input
);
6421 auto* store
= MFuzzilliHashStore::New(alloc(), hash
);
6422 addEffectful(store
);
6423 pushResult(constant(UndefinedValue()));
6425 return resumeAfter(store
);
6429 static void MaybeSetImplicitlyUsed(uint32_t numInstructionIdsBefore
,
6430 MDefinition
* input
) {
6431 // When building MIR from bytecode, for each MDefinition that's an operand to
6432 // a bytecode instruction, we must either add an SSA use or set the
6433 // ImplicitlyUsed flag on that definition. The ImplicitlyUsed flag prevents
6434 // the backend from optimizing-out values that will be used by Baseline after
6437 // WarpBuilder uses WarpPoppedValueUseChecker to assert this invariant in
6440 // This function is responsible for setting the ImplicitlyUsed flag for an
6441 // input when using the transpiler. It looks at the input's most recent use
6442 // and if that's an instruction that was added while transpiling this JSOp
6443 // (based on the MIR instruction id) we don't set the ImplicitlyUsed flag.
6445 if (input
->isImplicitlyUsed()) {
6450 // If the most recent use of 'input' is an instruction we just added, there is
6452 MDefinition
* inputUse
= input
->maybeMostRecentlyAddedDefUse();
6453 if (inputUse
&& inputUse
->id() >= numInstructionIdsBefore
) {
6457 // The transpiler didn't add a use for 'input'.
6458 input
->setImplicitlyUsed();
6461 bool jit::TranspileCacheIRToMIR(WarpBuilder
* builder
, BytecodeLocation loc
,
6462 const WarpCacheIR
* cacheIRSnapshot
,
6463 std::initializer_list
<MDefinition
*> inputs
,
6464 CallInfo
* maybeCallInfo
) {
6465 uint32_t numInstructionIdsBefore
=
6466 builder
->mirGen().graph().getNumInstructionIds();
6468 WarpCacheIRTranspiler
transpiler(builder
, loc
, maybeCallInfo
,
6470 if (!transpiler
.transpile(inputs
)) {
6474 for (MDefinition
* input
: inputs
) {
6475 MaybeSetImplicitlyUsed(numInstructionIdsBefore
, input
);
6478 if (maybeCallInfo
) {
6479 auto maybeSetFlag
= [numInstructionIdsBefore
](MDefinition
* def
) {
6480 MaybeSetImplicitlyUsed(numInstructionIdsBefore
, def
);
6482 maybeCallInfo
->forEachCallOperand(maybeSetFlag
);