diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 82575d1505f1..0741d8fa5e4e 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -86,10 +86,10 @@ class OperandId { static const uint16_t InvalidId = UINT16_MAX; uint16_t id_; - OperandId() : id_(InvalidId) {} explicit OperandId(uint16_t id) : id_(id) {} public: + OperandId() : id_(InvalidId) {} uint16_t id() const { return id_; } bool valid() const { return id_ != InvalidId; } }; @@ -406,7 +406,8 @@ enum class ArgumentKind : uint8_t { Arg0, Arg1, Arg2, - Arg3 + Arg3, + NumKinds }; // This function calculates the index of an argument based on the call flags. diff --git a/js/src/jit/WarpCacheIRTranspiler.cpp b/js/src/jit/WarpCacheIRTranspiler.cpp index 013f243b8349..8c4ac27927f7 100644 --- a/js/src/jit/WarpCacheIRTranspiler.cpp +++ b/js/src/jit/WarpCacheIRTranspiler.cpp @@ -47,6 +47,19 @@ class MOZ_RAII WarpCacheIRTranspiler : public WarpBuilderShared { CallInfo* callInfo_; + // Array mapping call arguments to OperandId. + using ArgumentKindArray = + mozilla::EnumeratedArray; + ArgumentKindArray argumentOperandIds_; + + void setArgumentId(ArgumentKind kind, OperandId id) { + MOZ_ASSERT(kind != ArgumentKind::Callee); + MOZ_ASSERT(!argumentOperandIds_[kind].valid()); + argumentOperandIds_[kind] = id; + } + + void updateArgumentsFromOperands(); + #ifdef DEBUG // Used to assert that there is only one effectful instruction // per stub. And that this instruction has a resume point. @@ -3430,6 +3443,46 @@ bool WarpCacheIRTranspiler::emitLoadWrapperTarget(ObjOperandId objId, return defineOperand(resultId, ins); } +// When we transpile a call, we may generate guards for some +// arguments. To make sure the call instruction depends on those +// guards, when the transpiler creates an operand for an argument, we +// register the OperandId of that argument in argumentIds_. (See +// emitLoadArgumentSlot.) Before generating the call, we update the +// CallInfo to use the appropriate value from operands_. +// Note: The callee is an explicit argument to the call op, and is +// tracked separately. +void WarpCacheIRTranspiler::updateArgumentsFromOperands() { + for (uint32_t i = 0; i < uint32_t(ArgumentKind::NumKinds); i++) { + ArgumentKind kind = ArgumentKind(i); + OperandId id = argumentOperandIds_[kind]; + if (id.valid()) { + switch (kind) { + case ArgumentKind::This: + callInfo_->setThis(getOperand(id)); + break; + case ArgumentKind::NewTarget: + callInfo_->setNewTarget(getOperand(id)); + break; + case ArgumentKind::Arg0: + callInfo_->setArg(0, getOperand(id)); + break; + case ArgumentKind::Arg1: + callInfo_->setArg(1, getOperand(id)); + break; + case ArgumentKind::Arg2: + callInfo_->setArg(2, getOperand(id)); + break; + case ArgumentKind::Arg3: + callInfo_->setArg(3, getOperand(id)); + break; + case ArgumentKind::Callee: + case ArgumentKind::NumKinds: + MOZ_CRASH("Unexpected argument kind"); + } + } + } +} + bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId, uint32_t slotIndex) { // Reverse of GetIndexOfArgument. @@ -3442,6 +3495,7 @@ bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId, // NewTarget (optional) if (callInfo_->constructing()) { if (slotIndex == 0) { + setArgumentId(ArgumentKind::NewTarget, resultId); return defineOperand(resultId, callInfo_->getNewTarget()); } @@ -3451,11 +3505,15 @@ bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId, // Args.. if (slotIndex < callInfo_->argc()) { uint32_t arg = callInfo_->argc() - 1 - slotIndex; + ArgumentKind kind = ArgumentKind(uint32_t(ArgumentKind::Arg0) + arg); + MOZ_ASSERT(kind < ArgumentKind::NumKinds); + setArgumentId(kind, resultId); return defineOperand(resultId, callInfo_->getArg(arg)); } // ThisValue if (slotIndex == callInfo_->argc()) { + setArgumentId(ArgumentKind::This, resultId); return defineOperand(resultId, callInfo_->thisArg()); } @@ -3544,6 +3602,10 @@ bool WarpCacheIRTranspiler::updateCallInfo(MDefinition* callee, // the resulting call instruction depends on these guards. callInfo_->setCallee(callee); + // The transpilation may also add guards to other arguments. + // We replace those arguments in the CallInfo here. + updateArgumentsFromOperands(); + switch (flags.getArgFormat()) { case CallFlags::Standard: MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); @@ -3552,7 +3614,7 @@ bool WarpCacheIRTranspiler::updateCallInfo(MDefinition* callee, MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Array); break; case CallFlags::FunCall: - // Note: setCallee above already changed the callee to the target + // Note: We already changed the callee to the target // function instead of the |call| function. MOZ_ASSERT(!callInfo_->constructing()); MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard);