Bug 1618198 part 29 - Implement JSOp::Pos. r=iain
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 26 Mar 2020 09:41:50 +0000
changeset 520543 58c3533fd95a962487b976a4a129dc6e67f7596a
parent 520542 1bedd35b63bf70e6f4b5db06356fcf62ec6b8328
child 520544 9911fb33115594e5bd957b67f1d8b0219efaae9f
push id37253
push usernerli@mozilla.com
push dateThu, 26 Mar 2020 21:36:52 +0000
treeherdermozilla-central@c644dd16e2cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersiain
bugs1618198
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1618198 part 29 - Implement JSOp::Pos. r=iain Note that JSOp::Pos used to be very hot because it was used to implement the increment and decrement operators, but for BigInt these were changed to use JSOp::ToNumeric. JSOp::Pos is now only used for the +x operator. IonBuilder compiles +x as x * 1, but that results in complexity elsewhere (ICs and CacheIR inlining for example). It's simpler to follow JSOp::ToNumeric/MToNumeric with an MToNumber instruction. The patch adds the most basic implementation of this (still reasonably fast because it checks for numbers inline). This also nicely matches what Baseline does. Differential Revision: https://phabricator.services.mozilla.com/D68192
js/src/jit/CodeGenerator.cpp
js/src/jit/Lowering.cpp
js/src/jit/MIR.h
js/src/jit/WarpBuilder.cpp
js/src/jit/WarpBuilder.h
js/src/jit/shared/LIR-shared.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4391,16 +4391,29 @@ void CodeGenerator::visitToNumeric(LToNu
     MOZ_ASSERT(checks == 0);
     masm.bind(&done);
     masm.moveValue(operand, output);
   }
 
   masm.bind(ool->rejoin());
 }
 
+void CodeGenerator::visitToNumber(LToNumber* lir) {
+  ValueOperand operand = ToValue(lir, LToNumber::Input);
+  ValueOperand output = ToOutValue(lir);
+
+  using Fn = bool (*)(JSContext*, HandleValue, MutableHandleValue);
+  OutOfLineCode* ool =
+      oolCallVM<Fn, DoToNumber>(lir, ArgList(operand), StoreValueTo(output));
+
+  masm.branchTestNumber(Assembler::NotEqual, operand, ool->entry());
+  masm.moveValue(operand, output);
+  masm.bind(ool->rejoin());
+}
+
 void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) {
   ValueOperand operand = ToValue(lir, LTypeBarrierV::Input);
   Register unboxScratch = ToTempRegisterOrInvalid(lir->unboxTemp());
   Register objScratch = ToTempRegisterOrInvalid(lir->objTemp());
 
   // guardObjectType may zero the payload/Value register on speculative paths
   // (we should have a defineReuseInput allocation in this case).
   Register spectreRegToZero = operand.payloadOrValueReg();
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2165,16 +2165,23 @@ void LIRGenerator::visitToIntegerInt32(M
 
 void LIRGenerator::visitToNumeric(MToNumeric* ins) {
   MOZ_ASSERT(ins->input()->type() == MIRType::Value);
   LToNumeric* lir = new (alloc()) LToNumeric(useBoxAtStart(ins->input()));
   defineBox(lir, ins);
   assignSafepoint(lir, ins);
 }
 
+void LIRGenerator::visitToNumber(MToNumber* ins) {
+  MOZ_ASSERT(ins->input()->type() == MIRType::Value);
+  LToNumber* lir = new (alloc()) LToNumber(useBoxAtStart(ins->input()));
+  defineBox(lir, ins);
+  assignSafepoint(lir, ins);
+}
+
 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
   MDefinition* opd = truncate->input();
 
   switch (opd->type()) {
     case MIRType::Value: {
       LValueToInt32* lir = new (alloc()) LValueToInt32(
           useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
       assignSnapshot(lir, Bailout_NonPrimitiveInput);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4062,16 +4062,31 @@ class MToNumeric : public MUnaryInstruct
   bool congruentTo(const MDefinition* ins) const override {
     return congruentIfOperandsEqual(ins);
   }
   MDefinition* foldsTo(TempAllocator& alloc) override;
 
   ALLOW_CLONE(MToNumeric)
 };
 
+// This corresponds to JS::ToNumber(value).
+class MToNumber : public MUnaryInstruction, public BoxInputsPolicy::Data {
+  explicit MToNumber(MDefinition* arg) : MUnaryInstruction(classOpcode, arg) {
+    // Note: this returns a Value instead of double to prevent unnecessary int32
+    // to double conversions.
+    setResultType(MIRType::Value);
+  }
+
+ public:
+  INSTRUCTION_HEADER(ToNumber)
+  TRIVIAL_NEW_WRAPPERS
+
+  ALLOW_CLONE(MToNumber)
+};
+
 // Applies ECMA's ToNumber on a primitive (either typed or untyped) and expects
 // the result to be precisely representable as an Int32, otherwise bails.
 //
 // If the input is not primitive at runtime, a bailout occurs. If the input
 // cannot be converted to an int32 without loss (i.e. 5.5 or undefined) then a
 // bailout occurs.
 class MToNumberInt32 : public MUnaryInstruction, public ToInt32Policy::Data {
   bool canBeNegativeZero_;
--- a/js/src/jit/WarpBuilder.cpp
+++ b/js/src/jit/WarpBuilder.cpp
@@ -660,16 +660,26 @@ bool WarpBuilder::build_SetArg(BytecodeL
 bool WarpBuilder::build_ToNumeric(BytecodeLocation loc) {
   MDefinition* value = current->pop();
   MToNumeric* ins = MToNumeric::New(alloc(), value, /* types = */ nullptr);
   current->add(ins);
   current->push(ins);
   return resumeAfter(ins, loc);
 }
 
+bool WarpBuilder::build_Pos(BytecodeLocation loc) {
+  // TODO: MToNumber is the most basic implementation. Optimize it for known
+  // numbers at least.
+  MDefinition* value = current->pop();
+  MToNumber* ins = MToNumber::New(alloc(), value);
+  current->add(ins);
+  current->push(ins);
+  return resumeAfter(ins, loc);
+}
+
 bool WarpBuilder::buildUnaryOp(BytecodeLocation loc) {
   MDefinition* value = current->pop();
   MInstruction* ins = MUnaryCache::New(alloc(), value);
   current->add(ins);
   current->push(ins);
   return resumeAfter(ins, loc);
 }
 
--- a/js/src/jit/WarpBuilder.h
+++ b/js/src/jit/WarpBuilder.h
@@ -52,16 +52,17 @@ namespace jit {
   _(Pick)                    \
   _(Unpick)                  \
   _(GetLocal)                \
   _(SetLocal)                \
   _(InitLexical)             \
   _(GetArg)                  \
   _(SetArg)                  \
   _(ToNumeric)               \
+  _(Pos)                     \
   _(Inc)                     \
   _(Dec)                     \
   _(Neg)                     \
   _(BitNot)                  \
   _(Add)                     \
   _(Sub)                     \
   _(Mul)                     \
   _(Div)                     \
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -5538,16 +5538,30 @@ class LToNumeric : public LInstructionHe
     setBoxOperand(Input, input);
   }
 
   static const size_t Input = 0;
 
   const MToNumeric* mir() const { return mir_->toToNumeric(); }
 };
 
+class LToNumber : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 0> {
+ public:
+  LIR_HEADER(ToNumber)
+
+  explicit LToNumber(const LBoxAllocation& input)
+      : LInstructionHelper(classOpcode) {
+    setBoxOperand(Input, input);
+  }
+
+  static const size_t Input = 0;
+
+  const MToNumber* mir() const { return mir_->toToNumber(); }
+};
+
 // Guard that a value is in a TypeSet.
 class LTypeBarrierV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 2> {
  public:
   LIR_HEADER(TypeBarrierV)
 
   LTypeBarrierV(const LBoxAllocation& input, const LDefinition& unboxTemp,
                 const LDefinition& objTemp)
       : LInstructionHelper(classOpcode) {