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 "builtin/DataViewObject.h"
15 #include "builtin/MapObject.h"
16 #include "jit/AtomicOp.h"
17 #include "jit/CacheIR.h"
18 #include "jit/CacheIRCompiler.h"
19 #include "jit/CacheIROpsGenerated.h"
20 #include "jit/CacheIRReader.h"
23 #include "jit/MIRGenerator.h"
24 #include "jit/MIRGraph.h"
25 #include "jit/WarpBuilder.h"
26 #include "jit/WarpBuilderShared.h"
27 #include "jit/WarpSnapshot.h"
28 #include "js/ScalarType.h" // js::Scalar::Type
29 #include "vm/ArgumentsObject.h"
30 #include "vm/BytecodeLocation.h"
31 #include "wasm/WasmCode.h"
33 #include "gc/ObjectKind-inl.h"
34 #include "vm/NativeObject-inl.h"
35 #include "wasm/WasmInstance-inl.h"
38 using namespace js::jit
;
40 // The CacheIR transpiler generates MIR from Baseline CacheIR.
41 class MOZ_RAII WarpCacheIRTranspiler
: public WarpBuilderShared
{
42 WarpBuilder
* builder_
;
43 BytecodeLocation loc_
;
44 const CacheIRStubInfo
* stubInfo_
;
45 const uint8_t* stubData_
;
47 // Vector mapping OperandId to corresponding MDefinition.
48 using MDefinitionStackVector
= Vector
<MDefinition
*, 8, SystemAllocPolicy
>;
49 MDefinitionStackVector operands_
;
53 // Array mapping call arguments to OperandId.
54 using ArgumentKindArray
=
55 mozilla::EnumeratedArray
<ArgumentKind
, ArgumentKind::NumKinds
, OperandId
>;
56 ArgumentKindArray argumentOperandIds_
;
58 void setArgumentId(ArgumentKind kind
, OperandId id
) {
59 MOZ_ASSERT(kind
!= ArgumentKind::Callee
);
60 MOZ_ASSERT(!argumentOperandIds_
[kind
].valid());
61 argumentOperandIds_
[kind
] = id
;
64 void updateArgumentsFromOperands();
67 // Used to assert that there is only one effectful instruction
68 // per stub. And that this instruction has a resume point.
69 MInstruction
* effectful_
= nullptr;
70 bool pushedResult_
= false;
73 inline void addUnchecked(MInstruction
* ins
) {
76 // If we have not set a more specific bailout kind, mark this instruction
77 // as transpiled CacheIR. If one of these instructions bails out, we
78 // expect to hit the baseline fallback stub and invalidate the Warp script
80 if (ins
->bailoutKind() == BailoutKind::Unknown
) {
81 ins
->setBailoutKind(BailoutKind::TranspiledCacheIR
);
85 inline void add(MInstruction
* ins
) {
86 MOZ_ASSERT(!ins
->isEffectful());
90 inline void addEffectful(MInstruction
* ins
) {
91 MOZ_ASSERT(ins
->isEffectful());
92 MOZ_ASSERT(!effectful_
, "Can only have one effectful instruction");
99 // Bypasses all checks in addEffectful. Only used for testing functions.
100 inline void addEffectfulUnsafe(MInstruction
* ins
) {
101 MOZ_ASSERT(ins
->isEffectful());
105 [[nodiscard
]] bool resumeAfterUnchecked(MInstruction
* ins
) {
106 return WarpBuilderShared::resumeAfter(ins
, loc_
);
108 [[nodiscard
]] bool resumeAfter(MInstruction
* ins
) {
109 MOZ_ASSERT(effectful_
== ins
);
110 return resumeAfterUnchecked(ins
);
113 // CacheIR instructions writing to the IC's result register (the *Result
114 // instructions) must call this to push the result onto the virtual stack.
115 void pushResult(MDefinition
* result
) {
116 MOZ_ASSERT(!pushedResult_
, "Can't have more than one result");
117 current
->push(result
);
119 pushedResult_
= true;
123 MDefinition
* getOperand(OperandId id
) const { return operands_
[id
.id()]; }
125 void setOperand(OperandId id
, MDefinition
* def
) { operands_
[id
.id()] = def
; }
127 [[nodiscard
]] bool defineOperand(OperandId id
, MDefinition
* def
) {
128 MOZ_ASSERT(id
.id() == operands_
.length());
129 return operands_
.append(def
);
132 uintptr_t readStubWord(uint32_t offset
) {
133 return stubInfo_
->getStubRawWord(stubData_
, offset
);
136 Shape
* shapeStubField(uint32_t offset
) {
137 return reinterpret_cast<Shape
*>(readStubWord(offset
));
139 GetterSetter
* getterSetterStubField(uint32_t offset
) {
140 return reinterpret_cast<GetterSetter
*>(readStubWord(offset
));
142 const JSClass
* classStubField(uint32_t offset
) {
143 return reinterpret_cast<const JSClass
*>(readStubWord(offset
));
145 JSString
* stringStubField(uint32_t offset
) {
146 return reinterpret_cast<JSString
*>(readStubWord(offset
));
148 JS::Symbol
* symbolStubField(uint32_t offset
) {
149 return reinterpret_cast<JS::Symbol
*>(readStubWord(offset
));
151 BaseScript
* baseScriptStubField(uint32_t offset
) {
152 return reinterpret_cast<BaseScript
*>(readStubWord(offset
));
154 const JSJitInfo
* jitInfoStubField(uint32_t offset
) {
155 return reinterpret_cast<const JSJitInfo
*>(readStubWord(offset
));
157 JSNative
jsnativeStubField(uint32_t offset
) {
158 return reinterpret_cast<JSNative
>(readStubWord(offset
));
160 JS::ExpandoAndGeneration
* expandoAndGenerationField(uint32_t offset
) {
161 return reinterpret_cast<JS::ExpandoAndGeneration
*>(readStubWord(offset
));
163 const wasm::FuncExport
* wasmFuncExportField(uint32_t offset
) {
164 return reinterpret_cast<const wasm::FuncExport
*>(readStubWord(offset
));
166 NativeIteratorListHead
* nativeIteratorListHeadStubField(uint32_t offset
) {
167 return reinterpret_cast<NativeIteratorListHead
*>(readStubWord(offset
));
169 gc::Heap
allocSiteInitialHeapField(uint32_t offset
) {
170 uintptr_t word
= readStubWord(offset
);
171 MOZ_ASSERT(word
== uintptr_t(gc::Heap::Default
) ||
172 word
== uintptr_t(gc::Heap::Tenured
));
173 return gc::Heap(word
);
175 const void* rawPointerField(uint32_t offset
) {
176 return reinterpret_cast<const void*>(readStubWord(offset
));
178 jsid
idStubField(uint32_t offset
) {
179 return jsid::fromRawBits(readStubWord(offset
));
181 int32_t int32StubField(uint32_t offset
) {
182 return static_cast<int32_t>(readStubWord(offset
));
184 uint32_t uint32StubField(uint32_t offset
) {
185 return static_cast<uint32_t>(readStubWord(offset
));
187 uint64_t uint64StubField(uint32_t offset
) {
188 return static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
190 Value
valueStubField(uint32_t offset
) {
192 static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
193 Value val
= Value::fromRawBits(raw
);
194 MOZ_ASSERT_IF(val
.isGCThing(), val
.toGCThing()->isTenured());
197 double doubleStubField(uint32_t offset
) {
199 static_cast<uint64_t>(stubInfo_
->getStubRawInt64(stubData_
, offset
));
200 return mozilla::BitwiseCast
<double>(raw
);
203 // This must only be called when the caller knows the object is tenured and
204 // not a nursery index.
205 JSObject
* tenuredObjectStubField(uint32_t offset
) {
206 WarpObjectField field
= WarpObjectField::fromData(readStubWord(offset
));
207 return field
.toObject();
210 // Returns either MConstant or MNurseryIndex. See WarpObjectField.
211 MInstruction
* objectStubField(uint32_t offset
);
213 const JSClass
* classForGuardClassKind(GuardClassKind kind
);
215 [[nodiscard
]] bool emitGuardTo(ValOperandId inputId
, MIRType type
);
217 [[nodiscard
]] bool emitToString(OperandId inputId
, StringOperandId resultId
);
219 template <typename T
>
220 [[nodiscard
]] bool emitDoubleBinaryArithResult(NumberOperandId lhsId
,
221 NumberOperandId rhsId
);
223 template <typename T
>
224 [[nodiscard
]] bool emitInt32BinaryArithResult(Int32OperandId lhsId
,
225 Int32OperandId rhsId
);
227 template <typename T
>
228 [[nodiscard
]] bool emitBigIntBinaryArithResult(BigIntOperandId lhsId
,
229 BigIntOperandId rhsId
);
231 template <typename T
>
232 [[nodiscard
]] bool emitBigIntBinaryArithEffectfulResult(
233 BigIntOperandId lhsId
, BigIntOperandId rhsId
);
235 template <typename T
>
236 [[nodiscard
]] bool emitBigIntUnaryArithResult(BigIntOperandId inputId
);
238 [[nodiscard
]] bool emitCompareResult(JSOp op
, OperandId lhsId
,
240 MCompare::CompareType compareType
);
242 [[nodiscard
]] bool emitTruthyResult(OperandId inputId
);
244 [[nodiscard
]] bool emitNewIteratorResult(MNewIterator::Type type
,
245 uint32_t templateObjectOffset
);
247 MInstruction
* addBoundsCheck(MDefinition
* index
, MDefinition
* length
);
249 [[nodiscard
]] MInstruction
* convertToBoolean(MDefinition
* input
);
251 bool emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind kind
,
252 ObjOperandId objId
, uint32_t offsetOffset
,
253 ValOperandId rhsId
, uint32_t newShapeOffset
);
255 void addDataViewData(MDefinition
* obj
, Scalar::Type type
,
256 MDefinition
** offset
, MInstruction
** elements
);
258 [[nodiscard
]] bool emitAtomicsBinaryOp(ObjOperandId objId
,
259 IntPtrOperandId indexId
,
261 Scalar::Type elementType
,
262 bool forEffect
, AtomicOp op
);
264 [[nodiscard
]] bool emitLoadArgumentSlot(ValOperandId resultId
,
267 // Calls are either Native (native function without a JitEntry),
268 // a DOM Native (native function with a JitInfo OpType::Method),
269 // or Scripted (scripted function or native function with a JitEntry).
270 enum class CallKind
{ Native
, DOM
, Scripted
};
272 [[nodiscard
]] bool updateCallInfo(MDefinition
* callee
, CallFlags flags
);
274 [[nodiscard
]] bool emitCallFunction(ObjOperandId calleeId
,
275 Int32OperandId argcId
,
276 mozilla::Maybe
<ObjOperandId
> thisObjId
,
277 CallFlags flags
, CallKind kind
);
278 [[nodiscard
]] bool emitFunApplyArgsObj(WrappedFunction
* wrappedTarget
,
281 MDefinition
* convertWasmArg(MDefinition
* arg
, wasm::ValType::Kind kind
);
283 WrappedFunction
* maybeWrappedFunction(MDefinition
* callee
, CallKind kind
,
284 uint16_t nargs
, FunctionFlags flags
);
285 WrappedFunction
* maybeCallTarget(MDefinition
* callee
, CallKind kind
);
287 bool maybeCreateThis(MDefinition
* callee
, CallFlags flags
, CallKind kind
);
289 [[nodiscard
]] bool emitCallGetterResult(CallKind kind
,
290 ValOperandId receiverId
,
291 uint32_t getterOffset
, bool sameRealm
,
292 uint32_t nargsAndFlagsOffset
);
293 [[nodiscard
]] bool emitCallSetter(CallKind kind
, ObjOperandId receiverId
,
294 uint32_t setterOffset
, ValOperandId rhsId
,
296 uint32_t nargsAndFlagsOffset
);
298 CACHE_IR_TRANSPILER_GENERATED
301 WarpCacheIRTranspiler(WarpBuilder
* builder
, BytecodeLocation loc
,
302 CallInfo
* callInfo
, const WarpCacheIR
* cacheIRSnapshot
)
303 : WarpBuilderShared(builder
->snapshot(), builder
->mirGen(),
304 builder
->currentBlock()),
307 stubInfo_(cacheIRSnapshot
->stubInfo()),
308 stubData_(cacheIRSnapshot
->stubData()),
309 callInfo_(callInfo
) {}
311 [[nodiscard
]] bool transpile(std::initializer_list
<MDefinition
*> inputs
);
314 bool WarpCacheIRTranspiler::transpile(
315 std::initializer_list
<MDefinition
*> inputs
) {
316 if (!operands_
.append(inputs
.begin(), inputs
.end())) {
320 CacheIRReader
reader(stubInfo_
);
322 CacheOp op
= reader
.readOp();
324 #define DEFINE_OP(op, ...) \
326 if (!emit##op(reader)) { \
330 CACHE_IR_TRANSPILER_OPS(DEFINE_OP
)
334 fprintf(stderr
, "Unsupported op: %s\n", CacheIROpNames
[size_t(op
)]);
335 MOZ_CRASH("Unsupported op");
337 } while (reader
.more());
339 // Effectful instructions should have a resume point. MIonToWasmCall is an
340 // exception: we can attach the resume point to the MInt64ToBigInt instruction
342 MOZ_ASSERT_IF(effectful_
,
343 effectful_
->resumePoint() || effectful_
->isIonToWasmCall());
347 MInstruction
* WarpCacheIRTranspiler::objectStubField(uint32_t offset
) {
348 WarpObjectField field
= WarpObjectField::fromData(readStubWord(offset
));
350 if (field
.isNurseryIndex()) {
351 auto* ins
= MNurseryObject::New(alloc(), field
.toNurseryIndex());
356 auto* ins
= MConstant::NewObject(alloc(), field
.toObject());
361 bool WarpCacheIRTranspiler::emitGuardClass(ObjOperandId objId
,
362 GuardClassKind kind
) {
363 MDefinition
* def
= getOperand(objId
);
366 if (kind
== GuardClassKind::JSFunction
) {
367 ins
= MGuardToFunction::New(alloc(), def
);
369 const JSClass
* classp
= classForGuardClassKind(kind
);
370 ins
= MGuardToClass::New(alloc(), def
, classp
);
375 setOperand(objId
, ins
);
379 const JSClass
* WarpCacheIRTranspiler::classForGuardClassKind(
380 GuardClassKind kind
) {
382 case GuardClassKind::Array
:
383 return &ArrayObject::class_
;
384 case GuardClassKind::PlainObject
:
385 return &PlainObject::class_
;
386 case GuardClassKind::ArrayBuffer
:
387 return &ArrayBufferObject::class_
;
388 case GuardClassKind::SharedArrayBuffer
:
389 return &SharedArrayBufferObject::class_
;
390 case GuardClassKind::DataView
:
391 return &DataViewObject::class_
;
392 case GuardClassKind::MappedArguments
:
393 return &MappedArgumentsObject::class_
;
394 case GuardClassKind::UnmappedArguments
:
395 return &UnmappedArgumentsObject::class_
;
396 case GuardClassKind::WindowProxy
:
397 return mirGen().runtime
->maybeWindowProxyClass();
398 case GuardClassKind::Set
:
399 return &SetObject::class_
;
400 case GuardClassKind::Map
:
401 return &MapObject::class_
;
402 case GuardClassKind::BoundFunction
:
403 return &BoundFunctionObject::class_
;
404 case GuardClassKind::JSFunction
:
407 MOZ_CRASH("unexpected kind");
410 bool WarpCacheIRTranspiler::emitGuardAnyClass(ObjOperandId objId
,
411 uint32_t claspOffset
) {
412 MDefinition
* def
= getOperand(objId
);
413 const JSClass
* classp
= classStubField(claspOffset
);
415 auto* ins
= MGuardToClass::New(alloc(), def
, classp
);
418 setOperand(objId
, ins
);
422 bool WarpCacheIRTranspiler::emitGuardShape(ObjOperandId objId
,
423 uint32_t shapeOffset
) {
424 MDefinition
* def
= getOperand(objId
);
426 // No read barrier is required because snapshot data is not weak and is traced
427 // as part of IonCompileTask.
428 Shape
* shape
= shapeStubField(shapeOffset
);
430 auto* ins
= MGuardShape::New(alloc(), def
, shape
);
433 setOperand(objId
, ins
);
437 bool WarpCacheIRTranspiler::emitGuardMultipleShapes(ObjOperandId objId
,
438 uint32_t shapesOffset
) {
439 MDefinition
* def
= getOperand(objId
);
440 MInstruction
* shapeList
= objectStubField(shapesOffset
);
442 auto* ins
= MGuardMultipleShapes::New(alloc(), def
, shapeList
);
443 if (builder_
->isMonomorphicInlined()) {
444 ins
->setBailoutKind(BailoutKind::MonomorphicInlinedStubFolding
);
448 setOperand(objId
, ins
);
452 bool WarpCacheIRTranspiler::emitGuardNullProto(ObjOperandId objId
) {
453 MDefinition
* def
= getOperand(objId
);
455 auto* ins
= MGuardNullProto::New(alloc(), def
);
458 setOperand(objId
, ins
);
462 bool WarpCacheIRTranspiler::emitGuardIsNativeObject(ObjOperandId objId
) {
463 MDefinition
* obj
= getOperand(objId
);
465 auto* ins
= MGuardIsNativeObject::New(alloc(), obj
);
468 setOperand(objId
, ins
);
472 bool WarpCacheIRTranspiler::emitGuardIsProxy(ObjOperandId objId
) {
473 MDefinition
* obj
= getOperand(objId
);
475 auto* ins
= MGuardIsProxy::New(alloc(), obj
);
478 setOperand(objId
, ins
);
482 bool WarpCacheIRTranspiler::emitGuardIsNotProxy(ObjOperandId objId
) {
483 MDefinition
* obj
= getOperand(objId
);
485 auto* ins
= MGuardIsNotProxy::New(alloc(), obj
);
488 setOperand(objId
, ins
);
492 bool WarpCacheIRTranspiler::emitGuardIsNotDOMProxy(ObjOperandId objId
) {
493 MDefinition
* obj
= getOperand(objId
);
495 auto* ins
= MGuardIsNotDOMProxy::New(alloc(), obj
);
498 setOperand(objId
, ins
);
502 bool WarpCacheIRTranspiler::emitGuardHasGetterSetter(
503 ObjOperandId objId
, uint32_t idOffset
, uint32_t getterSetterOffset
) {
504 MDefinition
* obj
= getOperand(objId
);
505 jsid id
= idStubField(idOffset
);
506 GetterSetter
* gs
= getterSetterStubField(getterSetterOffset
);
508 auto* ins
= MGuardHasGetterSetter::New(alloc(), obj
, id
, gs
);
511 setOperand(objId
, ins
);
515 bool WarpCacheIRTranspiler::emitProxyGetResult(ObjOperandId objId
,
517 MDefinition
* obj
= getOperand(objId
);
518 jsid id
= idStubField(idOffset
);
520 auto* ins
= MProxyGet::New(alloc(), obj
, id
);
524 return resumeAfter(ins
);
527 bool WarpCacheIRTranspiler::emitProxyGetByValueResult(ObjOperandId objId
,
529 MDefinition
* obj
= getOperand(objId
);
530 MDefinition
* id
= getOperand(idId
);
532 auto* ins
= MProxyGetByValue::New(alloc(), obj
, id
);
536 return resumeAfter(ins
);
539 bool WarpCacheIRTranspiler::emitProxyHasPropResult(ObjOperandId objId
,
542 MDefinition
* obj
= getOperand(objId
);
543 MDefinition
* id
= getOperand(idId
);
545 auto* ins
= MProxyHasProp::New(alloc(), obj
, id
, hasOwn
);
549 return resumeAfter(ins
);
552 bool WarpCacheIRTranspiler::emitProxySet(ObjOperandId objId
, uint32_t idOffset
,
553 ValOperandId rhsId
, bool strict
) {
554 MDefinition
* obj
= getOperand(objId
);
555 jsid id
= idStubField(idOffset
);
556 MDefinition
* rhs
= getOperand(rhsId
);
558 auto* ins
= MProxySet::New(alloc(), obj
, rhs
, id
, strict
);
561 return resumeAfter(ins
);
564 bool WarpCacheIRTranspiler::emitProxySetByValue(ObjOperandId objId
,
568 MDefinition
* obj
= getOperand(objId
);
569 MDefinition
* id
= getOperand(idId
);
570 MDefinition
* rhs
= getOperand(rhsId
);
572 auto* ins
= MProxySetByValue::New(alloc(), obj
, id
, rhs
, strict
);
575 return resumeAfter(ins
);
578 bool WarpCacheIRTranspiler::emitCallSetArrayLength(ObjOperandId objId
,
580 ValOperandId rhsId
) {
581 MDefinition
* obj
= getOperand(objId
);
582 MDefinition
* rhs
= getOperand(rhsId
);
584 auto* ins
= MCallSetArrayLength::New(alloc(), obj
, rhs
, strict
);
587 return resumeAfter(ins
);
590 bool WarpCacheIRTranspiler::emitCallDOMGetterResult(ObjOperandId objId
,
591 uint32_t jitInfoOffset
) {
592 MDefinition
* obj
= getOperand(objId
);
593 const JSJitInfo
* jitInfo
= jitInfoStubField(jitInfoOffset
);
596 if (jitInfo
->isAlwaysInSlot
) {
597 ins
= MGetDOMMember::New(alloc(), jitInfo
, obj
, nullptr, nullptr);
599 // TODO(post-Warp): realms, guard operands (movable?).
600 ins
= MGetDOMProperty::New(alloc(), jitInfo
, DOMObjectKind::Native
,
601 (JS::Realm
*)mirGen().realm
->realmPtr(), obj
,
609 if (ins
->isEffectful()) {
612 return resumeAfter(ins
);
620 bool WarpCacheIRTranspiler::emitCallDOMSetter(ObjOperandId objId
,
621 uint32_t jitInfoOffset
,
622 ValOperandId rhsId
) {
623 MDefinition
* obj
= getOperand(objId
);
624 const JSJitInfo
* jitInfo
= jitInfoStubField(jitInfoOffset
);
625 MDefinition
* value
= getOperand(rhsId
);
627 MOZ_ASSERT(jitInfo
->type() == JSJitInfo::Setter
);
629 MSetDOMProperty::New(alloc(), jitInfo
->setter
, DOMObjectKind::Native
,
630 (JS::Realm
*)mirGen().realm
->realmPtr(), obj
, value
);
632 return resumeAfter(set
);
635 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValue(ObjOperandId objId
,
636 ValOperandId resultId
) {
637 MDefinition
* proxy
= getOperand(objId
);
639 auto* ins
= MLoadDOMExpandoValue::New(alloc(), proxy
);
642 return defineOperand(resultId
, ins
);
645 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueGuardGeneration(
646 ObjOperandId objId
, uint32_t expandoAndGenerationOffset
,
647 uint32_t generationOffset
, ValOperandId resultId
) {
648 MDefinition
* proxy
= getOperand(objId
);
649 JS::ExpandoAndGeneration
* expandoAndGeneration
=
650 expandoAndGenerationField(expandoAndGenerationOffset
);
651 uint64_t generation
= uint64StubField(generationOffset
);
653 auto* ins
= MLoadDOMExpandoValueGuardGeneration::New(
654 alloc(), proxy
, expandoAndGeneration
, generation
);
657 return defineOperand(resultId
, ins
);
660 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueIgnoreGeneration(
661 ObjOperandId objId
, ValOperandId resultId
) {
662 MDefinition
* proxy
= getOperand(objId
);
664 auto* ins
= MLoadDOMExpandoValueIgnoreGeneration::New(alloc(), proxy
);
667 return defineOperand(resultId
, ins
);
670 bool WarpCacheIRTranspiler::emitGuardDOMExpandoMissingOrGuardShape(
671 ValOperandId expandoId
, uint32_t shapeOffset
) {
672 MDefinition
* expando
= getOperand(expandoId
);
673 Shape
* shape
= shapeStubField(shapeOffset
);
675 auto* ins
= MGuardDOMExpandoMissingOrGuardShape::New(alloc(), expando
, shape
);
678 setOperand(expandoId
, ins
);
682 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotResult(ObjOperandId objId
,
683 uint32_t nameOffset
) {
684 MDefinition
* obj
= getOperand(objId
);
685 PropertyName
* name
= stringStubField(nameOffset
)->asAtom().asPropertyName();
687 auto* ins
= MMegamorphicLoadSlot::New(alloc(), obj
, NameToId(name
));
694 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValueResult(
695 ObjOperandId objId
, ValOperandId idId
) {
696 MDefinition
* obj
= getOperand(objId
);
697 MDefinition
* id
= getOperand(idId
);
699 auto* ins
= MMegamorphicLoadSlotByValue::New(alloc(), obj
, id
);
706 bool WarpCacheIRTranspiler::emitMegamorphicStoreSlot(ObjOperandId objId
,
710 MDefinition
* obj
= getOperand(objId
);
711 jsid id
= idStubField(idOffset
);
712 MDefinition
* rhs
= getOperand(rhsId
);
714 auto* ins
= MMegamorphicStoreSlot::New(alloc(), obj
, rhs
, id
, strict
);
717 return resumeAfter(ins
);
720 bool WarpCacheIRTranspiler::emitMegamorphicHasPropResult(ObjOperandId objId
,
723 MDefinition
* obj
= getOperand(objId
);
724 MDefinition
* id
= getOperand(idId
);
726 auto* ins
= MMegamorphicHasProp::New(alloc(), obj
, id
, hasOwn
);
733 bool WarpCacheIRTranspiler::emitMegamorphicSetElement(ObjOperandId objId
,
737 MDefinition
* obj
= getOperand(objId
);
738 MDefinition
* id
= getOperand(idId
);
739 MDefinition
* rhs
= getOperand(rhsId
);
741 auto* ins
= MMegamorphicSetElement::New(alloc(), obj
, id
, rhs
, strict
);
744 return resumeAfter(ins
);
747 bool WarpCacheIRTranspiler::emitObjectToIteratorResult(
748 ObjOperandId objId
, uint32_t enumeratorsAddrOffset
) {
749 MDefinition
* obj
= getOperand(objId
);
750 NativeIteratorListHead
* enumeratorsAddr
=
751 nativeIteratorListHeadStubField(enumeratorsAddrOffset
);
753 auto* ins
= MObjectToIterator::New(alloc(), obj
, enumeratorsAddr
);
756 if (!resumeAfter(ins
)) {
763 bool WarpCacheIRTranspiler::emitValueToIteratorResult(ValOperandId valId
) {
764 MDefinition
* val
= getOperand(valId
);
766 auto* ins
= MValueToIterator::New(alloc(), val
);
770 return resumeAfter(ins
);
773 bool WarpCacheIRTranspiler::emitGuardIsNotArrayBufferMaybeShared(
774 ObjOperandId objId
) {
775 MDefinition
* obj
= getOperand(objId
);
777 auto* ins
= MGuardIsNotArrayBufferMaybeShared::New(alloc(), obj
);
780 setOperand(objId
, ins
);
784 bool WarpCacheIRTranspiler::emitGuardIsTypedArray(ObjOperandId objId
) {
785 MDefinition
* obj
= getOperand(objId
);
787 auto* ins
= MGuardIsTypedArray::New(alloc(), obj
);
790 setOperand(objId
, ins
);
794 bool WarpCacheIRTranspiler::emitGuardProto(ObjOperandId objId
,
795 uint32_t protoOffset
) {
796 MDefinition
* def
= getOperand(objId
);
797 MDefinition
* proto
= objectStubField(protoOffset
);
799 auto* ins
= MGuardProto::New(alloc(), def
, proto
);
802 setOperand(objId
, ins
);
806 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsSpecificObject(
807 ObjOperandId objId
, ObjOperandId expectedId
, uint32_t slotOffset
) {
808 size_t slotIndex
= int32StubField(slotOffset
);
809 MDefinition
* obj
= getOperand(objId
);
810 MDefinition
* expected
= getOperand(expectedId
);
812 auto* slots
= MSlots::New(alloc(), obj
);
815 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
818 auto* unbox
= MUnbox::New(alloc(), load
, MIRType::Object
, MUnbox::Fallible
);
821 auto* guard
= MGuardObjectIdentity::New(alloc(), unbox
, expected
,
822 /* bailOnEquality = */ false);
827 bool WarpCacheIRTranspiler::emitLoadDynamicSlot(ValOperandId resultId
,
829 uint32_t slotOffset
) {
830 size_t slotIndex
= int32StubField(slotOffset
);
831 MDefinition
* obj
= getOperand(objId
);
833 auto* slots
= MSlots::New(alloc(), obj
);
836 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
839 return defineOperand(resultId
, load
);
842 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsNotObject(
843 ObjOperandId objId
, uint32_t slotOffset
) {
844 size_t slotIndex
= int32StubField(slotOffset
);
845 MDefinition
* obj
= getOperand(objId
);
847 auto* slots
= MSlots::New(alloc(), obj
);
850 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
853 auto* guard
= MGuardIsNotObject::New(alloc(), load
);
858 bool WarpCacheIRTranspiler::emitGuardFixedSlotValue(ObjOperandId objId
,
859 uint32_t offsetOffset
,
860 uint32_t valOffset
) {
861 MDefinition
* obj
= getOperand(objId
);
863 size_t offset
= int32StubField(offsetOffset
);
864 Value val
= valueStubField(valOffset
);
866 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
868 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
871 auto* guard
= MGuardValue::New(alloc(), load
, val
);
876 bool WarpCacheIRTranspiler::emitGuardDynamicSlotValue(ObjOperandId objId
,
877 uint32_t offsetOffset
,
878 uint32_t valOffset
) {
879 MDefinition
* obj
= getOperand(objId
);
881 size_t offset
= int32StubField(offsetOffset
);
882 Value val
= valueStubField(valOffset
);
884 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
886 auto* slots
= MSlots::New(alloc(), obj
);
889 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
892 auto* guard
= MGuardValue::New(alloc(), load
, val
);
897 bool WarpCacheIRTranspiler::emitGuardSpecificAtom(StringOperandId strId
,
898 uint32_t expectedOffset
) {
899 MDefinition
* str
= getOperand(strId
);
900 JSString
* expected
= stringStubField(expectedOffset
);
902 auto* ins
= MGuardSpecificAtom::New(alloc(), str
, &expected
->asAtom());
905 setOperand(strId
, ins
);
909 bool WarpCacheIRTranspiler::emitGuardSpecificSymbol(SymbolOperandId symId
,
910 uint32_t expectedOffset
) {
911 MDefinition
* symbol
= getOperand(symId
);
912 JS::Symbol
* expected
= symbolStubField(expectedOffset
);
914 auto* ins
= MGuardSpecificSymbol::New(alloc(), symbol
, expected
);
917 setOperand(symId
, ins
);
921 bool WarpCacheIRTranspiler::emitGuardSpecificInt32(Int32OperandId numId
,
923 MDefinition
* num
= getOperand(numId
);
925 auto* ins
= MGuardSpecificInt32::New(alloc(), num
, expected
);
928 setOperand(numId
, ins
);
932 bool WarpCacheIRTranspiler::emitGuardSpecificObject(ObjOperandId objId
,
933 uint32_t expectedOffset
) {
934 MDefinition
* obj
= getOperand(objId
);
935 MDefinition
* expected
= objectStubField(expectedOffset
);
937 auto* ins
= MGuardObjectIdentity::New(alloc(), obj
, expected
,
938 /* bailOnEquality = */ false);
941 setOperand(objId
, ins
);
945 bool WarpCacheIRTranspiler::emitGuardSpecificFunction(
946 ObjOperandId objId
, uint32_t expectedOffset
, uint32_t nargsAndFlagsOffset
) {
947 MDefinition
* obj
= getOperand(objId
);
948 MDefinition
* expected
= objectStubField(expectedOffset
);
949 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
951 uint16_t nargs
= nargsAndFlags
>> 16;
952 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
954 auto* ins
= MGuardSpecificFunction::New(alloc(), obj
, expected
, nargs
, flags
);
957 setOperand(objId
, ins
);
961 bool WarpCacheIRTranspiler::emitGuardFunctionScript(
962 ObjOperandId funId
, uint32_t expectedOffset
, uint32_t nargsAndFlagsOffset
) {
963 MDefinition
* fun
= getOperand(funId
);
964 BaseScript
* expected
= baseScriptStubField(expectedOffset
);
965 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
967 uint16_t nargs
= nargsAndFlags
>> 16;
968 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
970 auto* ins
= MGuardFunctionScript::New(alloc(), fun
, expected
, nargs
, flags
);
973 setOperand(funId
, ins
);
977 bool WarpCacheIRTranspiler::emitGuardStringToIndex(StringOperandId strId
,
978 Int32OperandId resultId
) {
979 MDefinition
* str
= getOperand(strId
);
981 auto* ins
= MGuardStringToIndex::New(alloc(), str
);
984 return defineOperand(resultId
, ins
);
987 bool WarpCacheIRTranspiler::emitGuardStringToInt32(StringOperandId strId
,
988 Int32OperandId resultId
) {
989 MDefinition
* str
= getOperand(strId
);
991 auto* ins
= MGuardStringToInt32::New(alloc(), str
);
994 return defineOperand(resultId
, ins
);
997 bool WarpCacheIRTranspiler::emitGuardStringToNumber(StringOperandId strId
,
998 NumberOperandId resultId
) {
999 MDefinition
* str
= getOperand(strId
);
1001 auto* ins
= MGuardStringToDouble::New(alloc(), str
);
1004 return defineOperand(resultId
, ins
);
1007 bool WarpCacheIRTranspiler::emitGuardNoDenseElements(ObjOperandId objId
) {
1008 MDefinition
* obj
= getOperand(objId
);
1010 auto* ins
= MGuardNoDenseElements::New(alloc(), obj
);
1013 setOperand(objId
, ins
);
1017 bool WarpCacheIRTranspiler::emitGuardFunctionHasJitEntry(ObjOperandId funId
,
1018 bool constructing
) {
1019 MDefinition
* fun
= getOperand(funId
);
1020 uint16_t expectedFlags
= FunctionFlags::HasJitEntryFlags(constructing
);
1021 uint16_t unexpectedFlags
= 0;
1024 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1027 setOperand(funId
, ins
);
1031 bool WarpCacheIRTranspiler::emitGuardFunctionHasNoJitEntry(ObjOperandId funId
) {
1032 MDefinition
* fun
= getOperand(funId
);
1033 uint16_t expectedFlags
= 0;
1034 uint16_t unexpectedFlags
=
1035 FunctionFlags::HasJitEntryFlags(/*isConstructing=*/false);
1038 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1041 setOperand(funId
, ins
);
1045 bool WarpCacheIRTranspiler::emitGuardFunctionIsNonBuiltinCtor(
1046 ObjOperandId funId
) {
1047 MDefinition
* fun
= getOperand(funId
);
1049 auto* ins
= MGuardFunctionIsNonBuiltinCtor::New(alloc(), fun
);
1052 setOperand(funId
, ins
);
1056 bool WarpCacheIRTranspiler::emitGuardFunctionIsConstructor(ObjOperandId funId
) {
1057 MDefinition
* fun
= getOperand(funId
);
1058 uint16_t expectedFlags
= FunctionFlags::CONSTRUCTOR
;
1059 uint16_t unexpectedFlags
= 0;
1062 MGuardFunctionFlags::New(alloc(), fun
, expectedFlags
, unexpectedFlags
);
1065 setOperand(funId
, ins
);
1069 bool WarpCacheIRTranspiler::emitGuardNotClassConstructor(ObjOperandId funId
) {
1070 MDefinition
* fun
= getOperand(funId
);
1073 MGuardFunctionKind::New(alloc(), fun
, FunctionFlags::ClassConstructor
,
1074 /*bailOnEquality=*/true);
1077 setOperand(funId
, ins
);
1081 bool WarpCacheIRTranspiler::emitGuardArrayIsPacked(ObjOperandId arrayId
) {
1082 MDefinition
* array
= getOperand(arrayId
);
1084 auto* ins
= MGuardArrayIsPacked::New(alloc(), array
);
1087 setOperand(arrayId
, ins
);
1091 bool WarpCacheIRTranspiler::emitGuardArgumentsObjectFlags(ObjOperandId objId
,
1093 MDefinition
* obj
= getOperand(objId
);
1095 auto* ins
= MGuardArgumentsObjectFlags::New(alloc(), obj
, flags
);
1098 setOperand(objId
, ins
);
1102 bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId
,
1105 case ValueType::String
:
1106 case ValueType::Symbol
:
1107 case ValueType::BigInt
:
1108 case ValueType::Int32
:
1109 case ValueType::Boolean
:
1110 return emitGuardTo(inputId
, MIRTypeFromValueType(JSValueType(type
)));
1111 case ValueType::Undefined
:
1112 return emitGuardIsUndefined(inputId
);
1113 case ValueType::Null
:
1114 return emitGuardIsNull(inputId
);
1115 case ValueType::Double
:
1116 case ValueType::Magic
:
1117 case ValueType::PrivateGCThing
:
1118 case ValueType::Object
:
1119 #ifdef ENABLE_RECORD_TUPLE
1120 case ValueType::ExtendedPrimitive
:
1125 MOZ_CRASH("unexpected type");
1128 bool WarpCacheIRTranspiler::emitGuardTo(ValOperandId inputId
, MIRType type
) {
1129 MDefinition
* def
= getOperand(inputId
);
1130 if (def
->type() == type
) {
1134 auto* ins
= MUnbox::New(alloc(), def
, type
, MUnbox::Fallible
);
1137 setOperand(inputId
, ins
);
1141 bool WarpCacheIRTranspiler::emitGuardToObject(ValOperandId inputId
) {
1142 return emitGuardTo(inputId
, MIRType::Object
);
1145 bool WarpCacheIRTranspiler::emitGuardToString(ValOperandId inputId
) {
1146 return emitGuardTo(inputId
, MIRType::String
);
1149 bool WarpCacheIRTranspiler::emitGuardToSymbol(ValOperandId inputId
) {
1150 return emitGuardTo(inputId
, MIRType::Symbol
);
1153 bool WarpCacheIRTranspiler::emitGuardToBigInt(ValOperandId inputId
) {
1154 return emitGuardTo(inputId
, MIRType::BigInt
);
1157 bool WarpCacheIRTranspiler::emitGuardToBoolean(ValOperandId inputId
) {
1158 return emitGuardTo(inputId
, MIRType::Boolean
);
1161 bool WarpCacheIRTranspiler::emitGuardToInt32(ValOperandId inputId
) {
1162 return emitGuardTo(inputId
, MIRType::Int32
);
1165 bool WarpCacheIRTranspiler::emitGuardBooleanToInt32(ValOperandId inputId
,
1166 Int32OperandId resultId
) {
1167 MDefinition
* input
= getOperand(inputId
);
1169 auto* ins
= MBooleanToInt32::New(alloc(), input
);
1172 return defineOperand(resultId
, ins
);
1175 bool WarpCacheIRTranspiler::emitGuardIsNumber(ValOperandId inputId
) {
1176 // Prefer MToDouble because it gets further optimizations downstream.
1177 MDefinition
* def
= getOperand(inputId
);
1178 if (def
->type() == MIRType::Int32
) {
1179 auto* ins
= MToDouble::New(alloc(), def
);
1182 setOperand(inputId
, ins
);
1186 // MIRType::Double also implies int32 in Ion.
1187 return emitGuardTo(inputId
, MIRType::Double
);
1190 bool WarpCacheIRTranspiler::emitGuardIsNullOrUndefined(ValOperandId inputId
) {
1191 MDefinition
* input
= getOperand(inputId
);
1192 if (input
->type() == MIRType::Null
|| input
->type() == MIRType::Undefined
) {
1196 auto* ins
= MGuardNullOrUndefined::New(alloc(), input
);
1199 setOperand(inputId
, ins
);
1203 bool WarpCacheIRTranspiler::emitGuardIsNull(ValOperandId inputId
) {
1204 MDefinition
* input
= getOperand(inputId
);
1205 if (input
->type() == MIRType::Null
) {
1209 auto* ins
= MGuardValue::New(alloc(), input
, NullValue());
1211 setOperand(inputId
, ins
);
1215 bool WarpCacheIRTranspiler::emitGuardIsUndefined(ValOperandId inputId
) {
1216 MDefinition
* input
= getOperand(inputId
);
1217 if (input
->type() == MIRType::Undefined
) {
1221 auto* ins
= MGuardValue::New(alloc(), input
, UndefinedValue());
1223 setOperand(inputId
, ins
);
1227 bool WarpCacheIRTranspiler::emitGuardIsExtensible(ObjOperandId objId
) {
1228 MDefinition
* obj
= getOperand(objId
);
1230 auto* ins
= MGuardIsExtensible::New(alloc(), obj
);
1232 setOperand(objId
, ins
);
1236 bool WarpCacheIRTranspiler::emitGuardInt32IsNonNegative(
1237 Int32OperandId indexId
) {
1238 MDefinition
* index
= getOperand(indexId
);
1240 auto* ins
= MGuardInt32IsNonNegative::New(alloc(), index
);
1242 setOperand(indexId
, ins
);
1246 bool WarpCacheIRTranspiler::emitGuardIndexIsNotDenseElement(
1247 ObjOperandId objId
, Int32OperandId indexId
) {
1248 MDefinition
* obj
= getOperand(objId
);
1249 MDefinition
* index
= getOperand(indexId
);
1251 auto* ins
= MGuardIndexIsNotDenseElement::New(alloc(), obj
, index
);
1253 setOperand(indexId
, ins
);
1257 bool WarpCacheIRTranspiler::emitGuardIndexIsValidUpdateOrAdd(
1258 ObjOperandId objId
, Int32OperandId indexId
) {
1259 MDefinition
* obj
= getOperand(objId
);
1260 MDefinition
* index
= getOperand(indexId
);
1262 auto* ins
= MGuardIndexIsValidUpdateOrAdd::New(alloc(), obj
, index
);
1264 setOperand(indexId
, ins
);
1268 bool WarpCacheIRTranspiler::emitCallAddOrUpdateSparseElementHelper(
1269 ObjOperandId objId
, Int32OperandId idId
, ValOperandId rhsId
, bool strict
) {
1270 MDefinition
* obj
= getOperand(objId
);
1271 MDefinition
* id
= getOperand(idId
);
1272 MDefinition
* rhs
= getOperand(rhsId
);
1274 auto* ins
= MCallAddOrUpdateSparseElement::New(alloc(), obj
, id
, rhs
, strict
);
1277 return resumeAfter(ins
);
1280 bool WarpCacheIRTranspiler::emitGuardTagNotEqual(ValueTagOperandId lhsId
,
1281 ValueTagOperandId rhsId
) {
1282 MDefinition
* lhs
= getOperand(lhsId
);
1283 MDefinition
* rhs
= getOperand(rhsId
);
1285 auto* ins
= MGuardTagNotEqual::New(alloc(), lhs
, rhs
);
1291 bool WarpCacheIRTranspiler::emitGuardToInt32Index(ValOperandId inputId
,
1292 Int32OperandId resultId
) {
1293 MDefinition
* input
= getOperand(inputId
);
1295 MToNumberInt32::New(alloc(), input
, IntConversionInputKind::NumbersOnly
);
1297 // ToPropertyKey(-0) is "0", so we can silently convert -0 to 0 here.
1298 ins
->setNeedsNegativeZeroCheck(false);
1301 return defineOperand(resultId
, ins
);
1304 bool WarpCacheIRTranspiler::emitTruncateDoubleToUInt32(
1305 NumberOperandId inputId
, Int32OperandId resultId
) {
1306 MDefinition
* input
= getOperand(inputId
);
1307 auto* ins
= MTruncateToInt32::New(alloc(), input
);
1310 return defineOperand(resultId
, ins
);
1313 bool WarpCacheIRTranspiler::emitGuardToInt32ModUint32(ValOperandId valId
,
1314 Int32OperandId resultId
) {
1315 MDefinition
* input
= getOperand(valId
);
1316 auto* ins
= MTruncateToInt32::New(alloc(), input
);
1319 return defineOperand(resultId
, ins
);
1322 bool WarpCacheIRTranspiler::emitGuardToUint8Clamped(ValOperandId valId
,
1323 Int32OperandId resultId
) {
1324 MDefinition
* input
= getOperand(valId
);
1325 auto* ins
= MClampToUint8::New(alloc(), input
);
1328 return defineOperand(resultId
, ins
);
1331 bool WarpCacheIRTranspiler::emitToString(OperandId inputId
,
1332 StringOperandId resultId
) {
1333 MDefinition
* input
= getOperand(inputId
);
1335 MToString::New(alloc(), input
, MToString::SideEffectHandling::Bailout
);
1338 return defineOperand(resultId
, ins
);
1341 bool WarpCacheIRTranspiler::emitInt32ToIntPtr(Int32OperandId inputId
,
1342 IntPtrOperandId resultId
) {
1343 MDefinition
* input
= getOperand(inputId
);
1344 auto* ins
= MInt32ToIntPtr::New(alloc(), input
);
1346 return defineOperand(resultId
, ins
);
1349 bool WarpCacheIRTranspiler::emitGuardNumberToIntPtrIndex(
1350 NumberOperandId inputId
, bool supportOOB
, IntPtrOperandId resultId
) {
1351 MDefinition
* input
= getOperand(inputId
);
1352 auto* ins
= MGuardNumberToIntPtrIndex::New(alloc(), input
, supportOOB
);
1354 return defineOperand(resultId
, ins
);
1357 bool WarpCacheIRTranspiler::emitCallInt32ToString(Int32OperandId inputId
,
1358 StringOperandId resultId
) {
1359 return emitToString(inputId
, resultId
);
1362 bool WarpCacheIRTranspiler::emitCallNumberToString(NumberOperandId inputId
,
1363 StringOperandId resultId
) {
1364 return emitToString(inputId
, resultId
);
1367 bool WarpCacheIRTranspiler::emitInt32ToStringWithBaseResult(
1368 Int32OperandId inputId
, Int32OperandId baseId
) {
1369 MDefinition
* input
= getOperand(inputId
);
1370 MDefinition
* base
= getOperand(baseId
);
1372 auto* guardedBase
= MGuardInt32Range::New(alloc(), base
, 2, 36);
1375 auto* ins
= MInt32ToStringWithBase::New(alloc(), input
, guardedBase
);
1382 bool WarpCacheIRTranspiler::emitBooleanToString(BooleanOperandId inputId
,
1383 StringOperandId resultId
) {
1384 return emitToString(inputId
, resultId
);
1387 bool WarpCacheIRTranspiler::emitBooleanToNumber(BooleanOperandId inputId
,
1388 NumberOperandId resultId
) {
1389 MDefinition
* input
= getOperand(inputId
);
1391 auto* ins
= MToDouble::New(alloc(), input
);
1394 return defineOperand(resultId
, ins
);
1397 bool WarpCacheIRTranspiler::emitLoadInt32Result(Int32OperandId valId
) {
1398 MDefinition
* val
= getOperand(valId
);
1399 MOZ_ASSERT(val
->type() == MIRType::Int32
);
1404 bool WarpCacheIRTranspiler::emitLoadDoubleResult(NumberOperandId valId
) {
1405 MDefinition
* val
= getOperand(valId
);
1406 MOZ_ASSERT(val
->type() == MIRType::Double
);
1411 bool WarpCacheIRTranspiler::emitLoadBigIntResult(BigIntOperandId valId
) {
1412 MDefinition
* val
= getOperand(valId
);
1413 MOZ_ASSERT(val
->type() == MIRType::BigInt
);
1418 bool WarpCacheIRTranspiler::emitLoadObjectResult(ObjOperandId objId
) {
1419 MDefinition
* obj
= getOperand(objId
);
1420 MOZ_ASSERT(obj
->type() == MIRType::Object
);
1425 bool WarpCacheIRTranspiler::emitLoadStringResult(StringOperandId strId
) {
1426 MDefinition
* str
= getOperand(strId
);
1427 MOZ_ASSERT(str
->type() == MIRType::String
);
1432 bool WarpCacheIRTranspiler::emitLoadSymbolResult(SymbolOperandId symId
) {
1433 MDefinition
* sym
= getOperand(symId
);
1434 MOZ_ASSERT(sym
->type() == MIRType::Symbol
);
1439 bool WarpCacheIRTranspiler::emitLoadUndefinedResult() {
1440 pushResult(constant(UndefinedValue()));
1444 bool WarpCacheIRTranspiler::emitLoadBooleanResult(bool val
) {
1445 pushResult(constant(BooleanValue(val
)));
1449 bool WarpCacheIRTranspiler::emitLoadInt32Constant(uint32_t valOffset
,
1450 Int32OperandId resultId
) {
1451 int32_t val
= int32StubField(valOffset
);
1452 auto* valConst
= constant(Int32Value(val
));
1453 return defineOperand(resultId
, valConst
);
1456 bool WarpCacheIRTranspiler::emitLoadDoubleConstant(uint32_t valOffset
,
1457 NumberOperandId resultId
) {
1458 double val
= doubleStubField(valOffset
);
1459 auto* valConst
= constant(DoubleValue(val
));
1460 return defineOperand(resultId
, valConst
);
1463 bool WarpCacheIRTranspiler::emitLoadBooleanConstant(bool val
,
1464 BooleanOperandId resultId
) {
1465 auto* valConst
= constant(BooleanValue(val
));
1466 return defineOperand(resultId
, valConst
);
1469 bool WarpCacheIRTranspiler::emitLoadUndefined(ValOperandId resultId
) {
1470 auto* valConst
= constant(UndefinedValue());
1471 return defineOperand(resultId
, valConst
);
1474 bool WarpCacheIRTranspiler::emitLoadConstantString(uint32_t strOffset
,
1475 StringOperandId resultId
) {
1476 JSString
* val
= stringStubField(strOffset
);
1477 auto* valConst
= constant(StringValue(val
));
1478 return defineOperand(resultId
, valConst
);
1481 bool WarpCacheIRTranspiler::emitLoadConstantStringResult(uint32_t strOffset
) {
1482 JSString
* val
= stringStubField(strOffset
);
1483 auto* valConst
= constant(StringValue(val
));
1484 pushResult(valConst
);
1488 bool WarpCacheIRTranspiler::emitLoadTypeOfObjectResult(ObjOperandId objId
) {
1489 MDefinition
* obj
= getOperand(objId
);
1490 auto* typeOf
= MTypeOf::New(alloc(), obj
);
1493 auto* ins
= MTypeOfName::New(alloc(), typeOf
);
1499 bool WarpCacheIRTranspiler::emitLoadEnclosingEnvironment(
1500 ObjOperandId objId
, ObjOperandId resultId
) {
1501 MDefinition
* env
= getOperand(objId
);
1502 auto* ins
= MEnclosingEnvironment::New(alloc(), env
);
1505 return defineOperand(resultId
, ins
);
1508 bool WarpCacheIRTranspiler::emitLoadObject(ObjOperandId resultId
,
1509 uint32_t objOffset
) {
1510 MInstruction
* ins
= objectStubField(objOffset
);
1512 return defineOperand(resultId
, ins
);
1515 bool WarpCacheIRTranspiler::emitLoadProtoObject(ObjOperandId resultId
,
1517 ObjOperandId receiverObjId
) {
1518 MInstruction
* ins
= objectStubField(objOffset
);
1519 if (ins
->isConstant()) {
1520 MDefinition
* receiverObj
= getOperand(receiverObjId
);
1522 ins
= MConstantProto::New(alloc(), ins
, receiverObj
->skipObjectGuards());
1525 return defineOperand(resultId
, ins
);
1528 bool WarpCacheIRTranspiler::emitLoadProto(ObjOperandId objId
,
1529 ObjOperandId resultId
) {
1530 MDefinition
* obj
= getOperand(objId
);
1532 auto* ins
= MObjectStaticProto::New(alloc(), obj
);
1535 return defineOperand(resultId
, ins
);
1538 bool WarpCacheIRTranspiler::emitLoadInstanceOfObjectResult(
1539 ValOperandId lhsId
, ObjOperandId protoId
) {
1540 MDefinition
* lhs
= getOperand(lhsId
);
1541 MDefinition
* proto
= getOperand(protoId
);
1543 auto* instanceOf
= MInstanceOf::New(alloc(), lhs
, proto
);
1544 addEffectful(instanceOf
);
1546 pushResult(instanceOf
);
1547 return resumeAfter(instanceOf
);
1550 bool WarpCacheIRTranspiler::emitLoadValueTag(ValOperandId valId
,
1551 ValueTagOperandId resultId
) {
1552 MDefinition
* val
= getOperand(valId
);
1554 auto* ins
= MLoadValueTag::New(alloc(), val
);
1557 return defineOperand(resultId
, ins
);
1560 bool WarpCacheIRTranspiler::emitLoadDynamicSlotResult(ObjOperandId objId
,
1561 uint32_t offsetOffset
) {
1562 int32_t offset
= int32StubField(offsetOffset
);
1564 MDefinition
* obj
= getOperand(objId
);
1565 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
1567 auto* slots
= MSlots::New(alloc(), obj
);
1570 auto* load
= MLoadDynamicSlot::New(alloc(), slots
, slotIndex
);
1577 bool WarpCacheIRTranspiler::emitLoadFixedSlot(ValOperandId resultId
,
1579 uint32_t offsetOffset
) {
1580 MDefinition
* obj
= getOperand(objId
);
1582 size_t offset
= int32StubField(offsetOffset
);
1583 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1585 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1588 return defineOperand(resultId
, load
);
1591 bool WarpCacheIRTranspiler::emitLoadFixedSlotResult(ObjOperandId objId
,
1592 uint32_t offsetOffset
) {
1593 int32_t offset
= int32StubField(offsetOffset
);
1595 MDefinition
* obj
= getOperand(objId
);
1596 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1598 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1605 bool WarpCacheIRTranspiler::emitLoadFixedSlotTypedResult(ObjOperandId objId
,
1606 uint32_t offsetOffset
,
1608 int32_t offset
= int32StubField(offsetOffset
);
1610 MDefinition
* obj
= getOperand(objId
);
1611 uint32_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
1613 auto* load
= MLoadFixedSlot::New(alloc(), obj
, slotIndex
);
1614 load
->setResultType(MIRTypeFromValueType(JSValueType(type
)));
1621 bool WarpCacheIRTranspiler::emitGuardIsNotUninitializedLexical(
1622 ValOperandId valId
) {
1623 MDefinition
* val
= getOperand(valId
);
1625 auto* lexicalCheck
= MLexicalCheck::New(alloc(), val
);
1628 if (snapshot().bailoutInfo().failedLexicalCheck()) {
1629 lexicalCheck
->setNotMovable();
1632 setOperand(valId
, lexicalCheck
);
1636 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLengthResult(ObjOperandId objId
) {
1637 MDefinition
* obj
= getOperand(objId
);
1639 auto* elements
= MElements::New(alloc(), obj
);
1642 auto* length
= MArrayLength::New(alloc(), elements
);
1649 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLength(ObjOperandId objId
,
1650 Int32OperandId resultId
) {
1651 MDefinition
* obj
= getOperand(objId
);
1653 auto* elements
= MElements::New(alloc(), obj
);
1656 auto* length
= MArrayLength::New(alloc(), elements
);
1659 return defineOperand(resultId
, length
);
1662 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgResult(
1663 ObjOperandId objId
, Int32OperandId indexId
) {
1664 MDefinition
* obj
= getOperand(objId
);
1665 MDefinition
* index
= getOperand(indexId
);
1667 auto* load
= MLoadArgumentsObjectArg::New(alloc(), obj
, index
);
1674 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgHoleResult(
1675 ObjOperandId objId
, Int32OperandId indexId
) {
1676 MDefinition
* obj
= getOperand(objId
);
1677 MDefinition
* index
= getOperand(indexId
);
1679 auto* load
= MLoadArgumentsObjectArgHole::New(alloc(), obj
, index
);
1686 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgExistsResult(
1687 ObjOperandId objId
, Int32OperandId indexId
) {
1688 MDefinition
* obj
= getOperand(objId
);
1689 MDefinition
* index
= getOperand(indexId
);
1691 auto* ins
= MInArgumentsObjectArg::New(alloc(), obj
, index
);
1698 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLengthResult(
1699 ObjOperandId objId
) {
1700 MDefinition
* obj
= getOperand(objId
);
1702 auto* length
= MArgumentsObjectLength::New(alloc(), obj
);
1709 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLength(
1710 ObjOperandId objId
, Int32OperandId resultId
) {
1711 MDefinition
* obj
= getOperand(objId
);
1713 auto* length
= MArgumentsObjectLength::New(alloc(), obj
);
1716 return defineOperand(resultId
, length
);
1719 bool WarpCacheIRTranspiler::emitLoadBoundFunctionNumArgs(
1720 ObjOperandId objId
, Int32OperandId resultId
) {
1721 MDefinition
* obj
= getOperand(objId
);
1723 auto* numArgs
= MBoundFunctionNumArgs::New(alloc(), obj
);
1726 return defineOperand(resultId
, numArgs
);
1729 bool WarpCacheIRTranspiler::emitLoadBoundFunctionTarget(ObjOperandId objId
,
1730 ObjOperandId resultId
) {
1731 MDefinition
* obj
= getOperand(objId
);
1733 auto* target
= MLoadFixedSlotAndUnbox::New(
1734 alloc(), obj
, BoundFunctionObject::targetSlot(), MUnbox::Mode::Infallible
,
1738 return defineOperand(resultId
, target
);
1741 bool WarpCacheIRTranspiler::emitGuardBoundFunctionIsConstructor(
1742 ObjOperandId objId
) {
1743 MDefinition
* obj
= getOperand(objId
);
1745 auto* guard
= MGuardBoundFunctionIsConstructor::New(alloc(), obj
);
1748 setOperand(objId
, guard
);
1752 bool WarpCacheIRTranspiler::emitGuardObjectIdentity(ObjOperandId obj1Id
,
1753 ObjOperandId obj2Id
) {
1754 MDefinition
* obj1
= getOperand(obj1Id
);
1755 MDefinition
* obj2
= getOperand(obj2Id
);
1757 auto* guard
= MGuardObjectIdentity::New(alloc(), obj1
, obj2
,
1758 /* bailOnEquality = */ false);
1763 bool WarpCacheIRTranspiler::emitArrayFromArgumentsObjectResult(
1764 ObjOperandId objId
, uint32_t shapeOffset
) {
1765 MDefinition
* obj
= getOperand(objId
);
1766 Shape
* shape
= shapeStubField(shapeOffset
);
1769 auto* array
= MArrayFromArgumentsObject::New(alloc(), obj
, shape
);
1770 addEffectful(array
);
1773 return resumeAfter(array
);
1776 bool WarpCacheIRTranspiler::emitLoadFunctionLengthResult(ObjOperandId objId
) {
1777 MDefinition
* obj
= getOperand(objId
);
1779 auto* length
= MFunctionLength::New(alloc(), obj
);
1786 bool WarpCacheIRTranspiler::emitLoadFunctionNameResult(ObjOperandId objId
) {
1787 MDefinition
* obj
= getOperand(objId
);
1789 auto* name
= MFunctionName::New(alloc(), obj
);
1796 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthInt32Result(
1797 ObjOperandId objId
) {
1798 MDefinition
* obj
= getOperand(objId
);
1800 auto* length
= MArrayBufferByteLength::New(alloc(), obj
);
1803 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
1806 pushResult(lengthInt32
);
1810 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthDoubleResult(
1811 ObjOperandId objId
) {
1812 MDefinition
* obj
= getOperand(objId
);
1814 auto* length
= MArrayBufferByteLength::New(alloc(), obj
);
1817 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
1820 pushResult(lengthDouble
);
1824 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthInt32Result(
1825 ObjOperandId objId
) {
1826 MDefinition
* obj
= getOperand(objId
);
1828 // Use a separate instruction for converting the length to Int32, so that we
1829 // can fold the MArrayBufferViewLength instruction with length instructions
1830 // added for bounds checks.
1832 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
1835 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
1838 pushResult(lengthInt32
);
1842 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthDoubleResult(
1843 ObjOperandId objId
) {
1844 MDefinition
* obj
= getOperand(objId
);
1846 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
1849 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
1852 pushResult(lengthDouble
);
1856 bool WarpCacheIRTranspiler::emitLoadStringLengthResult(StringOperandId strId
) {
1857 MDefinition
* str
= getOperand(strId
);
1859 auto* length
= MStringLength::New(alloc(), str
);
1866 MInstruction
* WarpCacheIRTranspiler::addBoundsCheck(MDefinition
* index
,
1867 MDefinition
* length
) {
1868 MInstruction
* check
= MBoundsCheck::New(alloc(), index
, length
);
1871 if (snapshot().bailoutInfo().failedBoundsCheck()) {
1872 check
->setNotMovable();
1875 if (JitOptions
.spectreIndexMasking
) {
1876 // Use a separate MIR instruction for the index masking. Doing this as
1877 // part of MBoundsCheck would be unsound because bounds checks can be
1878 // optimized or eliminated completely. Consider this:
1880 // for (var i = 0; i < x; i++)
1883 // If we can prove |x < arr.length|, we are able to eliminate the bounds
1884 // check, but we should not get rid of the index masking because the
1885 // |i < x| branch could still be mispredicted.
1887 // Using a separate instruction lets us eliminate the bounds check
1888 // without affecting the index masking.
1889 check
= MSpectreMaskIndex::New(alloc(), check
, length
);
1896 bool WarpCacheIRTranspiler::emitLoadDenseElementResult(ObjOperandId objId
,
1897 Int32OperandId indexId
) {
1898 MDefinition
* obj
= getOperand(objId
);
1899 MDefinition
* index
= getOperand(indexId
);
1901 auto* elements
= MElements::New(alloc(), obj
);
1904 auto* length
= MInitializedLength::New(alloc(), elements
);
1907 index
= addBoundsCheck(index
, length
);
1909 auto* load
= MLoadElement::New(alloc(), elements
, index
);
1916 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleResult(
1917 ObjOperandId objId
, Int32OperandId indexId
) {
1918 MDefinition
* obj
= getOperand(objId
);
1919 MDefinition
* index
= getOperand(indexId
);
1921 auto* elements
= MElements::New(alloc(), obj
);
1924 auto* length
= MInitializedLength::New(alloc(), elements
);
1927 auto* load
= MLoadElementHole::New(alloc(), elements
, index
, length
);
1934 bool WarpCacheIRTranspiler::emitCallGetSparseElementResult(
1935 ObjOperandId objId
, Int32OperandId indexId
) {
1936 MDefinition
* obj
= getOperand(objId
);
1937 MDefinition
* index
= getOperand(indexId
);
1939 auto* call
= MCallGetSparseElement::New(alloc(), obj
, index
);
1943 return resumeAfter(call
);
1946 bool WarpCacheIRTranspiler::emitCallNativeGetElementResult(
1947 ObjOperandId objId
, Int32OperandId indexId
) {
1948 MDefinition
* obj
= getOperand(objId
);
1949 MDefinition
* index
= getOperand(indexId
);
1951 auto* call
= MCallNativeGetElement::New(alloc(), obj
, index
);
1955 return resumeAfter(call
);
1958 bool WarpCacheIRTranspiler::emitCallNativeGetElementSuperResult(
1959 ObjOperandId objId
, Int32OperandId indexId
, ValOperandId receiverId
) {
1960 MDefinition
* obj
= getOperand(objId
);
1961 MDefinition
* index
= getOperand(indexId
);
1962 MDefinition
* receiver
= getOperand(receiverId
);
1964 auto* call
= MCallNativeGetElementSuper::New(alloc(), obj
, index
, receiver
);
1968 return resumeAfter(call
);
1971 bool WarpCacheIRTranspiler::emitLoadDenseElementExistsResult(
1972 ObjOperandId objId
, Int32OperandId indexId
) {
1973 MDefinition
* obj
= getOperand(objId
);
1974 MDefinition
* index
= getOperand(indexId
);
1976 // Get the elements vector.
1977 auto* elements
= MElements::New(alloc(), obj
);
1980 auto* length
= MInitializedLength::New(alloc(), elements
);
1983 // Check if id < initLength.
1984 index
= addBoundsCheck(index
, length
);
1986 // And check elem[id] is not a hole.
1987 auto* guard
= MGuardElementNotHole::New(alloc(), elements
, index
);
1990 pushResult(constant(BooleanValue(true)));
1994 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleExistsResult(
1995 ObjOperandId objId
, Int32OperandId indexId
) {
1996 MDefinition
* obj
= getOperand(objId
);
1997 MDefinition
* index
= getOperand(indexId
);
1999 // Get the elements vector.
2000 auto* elements
= MElements::New(alloc(), obj
);
2003 auto* length
= MInitializedLength::New(alloc(), elements
);
2006 // Check if id < initLength and elem[id] not a hole.
2007 auto* ins
= MInArray::New(alloc(), elements
, index
, length
, obj
);
2014 bool WarpCacheIRTranspiler::emitCallObjectHasSparseElementResult(
2015 ObjOperandId objId
, Int32OperandId indexId
) {
2016 MDefinition
* obj
= getOperand(objId
);
2017 MDefinition
* index
= getOperand(indexId
);
2019 auto* ins
= MCallObjectHasSparseElement::New(alloc(), obj
, index
);
2026 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementExistsResult(
2027 ObjOperandId objId
, IntPtrOperandId indexId
) {
2028 MDefinition
* obj
= getOperand(objId
);
2029 MDefinition
* index
= getOperand(indexId
);
2031 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
2034 // Unsigned comparison to catch negative indices.
2035 auto* ins
= MCompare::New(alloc(), index
, length
, JSOp::Lt
,
2036 MCompare::Compare_UIntPtr
);
2043 static MIRType
MIRTypeForArrayBufferViewRead(Scalar::Type arrayType
,
2044 bool forceDoubleForUint32
) {
2045 switch (arrayType
) {
2048 case Scalar::Uint8Clamped
:
2050 case Scalar::Uint16
:
2052 return MIRType::Int32
;
2053 case Scalar::Uint32
:
2054 return forceDoubleForUint32
? MIRType::Double
: MIRType::Int32
;
2055 case Scalar::Float32
:
2056 return MIRType::Float32
;
2057 case Scalar::Float64
:
2058 return MIRType::Double
;
2059 case Scalar::BigInt64
:
2060 case Scalar::BigUint64
:
2061 return MIRType::BigInt
;
2065 MOZ_CRASH("Unknown typed array type");
2068 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementResult(
2069 ObjOperandId objId
, IntPtrOperandId indexId
, Scalar::Type elementType
,
2070 bool handleOOB
, bool forceDoubleForUint32
) {
2071 MDefinition
* obj
= getOperand(objId
);
2072 MDefinition
* index
= getOperand(indexId
);
2075 auto* load
= MLoadTypedArrayElementHole::New(
2076 alloc(), obj
, index
, elementType
, forceDoubleForUint32
);
2083 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
2086 index
= addBoundsCheck(index
, length
);
2088 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
2091 auto* load
= MLoadUnboxedScalar::New(alloc(), elements
, index
, elementType
);
2092 load
->setResultType(
2093 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
));
2100 bool WarpCacheIRTranspiler::emitLinearizeForCharAccess(
2101 StringOperandId strId
, Int32OperandId indexId
, StringOperandId resultId
) {
2102 MDefinition
* str
= getOperand(strId
);
2103 MDefinition
* index
= getOperand(indexId
);
2105 auto* ins
= MLinearizeForCharAccess::New(alloc(), str
, index
);
2108 return defineOperand(resultId
, ins
);
2111 bool WarpCacheIRTranspiler::emitLoadStringCharResult(StringOperandId strId
,
2112 Int32OperandId indexId
,
2114 MDefinition
* str
= getOperand(strId
);
2115 MDefinition
* index
= getOperand(indexId
);
2118 auto* ins
= MCharAtMaybeOutOfBounds::New(alloc(), str
, index
);
2125 auto* length
= MStringLength::New(alloc(), str
);
2128 index
= addBoundsCheck(index
, length
);
2130 auto* charCode
= MCharCodeAt::New(alloc(), str
, index
);
2133 auto* fromCharCode
= MFromCharCode::New(alloc(), charCode
);
2136 pushResult(fromCharCode
);
2140 bool WarpCacheIRTranspiler::emitLoadStringCharCodeResult(StringOperandId strId
,
2141 Int32OperandId indexId
,
2143 MDefinition
* str
= getOperand(strId
);
2144 MDefinition
* index
= getOperand(indexId
);
2147 auto* ins
= MCharCodeAtMaybeOutOfBounds::New(alloc(), str
, index
);
2154 auto* length
= MStringLength::New(alloc(), str
);
2157 index
= addBoundsCheck(index
, length
);
2159 auto* charCode
= MCharCodeAt::New(alloc(), str
, index
);
2162 pushResult(charCode
);
2166 bool WarpCacheIRTranspiler::emitNewStringObjectResult(
2167 uint32_t templateObjectOffset
, StringOperandId strId
) {
2168 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
2169 MDefinition
* string
= getOperand(strId
);
2171 auto* obj
= MNewStringObject::New(alloc(), string
, templateObj
);
2175 return resumeAfter(obj
);
2178 bool WarpCacheIRTranspiler::emitStringFromCharCodeResult(
2179 Int32OperandId codeId
) {
2180 MDefinition
* code
= getOperand(codeId
);
2182 auto* fromCharCode
= MFromCharCode::New(alloc(), code
);
2185 pushResult(fromCharCode
);
2189 bool WarpCacheIRTranspiler::emitStringFromCodePointResult(
2190 Int32OperandId codeId
) {
2191 MDefinition
* code
= getOperand(codeId
);
2193 auto* fromCodePoint
= MFromCodePoint::New(alloc(), code
);
2196 pushResult(fromCodePoint
);
2200 bool WarpCacheIRTranspiler::emitStringIndexOfResult(
2201 StringOperandId strId
, StringOperandId searchStrId
) {
2202 MDefinition
* str
= getOperand(strId
);
2203 MDefinition
* searchStr
= getOperand(searchStrId
);
2205 auto* indexOf
= MStringIndexOf::New(alloc(), str
, searchStr
);
2208 pushResult(indexOf
);
2212 bool WarpCacheIRTranspiler::emitStringStartsWithResult(
2213 StringOperandId strId
, StringOperandId searchStrId
) {
2214 MDefinition
* str
= getOperand(strId
);
2215 MDefinition
* searchStr
= getOperand(searchStrId
);
2217 auto* startsWith
= MStringStartsWith::New(alloc(), str
, searchStr
);
2220 pushResult(startsWith
);
2224 bool WarpCacheIRTranspiler::emitStringEndsWithResult(
2225 StringOperandId strId
, StringOperandId searchStrId
) {
2226 MDefinition
* str
= getOperand(strId
);
2227 MDefinition
* searchStr
= getOperand(searchStrId
);
2229 auto* endsWith
= MStringEndsWith::New(alloc(), str
, searchStr
);
2232 pushResult(endsWith
);
2236 bool WarpCacheIRTranspiler::emitStringToLowerCaseResult(StringOperandId strId
) {
2237 MDefinition
* str
= getOperand(strId
);
2240 MStringConvertCase::New(alloc(), str
, MStringConvertCase::LowerCase
);
2243 pushResult(convert
);
2247 bool WarpCacheIRTranspiler::emitStringToUpperCaseResult(StringOperandId strId
) {
2248 MDefinition
* str
= getOperand(strId
);
2251 MStringConvertCase::New(alloc(), str
, MStringConvertCase::UpperCase
);
2254 pushResult(convert
);
2258 bool WarpCacheIRTranspiler::emitStoreDynamicSlot(ObjOperandId objId
,
2259 uint32_t offsetOffset
,
2260 ValOperandId rhsId
) {
2261 int32_t offset
= int32StubField(offsetOffset
);
2263 MDefinition
* obj
= getOperand(objId
);
2264 size_t slotIndex
= NativeObject::getDynamicSlotIndexFromOffset(offset
);
2265 MDefinition
* rhs
= getOperand(rhsId
);
2267 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2270 auto* slots
= MSlots::New(alloc(), obj
);
2273 auto* store
= MStoreDynamicSlot::NewBarriered(alloc(), slots
, slotIndex
, rhs
);
2274 addEffectful(store
);
2275 return resumeAfter(store
);
2278 bool WarpCacheIRTranspiler::emitStoreFixedSlot(ObjOperandId objId
,
2279 uint32_t offsetOffset
,
2280 ValOperandId rhsId
) {
2281 int32_t offset
= int32StubField(offsetOffset
);
2283 MDefinition
* obj
= getOperand(objId
);
2284 size_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
2285 MDefinition
* rhs
= getOperand(rhsId
);
2287 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2290 auto* store
= MStoreFixedSlot::NewBarriered(alloc(), obj
, slotIndex
, rhs
);
2291 addEffectful(store
);
2292 return resumeAfter(store
);
2295 bool WarpCacheIRTranspiler::emitStoreFixedSlotUndefinedResult(
2296 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
) {
2297 int32_t offset
= int32StubField(offsetOffset
);
2299 MDefinition
* obj
= getOperand(objId
);
2300 size_t slotIndex
= NativeObject::getFixedSlotIndexFromOffset(offset
);
2301 MDefinition
* rhs
= getOperand(rhsId
);
2303 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2306 auto* store
= MStoreFixedSlot::NewBarriered(alloc(), obj
, slotIndex
, rhs
);
2307 addEffectful(store
);
2309 auto* undef
= constant(UndefinedValue());
2312 return resumeAfter(store
);
2315 bool WarpCacheIRTranspiler::emitAddAndStoreSlotShared(
2316 MAddAndStoreSlot::Kind kind
, ObjOperandId objId
, uint32_t offsetOffset
,
2317 ValOperandId rhsId
, uint32_t newShapeOffset
) {
2318 int32_t offset
= int32StubField(offsetOffset
);
2319 Shape
* shape
= shapeStubField(newShapeOffset
);
2321 MDefinition
* obj
= getOperand(objId
);
2322 MDefinition
* rhs
= getOperand(rhsId
);
2324 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2328 MAddAndStoreSlot::New(alloc(), obj
, rhs
, kind
, offset
, shape
);
2329 addEffectful(addAndStore
);
2331 return resumeAfter(addAndStore
);
2334 bool WarpCacheIRTranspiler::emitAddAndStoreFixedSlot(ObjOperandId objId
,
2335 uint32_t offsetOffset
,
2337 uint32_t newShapeOffset
) {
2338 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::FixedSlot
, objId
,
2339 offsetOffset
, rhsId
, newShapeOffset
);
2342 bool WarpCacheIRTranspiler::emitAddAndStoreDynamicSlot(
2343 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
,
2344 uint32_t newShapeOffset
) {
2345 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::DynamicSlot
, objId
,
2346 offsetOffset
, rhsId
, newShapeOffset
);
2349 bool WarpCacheIRTranspiler::emitAllocateAndStoreDynamicSlot(
2350 ObjOperandId objId
, uint32_t offsetOffset
, ValOperandId rhsId
,
2351 uint32_t newShapeOffset
, uint32_t numNewSlotsOffset
) {
2352 int32_t offset
= int32StubField(offsetOffset
);
2353 Shape
* shape
= shapeStubField(newShapeOffset
);
2354 uint32_t numNewSlots
= uint32StubField(numNewSlotsOffset
);
2356 MDefinition
* obj
= getOperand(objId
);
2357 MDefinition
* rhs
= getOperand(rhsId
);
2359 auto* barrier
= MPostWriteBarrier::New(alloc(), obj
, rhs
);
2362 auto* allocateAndStore
=
2363 MAllocateAndStoreSlot::New(alloc(), obj
, rhs
, offset
, shape
, numNewSlots
);
2364 addEffectful(allocateAndStore
);
2366 return resumeAfter(allocateAndStore
);
2369 bool WarpCacheIRTranspiler::emitAddSlotAndCallAddPropHook(
2370 ObjOperandId objId
, ValOperandId rhsId
, uint32_t newShapeOffset
) {
2371 Shape
* shape
= shapeStubField(newShapeOffset
);
2372 MDefinition
* obj
= getOperand(objId
);
2373 MDefinition
* rhs
= getOperand(rhsId
);
2375 auto* addProp
= MAddSlotAndCallAddPropHook::New(alloc(), obj
, rhs
, shape
);
2376 addEffectful(addProp
);
2378 return resumeAfter(addProp
);
2381 bool WarpCacheIRTranspiler::emitStoreDenseElement(ObjOperandId objId
,
2382 Int32OperandId indexId
,
2383 ValOperandId rhsId
) {
2384 MDefinition
* obj
= getOperand(objId
);
2385 MDefinition
* index
= getOperand(indexId
);
2386 MDefinition
* rhs
= getOperand(rhsId
);
2388 auto* elements
= MElements::New(alloc(), obj
);
2391 auto* length
= MInitializedLength::New(alloc(), elements
);
2394 index
= addBoundsCheck(index
, length
);
2396 auto* barrier
= MPostWriteElementBarrier::New(alloc(), obj
, rhs
, index
);
2399 bool needsHoleCheck
= true;
2400 auto* store
= MStoreElement::NewBarriered(alloc(), elements
, index
, rhs
,
2402 addEffectful(store
);
2403 return resumeAfter(store
);
2406 bool WarpCacheIRTranspiler::emitStoreDenseElementHole(ObjOperandId objId
,
2407 Int32OperandId indexId
,
2410 MDefinition
* obj
= getOperand(objId
);
2411 MDefinition
* index
= getOperand(indexId
);
2412 MDefinition
* rhs
= getOperand(rhsId
);
2414 auto* elements
= MElements::New(alloc(), obj
);
2417 auto* barrier
= MPostWriteElementBarrier::New(alloc(), obj
, rhs
, index
);
2420 MInstruction
* store
;
2422 // TODO(post-Warp): Consider changing MStoreElementHole to match IC code.
2423 store
= MStoreElementHole::New(alloc(), obj
, elements
, index
, rhs
);
2425 auto* length
= MInitializedLength::New(alloc(), elements
);
2428 index
= addBoundsCheck(index
, length
);
2430 bool needsHoleCheck
= false;
2431 store
= MStoreElement::NewBarriered(alloc(), elements
, index
, rhs
,
2434 addEffectful(store
);
2436 return resumeAfter(store
);
2439 bool WarpCacheIRTranspiler::emitStoreTypedArrayElement(ObjOperandId objId
,
2440 Scalar::Type elementType
,
2441 IntPtrOperandId indexId
,
2444 MDefinition
* obj
= getOperand(objId
);
2445 MDefinition
* index
= getOperand(indexId
);
2446 MDefinition
* rhs
= getOperand(ValOperandId(rhsId
));
2448 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
2452 // MStoreTypedArrayElementHole does the bounds checking.
2453 index
= addBoundsCheck(index
, length
);
2456 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
2459 MInstruction
* store
;
2461 store
= MStoreTypedArrayElementHole::New(alloc(), elements
, length
, index
,
2465 MStoreUnboxedScalar::New(alloc(), elements
, index
, rhs
, elementType
);
2467 addEffectful(store
);
2468 return resumeAfter(store
);
2471 void WarpCacheIRTranspiler::addDataViewData(MDefinition
* obj
, Scalar::Type type
,
2472 MDefinition
** offset
,
2473 MInstruction
** elements
) {
2474 MInstruction
* length
= MArrayBufferViewLength::New(alloc(), obj
);
2477 // Adjust the length to account for accesses near the end of the dataview.
2478 if (size_t byteSize
= Scalar::byteSize(type
); byteSize
> 1) {
2479 // To ensure |0 <= offset && offset + byteSize <= length|, first adjust the
2480 // length by subtracting |byteSize - 1| (bailing out if that becomes
2482 length
= MAdjustDataViewLength::New(alloc(), length
, byteSize
);
2486 *offset
= addBoundsCheck(*offset
, length
);
2488 *elements
= MArrayBufferViewElements::New(alloc(), obj
);
2492 bool WarpCacheIRTranspiler::emitLoadDataViewValueResult(
2493 ObjOperandId objId
, IntPtrOperandId offsetId
,
2494 BooleanOperandId littleEndianId
, Scalar::Type elementType
,
2495 bool forceDoubleForUint32
) {
2496 MDefinition
* obj
= getOperand(objId
);
2497 MDefinition
* offset
= getOperand(offsetId
);
2498 MDefinition
* littleEndian
= getOperand(littleEndianId
);
2500 // Add bounds check and get the DataViewObject's elements.
2501 MInstruction
* elements
;
2502 addDataViewData(obj
, elementType
, &offset
, &elements
);
2504 // Load the element.
2506 if (Scalar::byteSize(elementType
) == 1) {
2507 load
= MLoadUnboxedScalar::New(alloc(), elements
, offset
, elementType
);
2509 load
= MLoadDataViewElement::New(alloc(), elements
, offset
, littleEndian
,
2515 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
2516 load
->setResultType(knownType
);
2522 bool WarpCacheIRTranspiler::emitStoreDataViewValueResult(
2523 ObjOperandId objId
, IntPtrOperandId offsetId
, uint32_t valueId
,
2524 BooleanOperandId littleEndianId
, Scalar::Type elementType
) {
2525 MDefinition
* obj
= getOperand(objId
);
2526 MDefinition
* offset
= getOperand(offsetId
);
2527 MDefinition
* value
= getOperand(ValOperandId(valueId
));
2528 MDefinition
* littleEndian
= getOperand(littleEndianId
);
2530 // Add bounds check and get the DataViewObject's elements.
2531 MInstruction
* elements
;
2532 addDataViewData(obj
, elementType
, &offset
, &elements
);
2534 // Store the element.
2535 MInstruction
* store
;
2536 if (Scalar::byteSize(elementType
) == 1) {
2538 MStoreUnboxedScalar::New(alloc(), elements
, offset
, value
, elementType
);
2540 store
= MStoreDataViewElement::New(alloc(), elements
, offset
, value
,
2541 littleEndian
, elementType
);
2543 addEffectful(store
);
2545 pushResult(constant(UndefinedValue()));
2547 return resumeAfter(store
);
2550 bool WarpCacheIRTranspiler::emitInt32IncResult(Int32OperandId inputId
) {
2551 MDefinition
* input
= getOperand(inputId
);
2553 auto* constOne
= MConstant::New(alloc(), Int32Value(1));
2556 auto* ins
= MAdd::New(alloc(), input
, constOne
, MIRType::Int32
);
2563 bool WarpCacheIRTranspiler::emitDoubleIncResult(NumberOperandId inputId
) {
2564 MDefinition
* input
= getOperand(inputId
);
2566 auto* constOne
= MConstant::New(alloc(), DoubleValue(1.0));
2569 auto* ins
= MAdd::New(alloc(), input
, constOne
, MIRType::Double
);
2576 bool WarpCacheIRTranspiler::emitInt32DecResult(Int32OperandId inputId
) {
2577 MDefinition
* input
= getOperand(inputId
);
2579 auto* constOne
= MConstant::New(alloc(), Int32Value(1));
2582 auto* ins
= MSub::New(alloc(), input
, constOne
, MIRType::Int32
);
2589 bool WarpCacheIRTranspiler::emitDoubleDecResult(NumberOperandId inputId
) {
2590 MDefinition
* input
= getOperand(inputId
);
2592 auto* constOne
= MConstant::New(alloc(), DoubleValue(1.0));
2595 auto* ins
= MSub::New(alloc(), input
, constOne
, MIRType::Double
);
2602 bool WarpCacheIRTranspiler::emitInt32NegationResult(Int32OperandId inputId
) {
2603 MDefinition
* input
= getOperand(inputId
);
2605 auto* constNegOne
= MConstant::New(alloc(), Int32Value(-1));
2608 auto* ins
= MMul::New(alloc(), input
, constNegOne
, MIRType::Int32
);
2615 bool WarpCacheIRTranspiler::emitDoubleNegationResult(NumberOperandId inputId
) {
2616 MDefinition
* input
= getOperand(inputId
);
2618 auto* constNegOne
= MConstant::New(alloc(), DoubleValue(-1.0));
2621 auto* ins
= MMul::New(alloc(), input
, constNegOne
, MIRType::Double
);
2628 bool WarpCacheIRTranspiler::emitInt32NotResult(Int32OperandId inputId
) {
2629 MDefinition
* input
= getOperand(inputId
);
2631 auto* ins
= MBitNot::New(alloc(), input
);
2638 template <typename T
>
2639 bool WarpCacheIRTranspiler::emitDoubleBinaryArithResult(NumberOperandId lhsId
,
2640 NumberOperandId rhsId
) {
2641 MDefinition
* lhs
= getOperand(lhsId
);
2642 MDefinition
* rhs
= getOperand(rhsId
);
2644 auto* ins
= T::New(alloc(), lhs
, rhs
, MIRType::Double
);
2651 bool WarpCacheIRTranspiler::emitDoubleAddResult(NumberOperandId lhsId
,
2652 NumberOperandId rhsId
) {
2653 return emitDoubleBinaryArithResult
<MAdd
>(lhsId
, rhsId
);
2656 bool WarpCacheIRTranspiler::emitDoubleSubResult(NumberOperandId lhsId
,
2657 NumberOperandId rhsId
) {
2658 return emitDoubleBinaryArithResult
<MSub
>(lhsId
, rhsId
);
2661 bool WarpCacheIRTranspiler::emitDoubleMulResult(NumberOperandId lhsId
,
2662 NumberOperandId rhsId
) {
2663 return emitDoubleBinaryArithResult
<MMul
>(lhsId
, rhsId
);
2666 bool WarpCacheIRTranspiler::emitDoubleDivResult(NumberOperandId lhsId
,
2667 NumberOperandId rhsId
) {
2668 return emitDoubleBinaryArithResult
<MDiv
>(lhsId
, rhsId
);
2671 bool WarpCacheIRTranspiler::emitDoubleModResult(NumberOperandId lhsId
,
2672 NumberOperandId rhsId
) {
2673 return emitDoubleBinaryArithResult
<MMod
>(lhsId
, rhsId
);
2676 bool WarpCacheIRTranspiler::emitDoublePowResult(NumberOperandId lhsId
,
2677 NumberOperandId rhsId
) {
2678 return emitDoubleBinaryArithResult
<MPow
>(lhsId
, rhsId
);
2681 template <typename T
>
2682 bool WarpCacheIRTranspiler::emitInt32BinaryArithResult(Int32OperandId lhsId
,
2683 Int32OperandId rhsId
) {
2684 MDefinition
* lhs
= getOperand(lhsId
);
2685 MDefinition
* rhs
= getOperand(rhsId
);
2687 auto* ins
= T::New(alloc(), lhs
, rhs
, MIRType::Int32
);
2694 bool WarpCacheIRTranspiler::emitInt32AddResult(Int32OperandId lhsId
,
2695 Int32OperandId rhsId
) {
2696 return emitInt32BinaryArithResult
<MAdd
>(lhsId
, rhsId
);
2699 bool WarpCacheIRTranspiler::emitInt32SubResult(Int32OperandId lhsId
,
2700 Int32OperandId rhsId
) {
2701 return emitInt32BinaryArithResult
<MSub
>(lhsId
, rhsId
);
2704 bool WarpCacheIRTranspiler::emitInt32MulResult(Int32OperandId lhsId
,
2705 Int32OperandId rhsId
) {
2706 return emitInt32BinaryArithResult
<MMul
>(lhsId
, rhsId
);
2709 bool WarpCacheIRTranspiler::emitInt32DivResult(Int32OperandId lhsId
,
2710 Int32OperandId rhsId
) {
2711 return emitInt32BinaryArithResult
<MDiv
>(lhsId
, rhsId
);
2714 bool WarpCacheIRTranspiler::emitInt32ModResult(Int32OperandId lhsId
,
2715 Int32OperandId rhsId
) {
2716 return emitInt32BinaryArithResult
<MMod
>(lhsId
, rhsId
);
2719 bool WarpCacheIRTranspiler::emitInt32PowResult(Int32OperandId lhsId
,
2720 Int32OperandId rhsId
) {
2721 return emitInt32BinaryArithResult
<MPow
>(lhsId
, rhsId
);
2724 bool WarpCacheIRTranspiler::emitInt32BitOrResult(Int32OperandId lhsId
,
2725 Int32OperandId rhsId
) {
2726 return emitInt32BinaryArithResult
<MBitOr
>(lhsId
, rhsId
);
2729 bool WarpCacheIRTranspiler::emitInt32BitXorResult(Int32OperandId lhsId
,
2730 Int32OperandId rhsId
) {
2731 return emitInt32BinaryArithResult
<MBitXor
>(lhsId
, rhsId
);
2734 bool WarpCacheIRTranspiler::emitInt32BitAndResult(Int32OperandId lhsId
,
2735 Int32OperandId rhsId
) {
2736 return emitInt32BinaryArithResult
<MBitAnd
>(lhsId
, rhsId
);
2739 bool WarpCacheIRTranspiler::emitInt32LeftShiftResult(Int32OperandId lhsId
,
2740 Int32OperandId rhsId
) {
2741 return emitInt32BinaryArithResult
<MLsh
>(lhsId
, rhsId
);
2744 bool WarpCacheIRTranspiler::emitInt32RightShiftResult(Int32OperandId lhsId
,
2745 Int32OperandId rhsId
) {
2746 return emitInt32BinaryArithResult
<MRsh
>(lhsId
, rhsId
);
2749 bool WarpCacheIRTranspiler::emitInt32URightShiftResult(Int32OperandId lhsId
,
2750 Int32OperandId rhsId
,
2752 MDefinition
* lhs
= getOperand(lhsId
);
2753 MDefinition
* rhs
= getOperand(rhsId
);
2755 MIRType specialization
= forceDouble
? MIRType::Double
: MIRType::Int32
;
2756 auto* ins
= MUrsh::New(alloc(), lhs
, rhs
, specialization
);
2763 template <typename T
>
2764 bool WarpCacheIRTranspiler::emitBigIntBinaryArithResult(BigIntOperandId lhsId
,
2765 BigIntOperandId rhsId
) {
2766 MDefinition
* lhs
= getOperand(lhsId
);
2767 MDefinition
* rhs
= getOperand(rhsId
);
2769 auto* ins
= T::New(alloc(), lhs
, rhs
);
2776 bool WarpCacheIRTranspiler::emitBigIntAddResult(BigIntOperandId lhsId
,
2777 BigIntOperandId rhsId
) {
2778 return emitBigIntBinaryArithResult
<MBigIntAdd
>(lhsId
, rhsId
);
2781 bool WarpCacheIRTranspiler::emitBigIntSubResult(BigIntOperandId lhsId
,
2782 BigIntOperandId rhsId
) {
2783 return emitBigIntBinaryArithResult
<MBigIntSub
>(lhsId
, rhsId
);
2786 bool WarpCacheIRTranspiler::emitBigIntMulResult(BigIntOperandId lhsId
,
2787 BigIntOperandId rhsId
) {
2788 return emitBigIntBinaryArithResult
<MBigIntMul
>(lhsId
, rhsId
);
2791 template <typename T
>
2792 bool WarpCacheIRTranspiler::emitBigIntBinaryArithEffectfulResult(
2793 BigIntOperandId lhsId
, BigIntOperandId rhsId
) {
2794 MDefinition
* lhs
= getOperand(lhsId
);
2795 MDefinition
* rhs
= getOperand(rhsId
);
2797 auto* ins
= T::New(alloc(), lhs
, rhs
);
2799 if (ins
->isEffectful()) {
2803 return resumeAfter(ins
);
2812 bool WarpCacheIRTranspiler::emitBigIntDivResult(BigIntOperandId lhsId
,
2813 BigIntOperandId rhsId
) {
2814 return emitBigIntBinaryArithEffectfulResult
<MBigIntDiv
>(lhsId
, rhsId
);
2817 bool WarpCacheIRTranspiler::emitBigIntModResult(BigIntOperandId lhsId
,
2818 BigIntOperandId rhsId
) {
2819 return emitBigIntBinaryArithEffectfulResult
<MBigIntMod
>(lhsId
, rhsId
);
2822 bool WarpCacheIRTranspiler::emitBigIntPowResult(BigIntOperandId lhsId
,
2823 BigIntOperandId rhsId
) {
2824 return emitBigIntBinaryArithEffectfulResult
<MBigIntPow
>(lhsId
, rhsId
);
2827 bool WarpCacheIRTranspiler::emitBigIntBitAndResult(BigIntOperandId lhsId
,
2828 BigIntOperandId rhsId
) {
2829 return emitBigIntBinaryArithResult
<MBigIntBitAnd
>(lhsId
, rhsId
);
2832 bool WarpCacheIRTranspiler::emitBigIntBitOrResult(BigIntOperandId lhsId
,
2833 BigIntOperandId rhsId
) {
2834 return emitBigIntBinaryArithResult
<MBigIntBitOr
>(lhsId
, rhsId
);
2837 bool WarpCacheIRTranspiler::emitBigIntBitXorResult(BigIntOperandId lhsId
,
2838 BigIntOperandId rhsId
) {
2839 return emitBigIntBinaryArithResult
<MBigIntBitXor
>(lhsId
, rhsId
);
2842 bool WarpCacheIRTranspiler::emitBigIntLeftShiftResult(BigIntOperandId lhsId
,
2843 BigIntOperandId rhsId
) {
2844 return emitBigIntBinaryArithResult
<MBigIntLsh
>(lhsId
, rhsId
);
2847 bool WarpCacheIRTranspiler::emitBigIntRightShiftResult(BigIntOperandId lhsId
,
2848 BigIntOperandId rhsId
) {
2849 return emitBigIntBinaryArithResult
<MBigIntRsh
>(lhsId
, rhsId
);
2852 template <typename T
>
2853 bool WarpCacheIRTranspiler::emitBigIntUnaryArithResult(
2854 BigIntOperandId inputId
) {
2855 MDefinition
* input
= getOperand(inputId
);
2857 auto* ins
= T::New(alloc(), input
);
2864 bool WarpCacheIRTranspiler::emitBigIntIncResult(BigIntOperandId inputId
) {
2865 return emitBigIntUnaryArithResult
<MBigIntIncrement
>(inputId
);
2868 bool WarpCacheIRTranspiler::emitBigIntDecResult(BigIntOperandId inputId
) {
2869 return emitBigIntUnaryArithResult
<MBigIntDecrement
>(inputId
);
2872 bool WarpCacheIRTranspiler::emitBigIntNegationResult(BigIntOperandId inputId
) {
2873 return emitBigIntUnaryArithResult
<MBigIntNegate
>(inputId
);
2876 bool WarpCacheIRTranspiler::emitBigIntNotResult(BigIntOperandId inputId
) {
2877 return emitBigIntUnaryArithResult
<MBigIntBitNot
>(inputId
);
2880 bool WarpCacheIRTranspiler::emitCallStringConcatResult(StringOperandId lhsId
,
2881 StringOperandId rhsId
) {
2882 MDefinition
* lhs
= getOperand(lhsId
);
2883 MDefinition
* rhs
= getOperand(rhsId
);
2885 auto* ins
= MConcat::New(alloc(), lhs
, rhs
);
2892 bool WarpCacheIRTranspiler::emitCompareResult(
2893 JSOp op
, OperandId lhsId
, OperandId rhsId
,
2894 MCompare::CompareType compareType
) {
2895 MDefinition
* lhs
= getOperand(lhsId
);
2896 MDefinition
* rhs
= getOperand(rhsId
);
2898 auto* ins
= MCompare::New(alloc(), lhs
, rhs
, op
, compareType
);
2905 bool WarpCacheIRTranspiler::emitCompareInt32Result(JSOp op
,
2906 Int32OperandId lhsId
,
2907 Int32OperandId rhsId
) {
2908 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Int32
);
2911 bool WarpCacheIRTranspiler::emitCompareDoubleResult(JSOp op
,
2912 NumberOperandId lhsId
,
2913 NumberOperandId rhsId
) {
2914 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Double
);
2917 bool WarpCacheIRTranspiler::emitCompareObjectResult(JSOp op
, ObjOperandId lhsId
,
2918 ObjOperandId rhsId
) {
2919 MOZ_ASSERT(IsEqualityOp(op
));
2920 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Object
);
2923 bool WarpCacheIRTranspiler::emitCompareStringResult(JSOp op
,
2924 StringOperandId lhsId
,
2925 StringOperandId rhsId
) {
2926 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_String
);
2929 bool WarpCacheIRTranspiler::emitCompareSymbolResult(JSOp op
,
2930 SymbolOperandId lhsId
,
2931 SymbolOperandId rhsId
) {
2932 MOZ_ASSERT(IsEqualityOp(op
));
2933 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_Symbol
);
2936 bool WarpCacheIRTranspiler::emitCompareBigIntResult(JSOp op
,
2937 BigIntOperandId lhsId
,
2938 BigIntOperandId rhsId
) {
2939 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt
);
2942 bool WarpCacheIRTranspiler::emitCompareBigIntInt32Result(JSOp op
,
2943 BigIntOperandId lhsId
,
2944 Int32OperandId rhsId
) {
2945 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_Int32
);
2948 bool WarpCacheIRTranspiler::emitCompareBigIntNumberResult(
2949 JSOp op
, BigIntOperandId lhsId
, NumberOperandId rhsId
) {
2950 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_Double
);
2953 bool WarpCacheIRTranspiler::emitCompareBigIntStringResult(
2954 JSOp op
, BigIntOperandId lhsId
, StringOperandId rhsId
) {
2955 return emitCompareResult(op
, lhsId
, rhsId
, MCompare::Compare_BigInt_String
);
2958 bool WarpCacheIRTranspiler::emitCompareNullUndefinedResult(
2959 JSOp op
, bool isUndefined
, ValOperandId inputId
) {
2960 MDefinition
* input
= getOperand(inputId
);
2962 MOZ_ASSERT(IsEqualityOp(op
));
2964 // A previously emitted guard ensures that one side of the comparison
2965 // is null or undefined.
2967 isUndefined
? constant(UndefinedValue()) : constant(NullValue());
2969 isUndefined
? MCompare::Compare_Undefined
: MCompare::Compare_Null
;
2970 auto* ins
= MCompare::New(alloc(), input
, cst
, op
, compareType
);
2977 bool WarpCacheIRTranspiler::emitCompareDoubleSameValueResult(
2978 NumberOperandId lhsId
, NumberOperandId rhsId
) {
2979 MDefinition
* lhs
= getOperand(lhsId
);
2980 MDefinition
* rhs
= getOperand(rhsId
);
2982 auto* sameValue
= MSameValueDouble::New(alloc(), lhs
, rhs
);
2985 pushResult(sameValue
);
2989 bool WarpCacheIRTranspiler::emitSameValueResult(ValOperandId lhsId
,
2990 ValOperandId rhsId
) {
2991 MDefinition
* lhs
= getOperand(lhsId
);
2992 MDefinition
* rhs
= getOperand(rhsId
);
2994 auto* sameValue
= MSameValue::New(alloc(), lhs
, rhs
);
2997 pushResult(sameValue
);
3001 bool WarpCacheIRTranspiler::emitIndirectTruncateInt32Result(
3002 Int32OperandId valId
) {
3003 MDefinition
* val
= getOperand(valId
);
3004 MOZ_ASSERT(val
->type() == MIRType::Int32
);
3007 MLimitedTruncate::New(alloc(), val
, TruncateKind::IndirectTruncate
);
3010 pushResult(truncate
);
3014 bool WarpCacheIRTranspiler::emitMathHypot2NumberResult(
3015 NumberOperandId firstId
, NumberOperandId secondId
) {
3016 MDefinitionVector
vector(alloc());
3017 if (!vector
.reserve(2)) {
3021 vector
.infallibleAppend(getOperand(firstId
));
3022 vector
.infallibleAppend(getOperand(secondId
));
3024 auto* ins
= MHypot::New(alloc(), vector
);
3034 bool WarpCacheIRTranspiler::emitMathHypot3NumberResult(
3035 NumberOperandId firstId
, NumberOperandId secondId
,
3036 NumberOperandId thirdId
) {
3037 MDefinitionVector
vector(alloc());
3038 if (!vector
.reserve(3)) {
3042 vector
.infallibleAppend(getOperand(firstId
));
3043 vector
.infallibleAppend(getOperand(secondId
));
3044 vector
.infallibleAppend(getOperand(thirdId
));
3046 auto* ins
= MHypot::New(alloc(), vector
);
3056 bool WarpCacheIRTranspiler::emitMathHypot4NumberResult(
3057 NumberOperandId firstId
, NumberOperandId secondId
, NumberOperandId thirdId
,
3058 NumberOperandId fourthId
) {
3059 MDefinitionVector
vector(alloc());
3060 if (!vector
.reserve(4)) {
3064 vector
.infallibleAppend(getOperand(firstId
));
3065 vector
.infallibleAppend(getOperand(secondId
));
3066 vector
.infallibleAppend(getOperand(thirdId
));
3067 vector
.infallibleAppend(getOperand(fourthId
));
3069 auto* ins
= MHypot::New(alloc(), vector
);
3079 bool WarpCacheIRTranspiler::emitMathRandomResult(uint32_t rngOffset
) {
3081 // CodeGenerator uses CompileRealm::addressOfRandomNumberGenerator. Assert it
3082 // matches the RNG pointer stored in the stub field.
3083 const void* rng
= rawPointerField(rngOffset
);
3084 MOZ_ASSERT(rng
== mirGen().realm
->addressOfRandomNumberGenerator());
3087 auto* ins
= MRandom::New(alloc());
3091 return resumeAfter(ins
);
3094 bool WarpCacheIRTranspiler::emitInt32MinMax(bool isMax
, Int32OperandId firstId
,
3095 Int32OperandId secondId
,
3096 Int32OperandId resultId
) {
3097 MDefinition
* first
= getOperand(firstId
);
3098 MDefinition
* second
= getOperand(secondId
);
3100 auto* ins
= MMinMax::New(alloc(), first
, second
, MIRType::Int32
, isMax
);
3103 return defineOperand(resultId
, ins
);
3106 bool WarpCacheIRTranspiler::emitNumberMinMax(bool isMax
,
3107 NumberOperandId firstId
,
3108 NumberOperandId secondId
,
3109 NumberOperandId resultId
) {
3110 MDefinition
* first
= getOperand(firstId
);
3111 MDefinition
* second
= getOperand(secondId
);
3113 auto* ins
= MMinMax::New(alloc(), first
, second
, MIRType::Double
, isMax
);
3116 return defineOperand(resultId
, ins
);
3119 bool WarpCacheIRTranspiler::emitInt32MinMaxArrayResult(ObjOperandId arrayId
,
3121 MDefinition
* array
= getOperand(arrayId
);
3123 auto* ins
= MMinMaxArray::New(alloc(), array
, MIRType::Int32
, isMax
);
3130 bool WarpCacheIRTranspiler::emitNumberMinMaxArrayResult(ObjOperandId arrayId
,
3132 MDefinition
* array
= getOperand(arrayId
);
3134 auto* ins
= MMinMaxArray::New(alloc(), array
, MIRType::Double
, isMax
);
3141 bool WarpCacheIRTranspiler::emitMathAbsInt32Result(Int32OperandId inputId
) {
3142 MDefinition
* input
= getOperand(inputId
);
3144 auto* ins
= MAbs::New(alloc(), input
, MIRType::Int32
);
3151 bool WarpCacheIRTranspiler::emitMathAbsNumberResult(NumberOperandId inputId
) {
3152 MDefinition
* input
= getOperand(inputId
);
3154 auto* ins
= MAbs::New(alloc(), input
, MIRType::Double
);
3161 bool WarpCacheIRTranspiler::emitMathClz32Result(Int32OperandId inputId
) {
3162 MDefinition
* input
= getOperand(inputId
);
3164 auto* ins
= MClz::New(alloc(), input
, MIRType::Int32
);
3171 bool WarpCacheIRTranspiler::emitMathSignInt32Result(Int32OperandId inputId
) {
3172 MDefinition
* input
= getOperand(inputId
);
3174 auto* ins
= MSign::New(alloc(), input
, MIRType::Int32
);
3181 bool WarpCacheIRTranspiler::emitMathSignNumberResult(NumberOperandId inputId
) {
3182 MDefinition
* input
= getOperand(inputId
);
3184 auto* ins
= MSign::New(alloc(), input
, MIRType::Double
);
3191 bool WarpCacheIRTranspiler::emitMathSignNumberToInt32Result(
3192 NumberOperandId inputId
) {
3193 MDefinition
* input
= getOperand(inputId
);
3195 auto* ins
= MSign::New(alloc(), input
, MIRType::Int32
);
3202 bool WarpCacheIRTranspiler::emitMathImulResult(Int32OperandId lhsId
,
3203 Int32OperandId rhsId
) {
3204 MDefinition
* lhs
= getOperand(lhsId
);
3205 MDefinition
* rhs
= getOperand(rhsId
);
3207 auto* ins
= MMul::New(alloc(), lhs
, rhs
, MIRType::Int32
, MMul::Integer
);
3214 bool WarpCacheIRTranspiler::emitMathFloorToInt32Result(
3215 NumberOperandId inputId
) {
3216 MDefinition
* input
= getOperand(inputId
);
3218 auto* ins
= MFloor::New(alloc(), input
);
3225 bool WarpCacheIRTranspiler::emitMathCeilToInt32Result(NumberOperandId inputId
) {
3226 MDefinition
* input
= getOperand(inputId
);
3228 auto* ins
= MCeil::New(alloc(), input
);
3235 bool WarpCacheIRTranspiler::emitMathTruncToInt32Result(
3236 NumberOperandId inputId
) {
3237 MDefinition
* input
= getOperand(inputId
);
3239 auto* ins
= MTrunc::New(alloc(), input
);
3246 bool WarpCacheIRTranspiler::emitMathRoundToInt32Result(
3247 NumberOperandId inputId
) {
3248 MDefinition
* input
= getOperand(inputId
);
3250 auto* ins
= MRound::New(alloc(), input
);
3257 bool WarpCacheIRTranspiler::emitMathSqrtNumberResult(NumberOperandId inputId
) {
3258 MDefinition
* input
= getOperand(inputId
);
3260 auto* ins
= MSqrt::New(alloc(), input
, MIRType::Double
);
3267 bool WarpCacheIRTranspiler::emitMathFRoundNumberResult(
3268 NumberOperandId inputId
) {
3269 MDefinition
* input
= getOperand(inputId
);
3271 auto* ins
= MToFloat32::New(alloc(), input
);
3278 bool WarpCacheIRTranspiler::emitMathAtan2NumberResult(NumberOperandId yId
,
3279 NumberOperandId xId
) {
3280 MDefinition
* y
= getOperand(yId
);
3281 MDefinition
* x
= getOperand(xId
);
3283 auto* ins
= MAtan2::New(alloc(), y
, x
);
3290 bool WarpCacheIRTranspiler::emitMathFunctionNumberResult(
3291 NumberOperandId inputId
, UnaryMathFunction fun
) {
3292 MDefinition
* input
= getOperand(inputId
);
3294 auto* ins
= MMathFunction::New(alloc(), input
, fun
);
3301 bool WarpCacheIRTranspiler::emitMathFloorNumberResult(NumberOperandId inputId
) {
3302 MDefinition
* input
= getOperand(inputId
);
3305 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down
)) {
3306 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
, RoundingMode::Down
);
3308 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Floor
);
3316 bool WarpCacheIRTranspiler::emitMathCeilNumberResult(NumberOperandId inputId
) {
3317 MDefinition
* input
= getOperand(inputId
);
3320 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up
)) {
3321 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
, RoundingMode::Up
);
3323 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Ceil
);
3331 bool WarpCacheIRTranspiler::emitMathTruncNumberResult(NumberOperandId inputId
) {
3332 MDefinition
* input
= getOperand(inputId
);
3335 if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero
)) {
3336 ins
= MNearbyInt::New(alloc(), input
, MIRType::Double
,
3337 RoundingMode::TowardsZero
);
3339 ins
= MMathFunction::New(alloc(), input
, UnaryMathFunction::Trunc
);
3347 bool WarpCacheIRTranspiler::emitNumberParseIntResult(StringOperandId strId
,
3348 Int32OperandId radixId
) {
3349 MDefinition
* str
= getOperand(strId
);
3350 MDefinition
* radix
= getOperand(radixId
);
3352 auto* ins
= MNumberParseInt::New(alloc(), str
, radix
);
3359 bool WarpCacheIRTranspiler::emitDoubleParseIntResult(NumberOperandId numId
) {
3360 MDefinition
* num
= getOperand(numId
);
3362 auto* ins
= MDoubleParseInt::New(alloc(), num
);
3369 bool WarpCacheIRTranspiler::emitObjectToStringResult(ObjOperandId objId
) {
3370 MDefinition
* obj
= getOperand(objId
);
3372 auto* ins
= MObjectClassToString::New(alloc(), obj
);
3379 bool WarpCacheIRTranspiler::emitReflectGetPrototypeOfResult(
3380 ObjOperandId objId
) {
3381 MDefinition
* obj
= getOperand(objId
);
3383 auto* ins
= MGetPrototypeOf::New(alloc(), obj
);
3387 return resumeAfter(ins
);
3390 bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId
,
3391 ValOperandId rhsId
) {
3392 MDefinition
* obj
= getOperand(objId
);
3393 MDefinition
* value
= getOperand(rhsId
);
3395 auto* elements
= MElements::New(alloc(), obj
);
3398 auto* initLength
= MInitializedLength::New(alloc(), elements
);
3402 MPostWriteElementBarrier::New(alloc(), obj
, value
, initLength
);
3405 auto* ins
= MArrayPush::New(alloc(), obj
, value
);
3409 return resumeAfter(ins
);
3412 bool WarpCacheIRTranspiler::emitArrayJoinResult(ObjOperandId objId
,
3413 StringOperandId sepId
) {
3414 MDefinition
* obj
= getOperand(objId
);
3415 MDefinition
* sep
= getOperand(sepId
);
3417 auto* join
= MArrayJoin::New(alloc(), obj
, sep
);
3421 return resumeAfter(join
);
3424 bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId
) {
3425 MDefinition
* array
= getOperand(arrayId
);
3427 auto* ins
= MArrayPopShift::New(alloc(), array
, MArrayPopShift::Pop
);
3431 return resumeAfter(ins
);
3434 bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId
) {
3435 MDefinition
* array
= getOperand(arrayId
);
3437 auto* ins
= MArrayPopShift::New(alloc(), array
, MArrayPopShift::Shift
);
3441 return resumeAfter(ins
);
3444 bool WarpCacheIRTranspiler::emitPackedArraySliceResult(
3445 uint32_t templateObjectOffset
, ObjOperandId arrayId
, Int32OperandId beginId
,
3446 Int32OperandId endId
) {
3447 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3449 MDefinition
* array
= getOperand(arrayId
);
3450 MDefinition
* begin
= getOperand(beginId
);
3451 MDefinition
* end
= getOperand(endId
);
3453 // TODO: support pre-tenuring.
3454 gc::Heap heap
= gc::Heap::Default
;
3456 auto* ins
= MArraySlice::New(alloc(), array
, begin
, end
, templateObj
, heap
);
3460 return resumeAfter(ins
);
3463 bool WarpCacheIRTranspiler::emitArgumentsSliceResult(
3464 uint32_t templateObjectOffset
, ObjOperandId argsId
, Int32OperandId beginId
,
3465 Int32OperandId endId
) {
3466 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3468 MDefinition
* args
= getOperand(argsId
);
3469 MDefinition
* begin
= getOperand(beginId
);
3470 MDefinition
* end
= getOperand(endId
);
3472 // TODO: support pre-tenuring.
3473 gc::Heap heap
= gc::Heap::Default
;
3476 MArgumentsSlice::New(alloc(), args
, begin
, end
, templateObj
, heap
);
3480 return resumeAfter(ins
);
3483 bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId
,
3484 uint32_t claspOffset
) {
3485 MDefinition
* obj
= getOperand(objId
);
3486 const JSClass
* clasp
= classStubField(claspOffset
);
3488 auto* hasClass
= MHasClass::New(alloc(), obj
, clasp
);
3491 pushResult(hasClass
);
3495 bool WarpCacheIRTranspiler::emitCallRegExpMatcherResult(
3496 ObjOperandId regexpId
, StringOperandId inputId
, Int32OperandId lastIndexId
,
3497 uint32_t stubOffset
) {
3498 MDefinition
* regexp
= getOperand(regexpId
);
3499 MDefinition
* input
= getOperand(inputId
);
3500 MDefinition
* lastIndex
= getOperand(lastIndexId
);
3502 auto* matcher
= MRegExpMatcher::New(alloc(), regexp
, input
, lastIndex
);
3503 addEffectful(matcher
);
3504 pushResult(matcher
);
3506 return resumeAfter(matcher
);
3509 bool WarpCacheIRTranspiler::emitCallRegExpSearcherResult(
3510 ObjOperandId regexpId
, StringOperandId inputId
, Int32OperandId lastIndexId
,
3511 uint32_t stubOffset
) {
3512 MDefinition
* regexp
= getOperand(regexpId
);
3513 MDefinition
* input
= getOperand(inputId
);
3514 MDefinition
* lastIndex
= getOperand(lastIndexId
);
3516 auto* searcher
= MRegExpSearcher::New(alloc(), regexp
, input
, lastIndex
);
3517 addEffectful(searcher
);
3518 pushResult(searcher
);
3520 return resumeAfter(searcher
);
3523 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecMatchResult(
3524 ObjOperandId regexpId
, StringOperandId inputId
, uint32_t stubOffset
) {
3525 MDefinition
* regexp
= getOperand(regexpId
);
3526 MDefinition
* input
= getOperand(inputId
);
3528 auto* ins
= MRegExpExecMatch::New(alloc(), regexp
, input
);
3532 return resumeAfter(ins
);
3535 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecTestResult(
3536 ObjOperandId regexpId
, StringOperandId inputId
, uint32_t stubOffset
) {
3537 MDefinition
* regexp
= getOperand(regexpId
);
3538 MDefinition
* input
= getOperand(inputId
);
3540 auto* ins
= MRegExpExecTest::New(alloc(), regexp
, input
);
3544 return resumeAfter(ins
);
3547 MInstruction
* WarpCacheIRTranspiler::convertToBoolean(MDefinition
* input
) {
3548 // Convert to bool with the '!!' idiom.
3550 // The FoldTests and GVN passes both specifically handle this pattern. If you
3551 // change this code, make sure to update FoldTests and GVN, too.
3553 auto* resultInverted
= MNot::New(alloc(), input
);
3554 add(resultInverted
);
3555 auto* result
= MNot::New(alloc(), resultInverted
);
3561 bool WarpCacheIRTranspiler::emitRegExpFlagResult(ObjOperandId regexpId
,
3562 int32_t flagsMask
) {
3563 MDefinition
* regexp
= getOperand(regexpId
);
3565 auto* flags
= MLoadFixedSlot::New(alloc(), regexp
, RegExpObject::flagsSlot());
3566 flags
->setResultType(MIRType::Int32
);
3569 auto* mask
= MConstant::New(alloc(), Int32Value(flagsMask
));
3572 auto* maskedFlag
= MBitAnd::New(alloc(), flags
, mask
, MIRType::Int32
);
3575 auto* result
= convertToBoolean(maskedFlag
);
3581 bool WarpCacheIRTranspiler::emitCallSubstringKernelResult(
3582 StringOperandId strId
, Int32OperandId beginId
, Int32OperandId lengthId
) {
3583 MDefinition
* str
= getOperand(strId
);
3584 MDefinition
* begin
= getOperand(beginId
);
3585 MDefinition
* length
= getOperand(lengthId
);
3587 auto* substr
= MSubstr::New(alloc(), str
, begin
, length
);
3594 bool WarpCacheIRTranspiler::emitStringReplaceStringResult(
3595 StringOperandId strId
, StringOperandId patternId
,
3596 StringOperandId replacementId
) {
3597 MDefinition
* str
= getOperand(strId
);
3598 MDefinition
* pattern
= getOperand(patternId
);
3599 MDefinition
* replacement
= getOperand(replacementId
);
3601 auto* replace
= MStringReplace::New(alloc(), str
, pattern
, replacement
);
3604 pushResult(replace
);
3608 bool WarpCacheIRTranspiler::emitStringSplitStringResult(
3609 StringOperandId strId
, StringOperandId separatorId
) {
3610 MDefinition
* str
= getOperand(strId
);
3611 MDefinition
* separator
= getOperand(separatorId
);
3613 auto* split
= MStringSplit::New(alloc(), str
, separator
);
3620 bool WarpCacheIRTranspiler::emitRegExpPrototypeOptimizableResult(
3621 ObjOperandId protoId
) {
3622 MDefinition
* proto
= getOperand(protoId
);
3624 auto* optimizable
= MRegExpPrototypeOptimizable::New(alloc(), proto
);
3627 pushResult(optimizable
);
3631 bool WarpCacheIRTranspiler::emitRegExpInstanceOptimizableResult(
3632 ObjOperandId regexpId
, ObjOperandId protoId
) {
3633 MDefinition
* regexp
= getOperand(regexpId
);
3634 MDefinition
* proto
= getOperand(protoId
);
3636 auto* optimizable
= MRegExpInstanceOptimizable::New(alloc(), regexp
, proto
);
3639 pushResult(optimizable
);
3643 bool WarpCacheIRTranspiler::emitGetFirstDollarIndexResult(
3644 StringOperandId strId
) {
3645 MDefinition
* str
= getOperand(strId
);
3647 auto* firstDollarIndex
= MGetFirstDollarIndex::New(alloc(), str
);
3648 add(firstDollarIndex
);
3650 pushResult(firstDollarIndex
);
3654 bool WarpCacheIRTranspiler::emitIsArrayResult(ValOperandId inputId
) {
3655 MDefinition
* value
= getOperand(inputId
);
3657 auto* isArray
= MIsArray::New(alloc(), value
);
3658 addEffectful(isArray
);
3659 pushResult(isArray
);
3661 return resumeAfter(isArray
);
3664 bool WarpCacheIRTranspiler::emitIsObjectResult(ValOperandId inputId
) {
3665 MDefinition
* value
= getOperand(inputId
);
3667 if (value
->type() == MIRType::Object
) {
3668 pushResult(constant(BooleanValue(true)));
3670 auto* isObject
= MIsObject::New(alloc(), value
);
3672 pushResult(isObject
);
3678 bool WarpCacheIRTranspiler::emitIsPackedArrayResult(ObjOperandId objId
) {
3679 MDefinition
* obj
= getOperand(objId
);
3681 auto* isPackedArray
= MIsPackedArray::New(alloc(), obj
);
3684 pushResult(isPackedArray
);
3688 bool WarpCacheIRTranspiler::emitIsCallableResult(ValOperandId inputId
) {
3689 MDefinition
* value
= getOperand(inputId
);
3691 auto* isCallable
= MIsCallable::New(alloc(), value
);
3694 pushResult(isCallable
);
3698 bool WarpCacheIRTranspiler::emitIsConstructorResult(ObjOperandId objId
) {
3699 MDefinition
* obj
= getOperand(objId
);
3701 auto* isConstructor
= MIsConstructor::New(alloc(), obj
);
3704 pushResult(isConstructor
);
3708 bool WarpCacheIRTranspiler::emitIsCrossRealmArrayConstructorResult(
3709 ObjOperandId objId
) {
3710 MDefinition
* obj
= getOperand(objId
);
3712 auto* ins
= MIsCrossRealmArrayConstructor::New(alloc(), obj
);
3719 bool WarpCacheIRTranspiler::emitIsTypedArrayResult(ObjOperandId objId
,
3720 bool isPossiblyWrapped
) {
3721 MDefinition
* obj
= getOperand(objId
);
3723 auto* ins
= MIsTypedArray::New(alloc(), obj
, isPossiblyWrapped
);
3724 if (isPossiblyWrapped
) {
3732 if (isPossiblyWrapped
) {
3733 if (!resumeAfter(ins
)) {
3741 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetInt32Result(
3742 ObjOperandId objId
) {
3743 MDefinition
* obj
= getOperand(objId
);
3745 auto* byteOffset
= MArrayBufferViewByteOffset::New(alloc(), obj
);
3748 auto* byteOffsetInt32
= MNonNegativeIntPtrToInt32::New(alloc(), byteOffset
);
3749 add(byteOffsetInt32
);
3751 pushResult(byteOffsetInt32
);
3755 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetDoubleResult(
3756 ObjOperandId objId
) {
3757 MDefinition
* obj
= getOperand(objId
);
3759 auto* byteOffset
= MArrayBufferViewByteOffset::New(alloc(), obj
);
3762 auto* byteOffsetDouble
= MIntPtrToDouble::New(alloc(), byteOffset
);
3763 add(byteOffsetDouble
);
3765 pushResult(byteOffsetDouble
);
3769 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthInt32Result(
3770 ObjOperandId objId
) {
3771 MDefinition
* obj
= getOperand(objId
);
3773 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
3776 auto* lengthInt32
= MNonNegativeIntPtrToInt32::New(alloc(), length
);
3779 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
3782 auto* mul
= MMul::New(alloc(), lengthInt32
, size
, MIRType::Int32
);
3783 mul
->setCanBeNegativeZero(false);
3790 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthDoubleResult(
3791 ObjOperandId objId
) {
3792 MDefinition
* obj
= getOperand(objId
);
3794 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
3797 auto* lengthDouble
= MIntPtrToDouble::New(alloc(), length
);
3800 auto* size
= MTypedArrayElementSize::New(alloc(), obj
);
3803 auto* mul
= MMul::New(alloc(), lengthDouble
, size
, MIRType::Double
);
3804 mul
->setCanBeNegativeZero(false);
3811 bool WarpCacheIRTranspiler::emitTypedArrayElementSizeResult(
3812 ObjOperandId objId
) {
3813 MDefinition
* obj
= getOperand(objId
);
3815 auto* ins
= MTypedArrayElementSize::New(alloc(), obj
);
3822 bool WarpCacheIRTranspiler::emitGuardHasAttachedArrayBuffer(
3823 ObjOperandId objId
) {
3824 MDefinition
* obj
= getOperand(objId
);
3826 auto* ins
= MGuardHasAttachedArrayBuffer::New(alloc(), obj
);
3829 setOperand(objId
, ins
);
3833 bool WarpCacheIRTranspiler::emitIsTypedArrayConstructorResult(
3834 ObjOperandId objId
) {
3835 MDefinition
* obj
= getOperand(objId
);
3837 auto* ins
= MIsTypedArrayConstructor::New(alloc(), obj
);
3844 bool WarpCacheIRTranspiler::emitGetNextMapSetEntryForIteratorResult(
3845 ObjOperandId iterId
, ObjOperandId resultArrId
, bool isMap
) {
3846 MDefinition
* iter
= getOperand(iterId
);
3847 MDefinition
* resultArr
= getOperand(resultArrId
);
3849 MGetNextEntryForIterator::Mode mode
=
3850 isMap
? MGetNextEntryForIterator::Map
: MGetNextEntryForIterator::Set
;
3851 auto* ins
= MGetNextEntryForIterator::New(alloc(), iter
, resultArr
, mode
);
3855 return resumeAfter(ins
);
3858 bool WarpCacheIRTranspiler::emitFrameIsConstructingResult() {
3859 if (const CallInfo
* callInfo
= builder_
->inlineCallInfo()) {
3860 auto* ins
= constant(BooleanValue(callInfo
->constructing()));
3865 auto* ins
= MIsConstructing::New(alloc());
3871 bool WarpCacheIRTranspiler::emitNewIteratorResult(
3872 MNewIterator::Type type
, uint32_t templateObjectOffset
) {
3873 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3875 auto* templateConst
= constant(ObjectValue(*templateObj
));
3876 auto* iter
= MNewIterator::New(alloc(), templateConst
, type
);
3883 bool WarpCacheIRTranspiler::emitNewArrayIteratorResult(
3884 uint32_t templateObjectOffset
) {
3885 return emitNewIteratorResult(MNewIterator::ArrayIterator
,
3886 templateObjectOffset
);
3889 bool WarpCacheIRTranspiler::emitNewStringIteratorResult(
3890 uint32_t templateObjectOffset
) {
3891 return emitNewIteratorResult(MNewIterator::StringIterator
,
3892 templateObjectOffset
);
3895 bool WarpCacheIRTranspiler::emitNewRegExpStringIteratorResult(
3896 uint32_t templateObjectOffset
) {
3897 return emitNewIteratorResult(MNewIterator::RegExpStringIterator
,
3898 templateObjectOffset
);
3901 bool WarpCacheIRTranspiler::emitObjectCreateResult(
3902 uint32_t templateObjectOffset
) {
3903 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3905 auto* templateConst
= constant(ObjectValue(*templateObj
));
3907 // TODO: support pre-tenuring.
3908 gc::Heap heap
= gc::Heap::Default
;
3910 MNewObject::New(alloc(), templateConst
, heap
, MNewObject::ObjectCreate
);
3914 return resumeAfter(obj
);
3917 bool WarpCacheIRTranspiler::emitNewArrayFromLengthResult(
3918 uint32_t templateObjectOffset
, Int32OperandId lengthId
) {
3919 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3920 MDefinition
* length
= getOperand(lengthId
);
3922 // TODO: support pre-tenuring.
3923 gc::Heap heap
= gc::Heap::Default
;
3925 if (length
->isConstant()) {
3926 int32_t lenInt32
= length
->toConstant()->toInt32();
3927 if (lenInt32
>= 0 &&
3928 uint32_t(lenInt32
) == templateObj
->as
<ArrayObject
>().length()) {
3929 uint32_t len
= uint32_t(lenInt32
);
3930 auto* templateConst
= constant(ObjectValue(*templateObj
));
3932 size_t inlineLength
=
3933 gc::GetGCKindSlots(templateObj
->asTenured().getAllocKind()) -
3934 ObjectElements::VALUES_PER_HEADER
;
3937 if (len
> inlineLength
) {
3938 obj
= MNewArray::NewVM(alloc(), len
, templateConst
, heap
);
3940 obj
= MNewArray::New(alloc(), len
, templateConst
, heap
);
3948 auto* obj
= MNewArrayDynamicLength::New(alloc(), length
, templateObj
, heap
);
3951 return resumeAfter(obj
);
3954 bool WarpCacheIRTranspiler::emitNewTypedArrayFromLengthResult(
3955 uint32_t templateObjectOffset
, Int32OperandId lengthId
) {
3956 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3957 MDefinition
* length
= getOperand(lengthId
);
3959 // TODO: support pre-tenuring.
3960 gc::Heap heap
= gc::Heap::Default
;
3962 if (length
->isConstant()) {
3963 int32_t len
= length
->toConstant()->toInt32();
3965 uint32_t(len
) == templateObj
->as
<TypedArrayObject
>().length()) {
3966 auto* templateConst
= constant(ObjectValue(*templateObj
));
3967 auto* obj
= MNewTypedArray::New(alloc(), templateConst
, heap
);
3975 MNewTypedArrayDynamicLength::New(alloc(), length
, templateObj
, heap
);
3978 return resumeAfter(obj
);
3981 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayBufferResult(
3982 uint32_t templateObjectOffset
, ObjOperandId bufferId
,
3983 ValOperandId byteOffsetId
, ValOperandId lengthId
) {
3984 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
3985 MDefinition
* buffer
= getOperand(bufferId
);
3986 MDefinition
* byteOffset
= getOperand(byteOffsetId
);
3987 MDefinition
* length
= getOperand(lengthId
);
3989 // TODO: support pre-tenuring.
3990 gc::Heap heap
= gc::Heap::Default
;
3992 auto* obj
= MNewTypedArrayFromArrayBuffer::New(alloc(), buffer
, byteOffset
,
3993 length
, templateObj
, heap
);
3997 return resumeAfter(obj
);
4000 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayResult(
4001 uint32_t templateObjectOffset
, ObjOperandId arrayId
) {
4002 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
4003 MDefinition
* array
= getOperand(arrayId
);
4005 // TODO: support pre-tenuring.
4006 gc::Heap heap
= gc::Heap::Default
;
4008 auto* obj
= MNewTypedArrayFromArray::New(alloc(), array
, templateObj
, heap
);
4012 return resumeAfter(obj
);
4015 bool WarpCacheIRTranspiler::emitAtomicsCompareExchangeResult(
4016 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t expectedId
,
4017 uint32_t replacementId
, Scalar::Type elementType
) {
4018 MDefinition
* obj
= getOperand(objId
);
4019 MDefinition
* index
= getOperand(indexId
);
4020 MDefinition
* expected
= getOperand(ValOperandId(expectedId
));
4021 MDefinition
* replacement
= getOperand(ValOperandId(replacementId
));
4023 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4026 index
= addBoundsCheck(index
, length
);
4028 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4031 bool forceDoubleForUint32
= true;
4033 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4035 auto* cas
= MCompareExchangeTypedArrayElement::New(
4036 alloc(), elements
, index
, elementType
, expected
, replacement
);
4037 cas
->setResultType(knownType
);
4041 return resumeAfter(cas
);
4044 bool WarpCacheIRTranspiler::emitAtomicsExchangeResult(
4045 ObjOperandId objId
, IntPtrOperandId indexId
, uint32_t valueId
,
4046 Scalar::Type elementType
) {
4047 MDefinition
* obj
= getOperand(objId
);
4048 MDefinition
* index
= getOperand(indexId
);
4049 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4051 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4054 index
= addBoundsCheck(index
, length
);
4056 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4059 bool forceDoubleForUint32
= true;
4061 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4063 auto* exchange
= MAtomicExchangeTypedArrayElement::New(
4064 alloc(), elements
, index
, value
, elementType
);
4065 exchange
->setResultType(knownType
);
4066 addEffectful(exchange
);
4068 pushResult(exchange
);
4069 return resumeAfter(exchange
);
4072 bool WarpCacheIRTranspiler::emitAtomicsBinaryOp(ObjOperandId objId
,
4073 IntPtrOperandId indexId
,
4075 Scalar::Type elementType
,
4076 bool forEffect
, AtomicOp op
) {
4077 MDefinition
* obj
= getOperand(objId
);
4078 MDefinition
* index
= getOperand(indexId
);
4079 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4081 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4084 index
= addBoundsCheck(index
, length
);
4086 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4089 bool forceDoubleForUint32
= true;
4091 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4093 auto* binop
= MAtomicTypedArrayElementBinop::New(
4094 alloc(), op
, elements
, index
, elementType
, value
, forEffect
);
4096 binop
->setResultType(knownType
);
4098 addEffectful(binop
);
4103 pushResult(constant(UndefinedValue()));
4105 return resumeAfter(binop
);
4108 bool WarpCacheIRTranspiler::emitAtomicsAddResult(ObjOperandId objId
,
4109 IntPtrOperandId indexId
,
4111 Scalar::Type elementType
,
4113 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4117 bool WarpCacheIRTranspiler::emitAtomicsSubResult(ObjOperandId objId
,
4118 IntPtrOperandId indexId
,
4120 Scalar::Type elementType
,
4122 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4126 bool WarpCacheIRTranspiler::emitAtomicsAndResult(ObjOperandId objId
,
4127 IntPtrOperandId indexId
,
4129 Scalar::Type elementType
,
4131 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4135 bool WarpCacheIRTranspiler::emitAtomicsOrResult(ObjOperandId objId
,
4136 IntPtrOperandId indexId
,
4138 Scalar::Type elementType
,
4140 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4144 bool WarpCacheIRTranspiler::emitAtomicsXorResult(ObjOperandId objId
,
4145 IntPtrOperandId indexId
,
4147 Scalar::Type elementType
,
4149 return emitAtomicsBinaryOp(objId
, indexId
, valueId
, elementType
, forEffect
,
4153 bool WarpCacheIRTranspiler::emitAtomicsLoadResult(ObjOperandId objId
,
4154 IntPtrOperandId indexId
,
4155 Scalar::Type elementType
) {
4156 MDefinition
* obj
= getOperand(objId
);
4157 MDefinition
* index
= getOperand(indexId
);
4159 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4162 index
= addBoundsCheck(index
, length
);
4164 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4167 bool forceDoubleForUint32
= true;
4169 MIRTypeForArrayBufferViewRead(elementType
, forceDoubleForUint32
);
4171 auto* load
= MLoadUnboxedScalar::New(alloc(), elements
, index
, elementType
,
4172 DoesRequireMemoryBarrier
);
4173 load
->setResultType(knownType
);
4177 return resumeAfter(load
);
4180 bool WarpCacheIRTranspiler::emitAtomicsStoreResult(ObjOperandId objId
,
4181 IntPtrOperandId indexId
,
4183 Scalar::Type elementType
) {
4184 MDefinition
* obj
= getOperand(objId
);
4185 MDefinition
* index
= getOperand(indexId
);
4186 MDefinition
* value
= getOperand(ValOperandId(valueId
));
4188 auto* length
= MArrayBufferViewLength::New(alloc(), obj
);
4191 index
= addBoundsCheck(index
, length
);
4193 auto* elements
= MArrayBufferViewElements::New(alloc(), obj
);
4196 auto* store
= MStoreUnboxedScalar::New(alloc(), elements
, index
, value
,
4197 elementType
, DoesRequireMemoryBarrier
);
4198 addEffectful(store
);
4201 return resumeAfter(store
);
4204 bool WarpCacheIRTranspiler::emitAtomicsIsLockFreeResult(
4205 Int32OperandId valueId
) {
4206 MDefinition
* value
= getOperand(valueId
);
4208 auto* ilf
= MAtomicIsLockFree::New(alloc(), value
);
4215 bool WarpCacheIRTranspiler::emitBigIntAsIntNResult(Int32OperandId bitsId
,
4216 BigIntOperandId bigIntId
) {
4217 MDefinition
* bits
= getOperand(bitsId
);
4218 MDefinition
* bigInt
= getOperand(bigIntId
);
4220 auto* ins
= MBigIntAsIntN::New(alloc(), bits
, bigInt
);
4227 bool WarpCacheIRTranspiler::emitBigIntAsUintNResult(Int32OperandId bitsId
,
4228 BigIntOperandId bigIntId
) {
4229 MDefinition
* bits
= getOperand(bitsId
);
4230 MDefinition
* bigInt
= getOperand(bigIntId
);
4232 auto* ins
= MBigIntAsUintN::New(alloc(), bits
, bigInt
);
4239 bool WarpCacheIRTranspiler::emitGuardToNonGCThing(ValOperandId inputId
) {
4240 MDefinition
* def
= getOperand(inputId
);
4241 if (IsNonGCThing(def
->type())) {
4245 auto* ins
= MGuardNonGCThing::New(alloc(), def
);
4248 setOperand(inputId
, ins
);
4252 bool WarpCacheIRTranspiler::emitSetHasNonGCThingResult(ObjOperandId setId
,
4253 ValOperandId valId
) {
4254 MDefinition
* set
= getOperand(setId
);
4255 MDefinition
* val
= getOperand(valId
);
4257 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
4260 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
4263 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, hashValue
, hash
);
4270 bool WarpCacheIRTranspiler::emitSetHasStringResult(ObjOperandId setId
,
4271 StringOperandId strId
) {
4272 MDefinition
* set
= getOperand(setId
);
4273 MDefinition
* str
= getOperand(strId
);
4275 auto* hashValue
= MToHashableString::New(alloc(), str
);
4278 auto* hash
= MHashString::New(alloc(), hashValue
);
4281 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, hashValue
, hash
);
4288 bool WarpCacheIRTranspiler::emitSetHasSymbolResult(ObjOperandId setId
,
4289 SymbolOperandId symId
) {
4290 MDefinition
* set
= getOperand(setId
);
4291 MDefinition
* sym
= getOperand(symId
);
4293 auto* hash
= MHashSymbol::New(alloc(), sym
);
4296 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, sym
, hash
);
4303 bool WarpCacheIRTranspiler::emitSetHasBigIntResult(ObjOperandId setId
,
4304 BigIntOperandId bigIntId
) {
4305 MDefinition
* set
= getOperand(setId
);
4306 MDefinition
* bigInt
= getOperand(bigIntId
);
4308 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
4311 auto* ins
= MSetObjectHasBigInt::New(alloc(), set
, bigInt
, hash
);
4318 bool WarpCacheIRTranspiler::emitSetHasObjectResult(ObjOperandId setId
,
4319 ObjOperandId objId
) {
4320 MDefinition
* set
= getOperand(setId
);
4321 MDefinition
* obj
= getOperand(objId
);
4323 auto* hash
= MHashObject::New(alloc(), set
, obj
);
4326 auto* ins
= MSetObjectHasNonBigInt::New(alloc(), set
, obj
, hash
);
4333 bool WarpCacheIRTranspiler::emitSetHasResult(ObjOperandId setId
,
4334 ValOperandId valId
) {
4335 MDefinition
* set
= getOperand(setId
);
4336 MDefinition
* val
= getOperand(valId
);
4339 auto* hashValue
= MToHashableValue::New(alloc(), val
);
4342 auto* hash
= MHashValue::New(alloc(), set
, hashValue
);
4345 auto* ins
= MSetObjectHasValue::New(alloc(), set
, hashValue
, hash
);
4348 auto* ins
= MSetObjectHasValueVMCall::New(alloc(), set
, val
);
4356 bool WarpCacheIRTranspiler::emitSetSizeResult(ObjOperandId setId
) {
4357 MDefinition
* set
= getOperand(setId
);
4359 auto* ins
= MSetObjectSize::New(alloc(), set
);
4366 bool WarpCacheIRTranspiler::emitMapHasNonGCThingResult(ObjOperandId mapId
,
4367 ValOperandId valId
) {
4368 MDefinition
* map
= getOperand(mapId
);
4369 MDefinition
* val
= getOperand(valId
);
4371 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
4374 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
4377 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, hashValue
, hash
);
4384 bool WarpCacheIRTranspiler::emitMapHasStringResult(ObjOperandId mapId
,
4385 StringOperandId strId
) {
4386 MDefinition
* map
= getOperand(mapId
);
4387 MDefinition
* str
= getOperand(strId
);
4389 auto* hashValue
= MToHashableString::New(alloc(), str
);
4392 auto* hash
= MHashString::New(alloc(), hashValue
);
4395 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, hashValue
, hash
);
4402 bool WarpCacheIRTranspiler::emitMapHasSymbolResult(ObjOperandId mapId
,
4403 SymbolOperandId symId
) {
4404 MDefinition
* map
= getOperand(mapId
);
4405 MDefinition
* sym
= getOperand(symId
);
4407 auto* hash
= MHashSymbol::New(alloc(), sym
);
4410 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, sym
, hash
);
4417 bool WarpCacheIRTranspiler::emitMapHasBigIntResult(ObjOperandId mapId
,
4418 BigIntOperandId bigIntId
) {
4419 MDefinition
* map
= getOperand(mapId
);
4420 MDefinition
* bigInt
= getOperand(bigIntId
);
4422 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
4425 auto* ins
= MMapObjectHasBigInt::New(alloc(), map
, bigInt
, hash
);
4432 bool WarpCacheIRTranspiler::emitMapHasObjectResult(ObjOperandId mapId
,
4433 ObjOperandId objId
) {
4434 MDefinition
* map
= getOperand(mapId
);
4435 MDefinition
* obj
= getOperand(objId
);
4437 auto* hash
= MHashObject::New(alloc(), map
, obj
);
4440 auto* ins
= MMapObjectHasNonBigInt::New(alloc(), map
, obj
, hash
);
4447 bool WarpCacheIRTranspiler::emitMapHasResult(ObjOperandId mapId
,
4448 ValOperandId valId
) {
4449 MDefinition
* map
= getOperand(mapId
);
4450 MDefinition
* val
= getOperand(valId
);
4453 auto* hashValue
= MToHashableValue::New(alloc(), val
);
4456 auto* hash
= MHashValue::New(alloc(), map
, hashValue
);
4459 auto* ins
= MMapObjectHasValue::New(alloc(), map
, hashValue
, hash
);
4462 auto* ins
= MMapObjectHasValueVMCall::New(alloc(), map
, val
);
4470 bool WarpCacheIRTranspiler::emitMapGetNonGCThingResult(ObjOperandId mapId
,
4471 ValOperandId valId
) {
4472 MDefinition
* map
= getOperand(mapId
);
4473 MDefinition
* val
= getOperand(valId
);
4475 auto* hashValue
= MToHashableNonGCThing::New(alloc(), val
);
4478 auto* hash
= MHashNonGCThing::New(alloc(), hashValue
);
4481 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, hashValue
, hash
);
4488 bool WarpCacheIRTranspiler::emitMapGetStringResult(ObjOperandId mapId
,
4489 StringOperandId strId
) {
4490 MDefinition
* map
= getOperand(mapId
);
4491 MDefinition
* str
= getOperand(strId
);
4493 auto* hashValue
= MToHashableString::New(alloc(), str
);
4496 auto* hash
= MHashString::New(alloc(), hashValue
);
4499 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, hashValue
, hash
);
4506 bool WarpCacheIRTranspiler::emitMapGetSymbolResult(ObjOperandId mapId
,
4507 SymbolOperandId symId
) {
4508 MDefinition
* map
= getOperand(mapId
);
4509 MDefinition
* sym
= getOperand(symId
);
4511 auto* hash
= MHashSymbol::New(alloc(), sym
);
4514 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, sym
, hash
);
4521 bool WarpCacheIRTranspiler::emitMapGetBigIntResult(ObjOperandId mapId
,
4522 BigIntOperandId bigIntId
) {
4523 MDefinition
* map
= getOperand(mapId
);
4524 MDefinition
* bigInt
= getOperand(bigIntId
);
4526 auto* hash
= MHashBigInt::New(alloc(), bigInt
);
4529 auto* ins
= MMapObjectGetBigInt::New(alloc(), map
, bigInt
, hash
);
4536 bool WarpCacheIRTranspiler::emitMapGetObjectResult(ObjOperandId mapId
,
4537 ObjOperandId objId
) {
4538 MDefinition
* map
= getOperand(mapId
);
4539 MDefinition
* obj
= getOperand(objId
);
4541 auto* hash
= MHashObject::New(alloc(), map
, obj
);
4544 auto* ins
= MMapObjectGetNonBigInt::New(alloc(), map
, obj
, hash
);
4551 bool WarpCacheIRTranspiler::emitMapGetResult(ObjOperandId mapId
,
4552 ValOperandId valId
) {
4553 MDefinition
* map
= getOperand(mapId
);
4554 MDefinition
* val
= getOperand(valId
);
4557 auto* hashValue
= MToHashableValue::New(alloc(), val
);
4560 auto* hash
= MHashValue::New(alloc(), map
, hashValue
);
4563 auto* ins
= MMapObjectGetValue::New(alloc(), map
, hashValue
, hash
);
4566 auto* ins
= MMapObjectGetValueVMCall::New(alloc(), map
, val
);
4574 bool WarpCacheIRTranspiler::emitMapSizeResult(ObjOperandId mapId
) {
4575 MDefinition
* map
= getOperand(mapId
);
4577 auto* ins
= MMapObjectSize::New(alloc(), map
);
4584 bool WarpCacheIRTranspiler::emitTruthyResult(OperandId inputId
) {
4585 MDefinition
* input
= getOperand(inputId
);
4587 auto* result
= convertToBoolean(input
);
4593 bool WarpCacheIRTranspiler::emitLoadInt32TruthyResult(ValOperandId inputId
) {
4594 return emitTruthyResult(inputId
);
4597 bool WarpCacheIRTranspiler::emitLoadDoubleTruthyResult(
4598 NumberOperandId inputId
) {
4599 return emitTruthyResult(inputId
);
4602 bool WarpCacheIRTranspiler::emitLoadStringTruthyResult(
4603 StringOperandId inputId
) {
4604 return emitTruthyResult(inputId
);
4607 bool WarpCacheIRTranspiler::emitLoadObjectTruthyResult(ObjOperandId inputId
) {
4608 return emitTruthyResult(inputId
);
4611 bool WarpCacheIRTranspiler::emitLoadBigIntTruthyResult(
4612 BigIntOperandId inputId
) {
4613 return emitTruthyResult(inputId
);
4616 bool WarpCacheIRTranspiler::emitLoadValueTruthyResult(ValOperandId inputId
) {
4617 return emitTruthyResult(inputId
);
4620 bool WarpCacheIRTranspiler::emitLoadOperandResult(ValOperandId inputId
) {
4621 MDefinition
* input
= getOperand(inputId
);
4626 bool WarpCacheIRTranspiler::emitLoadWrapperTarget(ObjOperandId objId
,
4627 ObjOperandId resultId
) {
4628 MDefinition
* obj
= getOperand(objId
);
4630 auto* ins
= MLoadWrapperTarget::New(alloc(), obj
);
4633 return defineOperand(resultId
, ins
);
4636 // When we transpile a call, we may generate guards for some
4637 // arguments. To make sure the call instruction depends on those
4638 // guards, when the transpiler creates an operand for an argument, we
4639 // register the OperandId of that argument in argumentIds_. (See
4640 // emitLoadArgumentSlot.) Before generating the call, we update the
4641 // CallInfo to use the appropriate value from operands_.
4642 // Note: The callee is an explicit argument to the call op, and is
4643 // tracked separately.
4644 void WarpCacheIRTranspiler::updateArgumentsFromOperands() {
4645 for (uint32_t i
= 0; i
< uint32_t(ArgumentKind::NumKinds
); i
++) {
4646 ArgumentKind kind
= ArgumentKind(i
);
4647 OperandId id
= argumentOperandIds_
[kind
];
4650 case ArgumentKind::This
:
4651 callInfo_
->setThis(getOperand(id
));
4653 case ArgumentKind::NewTarget
:
4654 callInfo_
->setNewTarget(getOperand(id
));
4656 case ArgumentKind::Arg0
:
4657 callInfo_
->setArg(0, getOperand(id
));
4659 case ArgumentKind::Arg1
:
4660 callInfo_
->setArg(1, getOperand(id
));
4662 case ArgumentKind::Arg2
:
4663 callInfo_
->setArg(2, getOperand(id
));
4665 case ArgumentKind::Arg3
:
4666 callInfo_
->setArg(3, getOperand(id
));
4668 case ArgumentKind::Arg4
:
4669 callInfo_
->setArg(4, getOperand(id
));
4671 case ArgumentKind::Arg5
:
4672 callInfo_
->setArg(5, getOperand(id
));
4674 case ArgumentKind::Arg6
:
4675 callInfo_
->setArg(6, getOperand(id
));
4677 case ArgumentKind::Arg7
:
4678 callInfo_
->setArg(7, getOperand(id
));
4680 case ArgumentKind::Callee
:
4681 case ArgumentKind::NumKinds
:
4682 MOZ_CRASH("Unexpected argument kind");
4688 bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId
,
4689 uint32_t slotIndex
) {
4690 // Reverse of GetIndexOfArgument.
4693 // NewTarget | Args.. (reversed) | ThisValue | Callee
4694 // 0 | ArgC .. Arg1 Arg0 (+1) | argc (+1) | argc + 1 (+ 1)
4695 // ^ (if constructing)
4697 // NewTarget (optional)
4698 if (callInfo_
->constructing()) {
4699 if (slotIndex
== 0) {
4700 setArgumentId(ArgumentKind::NewTarget
, resultId
);
4701 return defineOperand(resultId
, callInfo_
->getNewTarget());
4704 slotIndex
-= 1; // Adjust slot index to match non-constructing calls.
4708 if (slotIndex
< callInfo_
->argc()) {
4709 uint32_t arg
= callInfo_
->argc() - 1 - slotIndex
;
4710 ArgumentKind kind
= ArgumentKindForArgIndex(arg
);
4711 MOZ_ASSERT(kind
< ArgumentKind::NumKinds
);
4712 setArgumentId(kind
, resultId
);
4713 return defineOperand(resultId
, callInfo_
->getArg(arg
));
4717 if (slotIndex
== callInfo_
->argc()) {
4718 setArgumentId(ArgumentKind::This
, resultId
);
4719 return defineOperand(resultId
, callInfo_
->thisArg());
4723 MOZ_ASSERT(slotIndex
== callInfo_
->argc() + 1);
4724 return defineOperand(resultId
, callInfo_
->callee());
4727 bool WarpCacheIRTranspiler::emitLoadArgumentFixedSlot(ValOperandId resultId
,
4728 uint8_t slotIndex
) {
4729 return emitLoadArgumentSlot(resultId
, slotIndex
);
4732 bool WarpCacheIRTranspiler::emitLoadArgumentDynamicSlot(ValOperandId resultId
,
4733 Int32OperandId argcId
,
4734 uint8_t slotIndex
) {
4736 MDefinition
* argc
= getOperand(argcId
);
4737 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
4738 static_cast<int32_t>(callInfo_
->argc()));
4741 return emitLoadArgumentSlot(resultId
, callInfo_
->argc() + slotIndex
);
4744 WrappedFunction
* WarpCacheIRTranspiler::maybeWrappedFunction(
4745 MDefinition
* callee
, CallKind kind
, uint16_t nargs
, FunctionFlags flags
) {
4746 MOZ_ASSERT(callee
->isConstant() || callee
->isNurseryObject());
4748 // If this is a native without a JitEntry, WrappedFunction needs to know the
4749 // target JSFunction.
4750 // TODO: support nursery-allocated natives with WrappedFunction, maybe by
4751 // storing the JSNative in the Baseline stub like flags/nargs.
4752 bool isNative
= flags
.isNativeWithoutJitEntry();
4753 if (isNative
&& !callee
->isConstant()) {
4757 JSFunction
* nativeTarget
= nullptr;
4759 nativeTarget
= &callee
->toConstant()->toObject().as
<JSFunction
>();
4762 WrappedFunction
* wrappedTarget
=
4763 new (alloc()) WrappedFunction(nativeTarget
, nargs
, flags
);
4764 MOZ_ASSERT_IF(kind
== CallKind::Native
|| kind
== CallKind::DOM
,
4765 wrappedTarget
->isNativeWithoutJitEntry());
4766 MOZ_ASSERT_IF(kind
== CallKind::Scripted
, wrappedTarget
->hasJitEntry());
4767 return wrappedTarget
;
4770 WrappedFunction
* WarpCacheIRTranspiler::maybeCallTarget(MDefinition
* callee
,
4772 // CacheIR emits the following for specialized calls:
4773 // GuardSpecificFunction <callee> <func> ..
4774 // Call(Native|Scripted)Function <callee> ..
4776 // GuardClass <callee> ..
4777 // GuardFunctionScript <callee> <script> ..
4778 // CallScriptedFunction <callee> ..
4780 // We can use the <func> JSFunction or <script> BaseScript to specialize this
4782 if (callee
->isGuardSpecificFunction()) {
4783 auto* guard
= callee
->toGuardSpecificFunction();
4784 return maybeWrappedFunction(guard
->expected(), kind
, guard
->nargs(),
4787 if (callee
->isGuardFunctionScript()) {
4788 MOZ_ASSERT(kind
== CallKind::Scripted
);
4789 auto* guard
= callee
->toGuardFunctionScript();
4790 WrappedFunction
* wrappedTarget
= new (alloc()) WrappedFunction(
4791 /* nativeFun = */ nullptr, guard
->nargs(), guard
->flags());
4792 MOZ_ASSERT(wrappedTarget
->hasJitEntry());
4793 return wrappedTarget
;
4798 // If it is possible to use MCall for this call, update callInfo_ to use
4799 // the correct arguments. Otherwise, update the ArgFormat of callInfo_.
4800 bool WarpCacheIRTranspiler::updateCallInfo(MDefinition
* callee
,
4802 // The transpilation will add various guards to the callee.
4803 // We replace the callee referenced by the CallInfo, so that
4804 // the resulting call instruction depends on these guards.
4805 callInfo_
->setCallee(callee
);
4807 // The transpilation may also add guards to other arguments.
4808 // We replace those arguments in the CallInfo here.
4809 updateArgumentsFromOperands();
4811 switch (flags
.getArgFormat()) {
4812 case CallFlags::Standard
:
4813 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
4815 case CallFlags::Spread
:
4816 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Array
);
4818 case CallFlags::FunCall
:
4819 // Note: We already changed the callee to the target
4820 // function instead of the |call| function.
4821 MOZ_ASSERT(!callInfo_
->constructing());
4822 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
4824 if (callInfo_
->argc() == 0) {
4825 // Special case for fun.call() with no arguments.
4826 auto* undef
= constant(UndefinedValue());
4827 callInfo_
->setThis(undef
);
4829 // The first argument for |call| is the new this value.
4830 callInfo_
->setThis(callInfo_
->getArg(0));
4832 // Shift down all other arguments by removing the first.
4833 callInfo_
->removeArg(0);
4836 case CallFlags::FunApplyArgsObj
:
4837 MOZ_ASSERT(!callInfo_
->constructing());
4838 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
4840 callInfo_
->setArgFormat(CallInfo::ArgFormat::FunApplyArgsObj
);
4842 case CallFlags::FunApplyArray
: {
4843 MDefinition
* argFunc
= callInfo_
->thisArg();
4844 MDefinition
* argThis
= callInfo_
->getArg(0);
4845 callInfo_
->setCallee(argFunc
);
4846 callInfo_
->setThis(argThis
);
4847 callInfo_
->setArgFormat(CallInfo::ArgFormat::Array
);
4850 case CallFlags::FunApplyNullUndefined
:
4851 // Note: We already changed the callee to the target
4852 // function instead of the |apply| function.
4853 MOZ_ASSERT(callInfo_
->argc() == 2);
4854 MOZ_ASSERT(!callInfo_
->constructing());
4855 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
4856 callInfo_
->setThis(callInfo_
->getArg(0));
4857 callInfo_
->getArg(1)->setImplicitlyUsedUnchecked();
4858 callInfo_
->removeArg(1);
4859 callInfo_
->removeArg(0);
4862 MOZ_CRASH("Unsupported arg format");
4867 // Returns true if we are generating a call to CreateThisFromIon and
4868 // must check its return value.
4869 bool WarpCacheIRTranspiler::maybeCreateThis(MDefinition
* callee
,
4870 CallFlags flags
, CallKind kind
) {
4871 MOZ_ASSERT(kind
!= CallKind::DOM
, "DOM functions are not constructors");
4872 MDefinition
* thisArg
= callInfo_
->thisArg();
4874 if (kind
== CallKind::Native
) {
4875 // Native functions keep the is-constructing MagicValue as |this|.
4876 // If one of the arguments uses spread syntax this can be a loop phi with
4878 MOZ_ASSERT(thisArg
->type() == MIRType::MagicIsConstructing
||
4882 MOZ_ASSERT(kind
== CallKind::Scripted
);
4884 if (thisArg
->isNewPlainObject()) {
4885 // We have already updated |this| based on MetaScriptedThisShape. We do
4886 // not need to generate a check.
4889 if (flags
.needsUninitializedThis()) {
4890 MConstant
* uninit
= constant(MagicValue(JS_UNINITIALIZED_LEXICAL
));
4891 thisArg
->setImplicitlyUsedUnchecked();
4892 callInfo_
->setThis(uninit
);
4895 // See the Native case above.
4896 MOZ_ASSERT(thisArg
->type() == MIRType::MagicIsConstructing
||
4899 MDefinition
* newTarget
= callInfo_
->getNewTarget();
4900 auto* createThis
= MCreateThis::New(alloc(), callee
, newTarget
);
4903 thisArg
->setImplicitlyUsedUnchecked();
4904 callInfo_
->setThis(createThis
);
4909 bool WarpCacheIRTranspiler::emitCallFunction(
4910 ObjOperandId calleeId
, Int32OperandId argcId
,
4911 mozilla::Maybe
<ObjOperandId
> thisObjId
, CallFlags flags
, CallKind kind
) {
4912 MDefinition
* callee
= getOperand(calleeId
);
4913 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
4914 // We are transpiling to generate the correct guards. We also
4915 // update the CallInfo to use the correct arguments. Code for the
4916 // inlined function itself will be generated in
4917 // WarpBuilder::buildInlinedCall.
4918 if (!updateCallInfo(callee
, flags
)) {
4921 if (callInfo_
->constructing()) {
4922 MOZ_ASSERT(flags
.isConstructing());
4924 // We call maybeCreateThis to update |this|, but inlined constructors
4925 // never need a VM call. CallIRGenerator::getThisForScripted ensures that
4926 // we don't attach a specialized stub unless we have a template object or
4927 // know that the constructor needs uninitialized this.
4928 MOZ_ALWAYS_FALSE(maybeCreateThis(callee
, flags
, CallKind::Scripted
));
4929 mozilla::DebugOnly
<MDefinition
*> thisArg
= callInfo_
->thisArg();
4930 MOZ_ASSERT(thisArg
->isNewPlainObject() ||
4931 thisArg
->type() == MIRType::MagicUninitializedLexical
);
4934 if (flags
.getArgFormat() == CallFlags::FunCall
) {
4935 callInfo_
->setInliningResumeMode(ResumeMode::InlinedFunCall
);
4937 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::Standard
);
4938 callInfo_
->setInliningResumeMode(ResumeMode::InlinedStandardCall
);
4941 switch (callInfo_
->argFormat()) {
4942 case CallInfo::ArgFormat::Standard
:
4945 MOZ_CRASH("Unsupported arg format");
4951 MDefinition
* argc
= getOperand(argcId
);
4952 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
4953 static_cast<int32_t>(callInfo_
->argc()));
4956 if (!updateCallInfo(callee
, flags
)) {
4960 if (kind
== CallKind::DOM
) {
4961 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::Standard
);
4962 // For DOM calls |this| has a class guard.
4963 MDefinition
* thisObj
= getOperand(*thisObjId
);
4964 callInfo_
->setThis(thisObj
);
4967 WrappedFunction
* wrappedTarget
= maybeCallTarget(callee
, kind
);
4969 bool needsThisCheck
= false;
4970 if (callInfo_
->constructing()) {
4971 MOZ_ASSERT(flags
.isConstructing());
4972 needsThisCheck
= maybeCreateThis(callee
, flags
, kind
);
4973 if (needsThisCheck
) {
4974 wrappedTarget
= nullptr;
4978 switch (callInfo_
->argFormat()) {
4979 case CallInfo::ArgFormat::Standard
: {
4980 MCall
* call
= makeCall(*callInfo_
, needsThisCheck
, wrappedTarget
,
4981 kind
== CallKind::DOM
);
4986 if (flags
.isSameRealm()) {
4987 call
->setNotCrossRealm();
4990 if (call
->isEffectful()) {
4993 return resumeAfter(call
);
4996 MOZ_ASSERT(kind
== CallKind::DOM
);
5001 case CallInfo::ArgFormat::Array
: {
5002 MInstruction
* call
= makeSpreadCall(*callInfo_
, needsThisCheck
,
5003 flags
.isSameRealm(), wrappedTarget
);
5010 return resumeAfter(call
);
5012 case CallInfo::ArgFormat::FunApplyArgsObj
: {
5013 return emitFunApplyArgsObj(wrappedTarget
, flags
);
5016 MOZ_CRASH("unreachable");
5019 bool WarpCacheIRTranspiler::emitFunApplyArgsObj(WrappedFunction
* wrappedTarget
,
5021 MOZ_ASSERT(!callInfo_
->constructing());
5023 MDefinition
* callee
= callInfo_
->thisArg();
5024 MDefinition
* thisArg
= callInfo_
->getArg(0);
5025 MDefinition
* argsObj
= callInfo_
->getArg(1);
5027 MApplyArgsObj
* apply
=
5028 MApplyArgsObj::New(alloc(), wrappedTarget
, callee
, argsObj
, thisArg
);
5030 if (flags
.isSameRealm()) {
5031 apply
->setNotCrossRealm();
5033 if (callInfo_
->ignoresReturnValue()) {
5034 apply
->setIgnoresReturnValue();
5037 addEffectful(apply
);
5040 return resumeAfter(apply
);
5043 #ifndef JS_SIMULATOR
5044 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId
,
5045 Int32OperandId argcId
,
5048 bool ignoresReturnValue
) {
5049 // Instead of ignoresReturnValue we use CallInfo::ignoresReturnValue.
5050 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5054 bool WarpCacheIRTranspiler::emitCallDOMFunction(ObjOperandId calleeId
,
5055 Int32OperandId argcId
,
5056 ObjOperandId thisObjId
,
5058 uint32_t argcFixed
) {
5059 return emitCallFunction(calleeId
, argcId
, mozilla::Some(thisObjId
), flags
,
5063 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId
,
5064 Int32OperandId argcId
,
5067 uint32_t targetOffset
) {
5068 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5072 bool WarpCacheIRTranspiler::emitCallDOMFunction(
5073 ObjOperandId calleeId
, Int32OperandId argcId
, ObjOperandId thisObjId
,
5074 CallFlags flags
, uint32_t argcFixed
, uint32_t targetOffset
) {
5075 return emitCallFunction(calleeId
, argcId
, mozilla::Some(thisObjId
), flags
,
5080 bool WarpCacheIRTranspiler::emitCallScriptedFunction(ObjOperandId calleeId
,
5081 Int32OperandId argcId
,
5083 uint32_t argcFixed
) {
5084 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5085 CallKind::Scripted
);
5088 bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId
,
5089 Int32OperandId argcId
,
5090 uint32_t icScriptOffset
,
5092 uint32_t argcFixed
) {
5093 return emitCallFunction(calleeId
, argcId
, mozilla::Nothing(), flags
,
5094 CallKind::Scripted
);
5097 bool WarpCacheIRTranspiler::emitCallClassHook(ObjOperandId calleeId
,
5098 Int32OperandId argcId
,
5101 uint32_t targetOffset
) {
5102 MDefinition
* callee
= getOperand(calleeId
);
5103 JSNative target
= jsnativeStubField(targetOffset
);
5106 MDefinition
* argc
= getOperand(argcId
);
5107 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5108 static_cast<int32_t>(callInfo_
->argc()));
5111 if (!updateCallInfo(callee
, flags
)) {
5115 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5116 MOZ_ASSERT(flags
.getArgFormat() == CallFlags::ArgFormat::Standard
);
5118 // Callees can be from any realm. If this changes, we should update
5119 // MCallClassHook::maybeCrossRealm.
5120 MOZ_ASSERT(!flags
.isSameRealm());
5122 auto* call
= MCallClassHook::New(alloc(), target
, callInfo_
->argc(),
5123 callInfo_
->constructing());
5128 if (callInfo_
->ignoresReturnValue()) {
5129 call
->setIgnoresReturnValue();
5132 call
->initCallee(callInfo_
->callee());
5133 call
->addArg(0, callInfo_
->thisArg());
5135 for (uint32_t i
= 0; i
< callInfo_
->argc(); i
++) {
5136 call
->addArg(i
+ 1, callInfo_
->getArg(i
));
5139 if (callInfo_
->constructing()) {
5140 call
->addArg(1 + callInfo_
->argc(), callInfo_
->getNewTarget());
5146 return resumeAfter(call
);
5149 bool WarpCacheIRTranspiler::emitCallBoundScriptedFunction(
5150 ObjOperandId calleeId
, ObjOperandId targetId
, Int32OperandId argcId
,
5151 CallFlags flags
, uint32_t numBoundArgs
) {
5152 MDefinition
* callee
= getOperand(calleeId
);
5153 MDefinition
* target
= getOperand(targetId
);
5155 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5156 MOZ_ASSERT(callInfo_
->constructing() == flags
.isConstructing());
5158 callInfo_
->setCallee(target
);
5159 updateArgumentsFromOperands();
5161 WrappedFunction
* wrappedTarget
= maybeCallTarget(target
, CallKind::Scripted
);
5163 bool needsThisCheck
= false;
5164 if (callInfo_
->constructing()) {
5165 callInfo_
->setNewTarget(target
);
5166 needsThisCheck
= maybeCreateThis(target
, flags
, CallKind::Scripted
);
5167 if (needsThisCheck
) {
5168 wrappedTarget
= nullptr;
5171 auto* thisv
= MLoadFixedSlot::New(alloc(), callee
,
5172 BoundFunctionObject::boundThisSlot());
5174 callInfo_
->thisArg()->setImplicitlyUsedUnchecked();
5175 callInfo_
->setThis(thisv
);
5178 bool usingInlineBoundArgs
=
5179 numBoundArgs
<= BoundFunctionObject::MaxInlineBoundArgs
;
5181 MElements
* elements
= nullptr;
5182 if (!usingInlineBoundArgs
) {
5183 auto* boundArgs
= MLoadFixedSlot::New(
5184 alloc(), callee
, BoundFunctionObject::firstInlineBoundArgSlot());
5186 elements
= MElements::New(alloc(), boundArgs
);
5190 auto loadBoundArg
= [&](size_t index
) {
5192 if (usingInlineBoundArgs
) {
5193 size_t slot
= BoundFunctionObject::firstInlineBoundArgSlot() + index
;
5194 arg
= MLoadFixedSlot::New(alloc(), callee
, slot
);
5196 arg
= MLoadElement::New(alloc(), elements
, constant(Int32Value(index
)));
5201 if (!callInfo_
->prependArgs(numBoundArgs
, loadBoundArg
)) {
5205 MCall
* call
= makeCall(*callInfo_
, needsThisCheck
, wrappedTarget
);
5210 if (flags
.isSameRealm()) {
5211 call
->setNotCrossRealm();
5216 return resumeAfter(call
);
5219 bool WarpCacheIRTranspiler::emitBindFunctionResult(
5220 ObjOperandId targetId
, uint32_t argc
, uint32_t templateObjectOffset
) {
5221 MDefinition
* target
= getOperand(targetId
);
5222 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
5224 MOZ_ASSERT(callInfo_
->argc() == argc
);
5226 auto* bound
= MBindFunction::New(alloc(), target
, argc
, templateObj
);
5230 addEffectful(bound
);
5232 for (uint32_t i
= 0; i
< argc
; i
++) {
5233 bound
->initArg(i
, callInfo_
->getArg(i
));
5237 return resumeAfter(bound
);
5240 bool WarpCacheIRTranspiler::emitSpecializedBindFunctionResult(
5241 ObjOperandId targetId
, uint32_t argc
, uint32_t templateObjectOffset
) {
5242 MDefinition
* target
= getOperand(targetId
);
5243 JSObject
* templateObj
= tenuredObjectStubField(templateObjectOffset
);
5245 MOZ_ASSERT(callInfo_
->argc() == argc
);
5247 auto* bound
= MNewBoundFunction::New(alloc(), templateObj
);
5250 size_t numBoundArgs
= argc
> 0 ? argc
- 1 : 0;
5251 MOZ_ASSERT(numBoundArgs
<= BoundFunctionObject::MaxInlineBoundArgs
);
5253 auto initSlot
= [&](size_t slot
, MDefinition
* value
) {
5255 // Assert we can elide the post write barrier. See also the comment in
5256 // WarpBuilder::buildNamedLambdaEnv.
5257 add(MAssertCanElidePostWriteBarrier::New(alloc(), bound
, value
));
5259 addUnchecked(MStoreFixedSlot::NewUnbarriered(alloc(), bound
, slot
, value
));
5262 initSlot(BoundFunctionObject::targetSlot(), target
);
5264 initSlot(BoundFunctionObject::boundThisSlot(), callInfo_
->getArg(0));
5266 for (size_t i
= 0; i
< numBoundArgs
; i
++) {
5267 size_t slot
= BoundFunctionObject::firstInlineBoundArgSlot() + i
;
5268 initSlot(slot
, callInfo_
->getArg(1 + i
));
5275 bool WarpCacheIRTranspiler::emitCallWasmFunction(
5276 ObjOperandId calleeId
, Int32OperandId argcId
, CallFlags flags
,
5277 uint32_t argcFixed
, uint32_t funcExportOffset
, uint32_t instanceOffset
) {
5278 MDefinition
* callee
= getOperand(calleeId
);
5280 MDefinition
* argc
= getOperand(argcId
);
5281 MOZ_ASSERT(argc
->toConstant()->toInt32() ==
5282 static_cast<int32_t>(callInfo_
->argc()));
5284 JSObject
* instanceObject
= tenuredObjectStubField(instanceOffset
);
5285 auto* wasmInstanceObj
= &instanceObject
->as
<WasmInstanceObject
>();
5286 const wasm::FuncExport
* funcExport
= wasmFuncExportField(funcExportOffset
);
5287 const wasm::FuncType
& sig
=
5288 wasmInstanceObj
->instance().metadata().getFuncExportType(*funcExport
);
5290 if (!updateCallInfo(callee
, flags
)) {
5294 static_assert(wasm::MaxArgsForJitInlineCall
<= MaxNumLInstructionOperands
,
5295 "arguments must fit in LIR operands");
5296 MOZ_ASSERT(sig
.args().length() <= wasm::MaxArgsForJitInlineCall
);
5298 MOZ_ASSERT(callInfo_
->argFormat() == CallInfo::ArgFormat::Standard
);
5300 auto* call
= MIonToWasmCall::New(alloc(), wasmInstanceObj
, *funcExport
);
5305 mozilla::Maybe
<MDefinition
*> undefined
;
5306 for (size_t i
= 0; i
< sig
.args().length(); i
++) {
5307 if (!alloc().ensureBallast()) {
5312 if (i
< callInfo_
->argc()) {
5313 arg
= callInfo_
->getArg(i
);
5316 undefined
.emplace(constant(UndefinedValue()));
5318 arg
= convertWasmArg(*undefined
, sig
.args()[i
].kind());
5320 call
->initArg(i
, arg
);
5325 // Add any post-function call conversions that are necessary.
5326 MInstruction
* postConversion
= call
;
5327 const wasm::ValTypeVector
& results
= sig
.results();
5328 MOZ_ASSERT(results
.length() <= 1, "Multi-value returns not supported.");
5329 if (results
.length() == 0) {
5330 // No results to convert.
5332 switch (results
[0].kind()) {
5333 case wasm::ValType::I64
:
5334 // JS expects a BigInt from I64 types.
5335 postConversion
= MInt64ToBigInt::New(alloc(), call
);
5337 // Make non-movable so we can attach a resume point.
5338 postConversion
->setNotMovable();
5340 add(postConversion
);
5343 // No spectre.index_masking of i32 results required, as the generated
5344 // stub takes care of that.
5349 // The resume point has to be attached to the post-conversion instruction
5350 // (if present) instead of to the call. This way, if the call triggers an
5351 // invalidation bailout, we will have the BigInt value on the Baseline stack.
5352 // Potential alternative solution: attach the resume point to the call and
5353 // have bailouts turn the Int64 value into a BigInt, maybe with a recover
5355 pushResult(postConversion
);
5356 return resumeAfterUnchecked(postConversion
);
5359 MDefinition
* WarpCacheIRTranspiler::convertWasmArg(MDefinition
* arg
,
5360 wasm::ValType::Kind kind
) {
5361 // An invariant in this code is that any type conversion operation that has
5362 // externally visible effects, such as invoking valueOf on an object argument,
5363 // must bailout so that we don't have to worry about replaying effects during
5364 // argument conversion.
5365 MInstruction
* conversion
= nullptr;
5367 case wasm::ValType::I32
:
5368 conversion
= MTruncateToInt32::New(alloc(), arg
);
5370 case wasm::ValType::I64
:
5371 conversion
= MToInt64::New(alloc(), arg
);
5373 case wasm::ValType::F32
:
5374 conversion
= MToFloat32::New(alloc(), arg
);
5376 case wasm::ValType::F64
:
5377 conversion
= MToDouble::New(alloc(), arg
);
5379 case wasm::ValType::V128
:
5380 MOZ_CRASH("Unexpected type for Wasm JitEntry");
5381 case wasm::ValType::Ref
:
5382 // Transform the JS representation into an AnyRef representation.
5383 // The resulting type is MIRType::RefOrNull. These cases are all
5385 switch (arg
->type()) {
5386 case MIRType::Object
:
5387 conversion
= MWasmAnyRefFromJSObject::New(alloc(), arg
);
5390 arg
->setImplicitlyUsedUnchecked();
5391 conversion
= MWasmNullConstant::New(alloc());
5394 conversion
= MWasmBoxValue::New(alloc(), arg
);
5404 bool WarpCacheIRTranspiler::emitGuardWasmArg(ValOperandId argId
,
5405 wasm::ValType::Kind kind
) {
5406 MDefinition
* arg
= getOperand(argId
);
5407 MDefinition
* conversion
= convertWasmArg(arg
, kind
);
5409 setOperand(argId
, conversion
);
5413 bool WarpCacheIRTranspiler::emitCallGetterResult(CallKind kind
,
5414 ValOperandId receiverId
,
5415 uint32_t getterOffset
,
5417 uint32_t nargsAndFlagsOffset
) {
5418 MDefinition
* receiver
= getOperand(receiverId
);
5419 MDefinition
* getter
= objectStubField(getterOffset
);
5420 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
5421 // We are transpiling to generate the correct guards. We also update the
5422 // CallInfo to use the correct arguments. Code for the inlined getter
5423 // itself will be generated in WarpBuilder::buildInlinedCall.
5424 callInfo_
->initForGetterCall(getter
, receiver
);
5425 callInfo_
->setInliningResumeMode(ResumeMode::InlinedAccessor
);
5427 // Make sure there's enough room to push the arguments on the stack.
5428 if (!current
->ensureHasSlots(2)) {
5435 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
5436 uint16_t nargs
= nargsAndFlags
>> 16;
5437 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
5438 WrappedFunction
* wrappedTarget
=
5439 maybeWrappedFunction(getter
, kind
, nargs
, flags
);
5441 bool ignoresRval
= loc_
.resultIsPopped();
5442 CallInfo
callInfo(alloc(), /* constructing = */ false, ignoresRval
);
5443 callInfo
.initForGetterCall(getter
, receiver
);
5445 MCall
* call
= makeCall(callInfo
, /* needsThisCheck = */ false, wrappedTarget
);
5451 call
->setNotCrossRealm();
5457 return resumeAfter(call
);
5460 bool WarpCacheIRTranspiler::emitCallScriptedGetterResult(
5461 ValOperandId receiverId
, uint32_t getterOffset
, bool sameRealm
,
5462 uint32_t nargsAndFlagsOffset
) {
5463 return emitCallGetterResult(CallKind::Scripted
, receiverId
, getterOffset
,
5464 sameRealm
, nargsAndFlagsOffset
);
5467 bool WarpCacheIRTranspiler::emitCallInlinedGetterResult(
5468 ValOperandId receiverId
, uint32_t getterOffset
, uint32_t icScriptOffset
,
5469 bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
5470 return emitCallGetterResult(CallKind::Scripted
, receiverId
, getterOffset
,
5471 sameRealm
, nargsAndFlagsOffset
);
5474 bool WarpCacheIRTranspiler::emitCallNativeGetterResult(
5475 ValOperandId receiverId
, uint32_t getterOffset
, bool sameRealm
,
5476 uint32_t nargsAndFlagsOffset
) {
5477 return emitCallGetterResult(CallKind::Native
, receiverId
, getterOffset
,
5478 sameRealm
, nargsAndFlagsOffset
);
5481 bool WarpCacheIRTranspiler::emitCallSetter(CallKind kind
,
5482 ObjOperandId receiverId
,
5483 uint32_t setterOffset
,
5484 ValOperandId rhsId
, bool sameRealm
,
5485 uint32_t nargsAndFlagsOffset
) {
5486 MDefinition
* receiver
= getOperand(receiverId
);
5487 MDefinition
* setter
= objectStubField(setterOffset
);
5488 MDefinition
* rhs
= getOperand(rhsId
);
5489 if (kind
== CallKind::Scripted
&& callInfo_
&& callInfo_
->isInlined()) {
5490 // We are transpiling to generate the correct guards. We also update the
5491 // CallInfo to use the correct arguments. Code for the inlined setter
5492 // itself will be generated in WarpBuilder::buildInlinedCall.
5493 callInfo_
->initForSetterCall(setter
, receiver
, rhs
);
5494 callInfo_
->setInliningResumeMode(ResumeMode::InlinedAccessor
);
5496 // Make sure there's enough room to push the arguments on the stack.
5497 if (!current
->ensureHasSlots(3)) {
5504 uint32_t nargsAndFlags
= uint32StubField(nargsAndFlagsOffset
);
5505 uint16_t nargs
= nargsAndFlags
>> 16;
5506 FunctionFlags flags
= FunctionFlags(uint16_t(nargsAndFlags
));
5507 WrappedFunction
* wrappedTarget
=
5508 maybeWrappedFunction(setter
, kind
, nargs
, flags
);
5510 CallInfo
callInfo(alloc(), /* constructing = */ false,
5511 /* ignoresReturnValue = */ true);
5512 callInfo
.initForSetterCall(setter
, receiver
, rhs
);
5514 MCall
* call
= makeCall(callInfo
, /* needsThisCheck = */ false, wrappedTarget
);
5520 call
->setNotCrossRealm();
5524 return resumeAfter(call
);
5527 bool WarpCacheIRTranspiler::emitCallScriptedSetter(
5528 ObjOperandId receiverId
, uint32_t setterOffset
, ValOperandId rhsId
,
5529 bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
5530 return emitCallSetter(CallKind::Scripted
, receiverId
, setterOffset
, rhsId
,
5531 sameRealm
, nargsAndFlagsOffset
);
5534 bool WarpCacheIRTranspiler::emitCallInlinedSetter(
5535 ObjOperandId receiverId
, uint32_t setterOffset
, ValOperandId rhsId
,
5536 uint32_t icScriptOffset
, bool sameRealm
, uint32_t nargsAndFlagsOffset
) {
5537 return emitCallSetter(CallKind::Scripted
, receiverId
, setterOffset
, rhsId
,
5538 sameRealm
, nargsAndFlagsOffset
);
5541 bool WarpCacheIRTranspiler::emitCallNativeSetter(ObjOperandId receiverId
,
5542 uint32_t setterOffset
,
5545 uint32_t nargsAndFlagsOffset
) {
5546 return emitCallSetter(CallKind::Native
, receiverId
, setterOffset
, rhsId
,
5547 sameRealm
, nargsAndFlagsOffset
);
5550 bool WarpCacheIRTranspiler::emitMetaScriptedThisShape(
5551 uint32_t thisShapeOffset
) {
5552 SharedShape
* shape
= &shapeStubField(thisShapeOffset
)->asShared();
5553 MOZ_ASSERT(shape
->getObjectClass() == &PlainObject::class_
);
5555 MConstant
* shapeConst
= MConstant::NewShape(alloc(), shape
);
5558 // TODO: support pre-tenuring.
5559 gc::Heap heap
= gc::Heap::Default
;
5561 uint32_t numFixedSlots
= shape
->numFixedSlots();
5562 uint32_t numDynamicSlots
= NativeObject::calculateDynamicSlots(shape
);
5563 gc::AllocKind kind
= gc::GetGCObjectKind(numFixedSlots
);
5564 MOZ_ASSERT(gc::CanChangeToBackgroundAllocKind(kind
, &PlainObject::class_
));
5565 kind
= gc::ForegroundToBackgroundAllocKind(kind
);
5567 auto* createThis
= MNewPlainObject::New(alloc(), shapeConst
, numFixedSlots
,
5568 numDynamicSlots
, kind
, heap
);
5571 callInfo_
->thisArg()->setImplicitlyUsedUnchecked();
5572 callInfo_
->setThis(createThis
);
5576 bool WarpCacheIRTranspiler::emitReturnFromIC() { return true; }
5578 bool WarpCacheIRTranspiler::emitBailout() {
5579 auto* bail
= MBail::New(alloc());
5585 bool WarpCacheIRTranspiler::emitAssertPropertyLookup(ObjOperandId objId
,
5587 uint32_t slotOffset
) {
5588 // We currently only emit checks in baseline.
5592 bool WarpCacheIRTranspiler::emitAssertRecoveredOnBailoutResult(
5593 ValOperandId valId
, bool mustBeRecovered
) {
5594 MDefinition
* val
= getOperand(valId
);
5596 // Don't assert for recovered instructions when recovering is disabled.
5597 if (JitOptions
.disableRecoverIns
) {
5598 pushResult(constant(UndefinedValue()));
5602 if (JitOptions
.checkRangeAnalysis
) {
5603 // If we are checking the range of all instructions, then the guards
5604 // inserted by Range Analysis prevent the use of recover instruction. Thus,
5605 // we just disable these checks.
5606 pushResult(constant(UndefinedValue()));
5610 auto* assert = MAssertRecoveredOnBailout::New(alloc(), val
, mustBeRecovered
);
5611 addEffectfulUnsafe(assert);
5612 current
->push(assert);
5614 // Create an instruction sequence which implies that the argument of the
5615 // assertRecoveredOnBailout function would be encoded at least in one
5617 auto* nop
= MNop::New(alloc());
5620 auto* resumePoint
= MResumePoint::New(
5621 alloc(), nop
->block(), loc_
.toRawBytecode(), ResumeMode::ResumeAfter
);
5625 nop
->setResumePoint(resumePoint
);
5627 auto* encode
= MEncodeSnapshot::New(alloc());
5628 addEffectfulUnsafe(encode
);
5632 pushResult(constant(UndefinedValue()));
5636 bool WarpCacheIRTranspiler::emitGuardNoAllocationMetadataBuilder(
5637 uint32_t builderAddrOffset
) {
5638 // This is a no-op because we discard all JIT code when set an allocation
5639 // metadata callback.
5643 bool WarpCacheIRTranspiler::emitNewPlainObjectResult(uint32_t numFixedSlots
,
5644 uint32_t numDynamicSlots
,
5645 gc::AllocKind allocKind
,
5646 uint32_t shapeOffset
,
5647 uint32_t siteOffset
) {
5648 Shape
* shape
= shapeStubField(shapeOffset
);
5649 gc::Heap heap
= allocSiteInitialHeapField(siteOffset
);
5651 auto* shapeConstant
= MConstant::NewShape(alloc(), shape
);
5654 auto* obj
= MNewPlainObject::New(alloc(), shapeConstant
, numFixedSlots
,
5655 numDynamicSlots
, allocKind
, heap
);
5662 bool WarpCacheIRTranspiler::emitNewArrayObjectResult(uint32_t length
,
5663 uint32_t shapeOffset
,
5664 uint32_t siteOffset
) {
5665 Shape
* shape
= shapeStubField(shapeOffset
);
5666 gc::Heap heap
= allocSiteInitialHeapField(siteOffset
);
5668 auto* shapeConstant
= MConstant::NewShape(alloc(), shape
);
5671 auto* obj
= MNewArrayObject::New(alloc(), shapeConstant
, length
, heap
);
5678 bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId
,
5679 ObjOperandId calleeId
,
5680 CompletionKind kind
,
5681 uint32_t calleeNargs
) {
5682 MDefinition
* iter
= getOperand(iterId
);
5683 MDefinition
* callee
= getOperand(calleeId
);
5685 WrappedFunction
* wrappedTarget
= maybeCallTarget(callee
, CallKind::Scripted
);
5686 MOZ_ASSERT(wrappedTarget
);
5687 MOZ_ASSERT(wrappedTarget
->nargs() == calleeNargs
);
5688 MOZ_ASSERT(wrappedTarget
->hasJitEntry());
5690 bool constructing
= false;
5691 bool ignoresRval
= false;
5692 bool needsThisCheck
= false;
5693 bool isDOMCall
= false;
5694 CallInfo
callInfo(alloc(), constructing
, ignoresRval
);
5695 callInfo
.initForCloseIter(iter
, callee
);
5696 MCall
* call
= makeCall(callInfo
, needsThisCheck
, wrappedTarget
, isDOMCall
);
5701 if (kind
== CompletionKind::Throw
) {
5702 return resumeAfter(call
);
5705 // If we bail out here, after the call but before the CheckIsObj, we
5706 // can't simply resume in the baseline interpreter. If we resume
5707 // after the CloseIter, we won't check the return value. If we
5708 // resume at the CloseIter, we will call the |return| method twice.
5709 // Instead, we use a special resume mode that captures the
5710 // intermediate value, and then checks that it's an object while
5712 current
->push(call
);
5713 MResumePoint
* resumePoint
=
5714 MResumePoint::New(alloc(), current
, loc_
.toRawBytecode(),
5715 ResumeMode::ResumeAfterCheckIsObject
);
5719 call
->setResumePoint(resumePoint
);
5722 MCheckIsObj
* check
= MCheckIsObj::New(
5723 alloc(), call
, uint8_t(CheckIsObjectKind::IteratorReturn
));
5729 bool WarpCacheIRTranspiler::emitGuardGlobalGeneration(
5730 uint32_t expectedOffset
, uint32_t generationAddrOffset
) {
5731 uint32_t expected
= uint32StubField(expectedOffset
);
5732 const void* generationAddr
= rawPointerField(generationAddrOffset
);
5734 auto guard
= MGuardGlobalGeneration::New(alloc(), expected
, generationAddr
);
5740 #ifdef FUZZING_JS_FUZZILLI
5741 bool WarpCacheIRTranspiler::emitFuzzilliHashResult(ValOperandId valId
) {
5742 MDefinition
* input
= getOperand(valId
);
5744 auto* hash
= MFuzzilliHash::New(alloc(), input
);
5747 auto* store
= MFuzzilliHashStore::New(alloc(), hash
);
5748 addEffectful(store
);
5749 pushResult(constant(UndefinedValue()));
5751 return resumeAfter(store
);
5755 static void MaybeSetImplicitlyUsed(uint32_t numInstructionIdsBefore
,
5756 MDefinition
* input
) {
5757 // When building MIR from bytecode, for each MDefinition that's an operand to
5758 // a bytecode instruction, we must either add an SSA use or set the
5759 // ImplicitlyUsed flag on that definition. The ImplicitlyUsed flag prevents
5760 // the backend from optimizing-out values that will be used by Baseline after
5763 // WarpBuilder uses WarpPoppedValueUseChecker to assert this invariant in
5766 // This function is responsible for setting the ImplicitlyUsed flag for an
5767 // input when using the transpiler. It looks at the input's most recent use
5768 // and if that's an instruction that was added while transpiling this JSOp
5769 // (based on the MIR instruction id) we don't set the ImplicitlyUsed flag.
5771 if (input
->isImplicitlyUsed()) {
5776 // If the most recent use of 'input' is an instruction we just added, there is
5778 MDefinition
* inputUse
= input
->maybeMostRecentlyAddedDefUse();
5779 if (inputUse
&& inputUse
->id() >= numInstructionIdsBefore
) {
5783 // The transpiler didn't add a use for 'input'.
5784 input
->setImplicitlyUsed();
5787 bool jit::TranspileCacheIRToMIR(WarpBuilder
* builder
, BytecodeLocation loc
,
5788 const WarpCacheIR
* cacheIRSnapshot
,
5789 std::initializer_list
<MDefinition
*> inputs
,
5790 CallInfo
* maybeCallInfo
) {
5791 uint32_t numInstructionIdsBefore
=
5792 builder
->mirGen().graph().getNumInstructionIds();
5794 WarpCacheIRTranspiler
transpiler(builder
, loc
, maybeCallInfo
,
5796 if (!transpiler
.transpile(inputs
)) {
5800 for (MDefinition
* input
: inputs
) {
5801 MaybeSetImplicitlyUsed(numInstructionIdsBefore
, input
);
5804 if (maybeCallInfo
) {
5805 auto maybeSetFlag
= [numInstructionIdsBefore
](MDefinition
* def
) {
5806 MaybeSetImplicitlyUsed(numInstructionIdsBefore
, def
);
5808 maybeCallInfo
->forEachCallOperand(maybeSetFlag
);