Bug 1536702 - Part 2: Add MacroAssembler support to allocate and initialise BigInt values. r=jandem
authorAndré Bargull <andre.bargull@gmail.com>
Mon, 21 Oct 2019 11:26:23 +0000
changeset 498355 71a2bfc0cf2b433186cc97854eb158adca9693f4
parent 498354 80bd01919ed4d7f244ca47dfb9c1b0879836381e
child 498356 1398fdc0f7e9ec2b693412eb636b74bed0ffdc9e
push id36717
push usernbeleuzu@mozilla.com
push dateMon, 21 Oct 2019 21:51:55 +0000
treeherdermozilla-central@563f437f24b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1536702
milestone71.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 1536702 - Part 2: Add MacroAssembler support to allocate and initialise BigInt values. r=jandem Differential Revision: https://phabricator.services.mozilla.com/D48339
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/arm/MacroAssembler-arm.h
js/src/jit/arm64/MacroAssembler-arm64.h
js/src/jit/x64/MacroAssembler-x64.h
js/src/vm/BigIntType.h
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -798,16 +798,21 @@ void MacroAssembler::newGCString(Registe
 }
 
 void MacroAssembler::newGCFatInlineString(Register result, Register temp,
                                           Label* fail, bool attemptNursery) {
   allocateString(result, temp, js::gc::AllocKind::FAT_INLINE_STRING,
                  attemptNursery ? gc::DefaultHeap : gc::TenuredHeap, fail);
 }
 
+void MacroAssembler::newGCBigInt(Register result, Register temp, Label* fail) {
+  checkAllocatorState(fail);
+  freeListAllocate(result, temp, gc::AllocKind::BIGINT, fail);
+}
+
 void MacroAssembler::copySlotsFromTemplate(
     Register obj, const NativeTemplateObject& templateObj, uint32_t start,
     uint32_t end) {
   uint32_t nfixed = Min(templateObj.numFixedSlots(), end);
   for (unsigned i = start; i < nfixed; i++) {
     // Template objects are not exposed to script and therefore immutable.
     // However, regexp template objects are sometimes used directly (when
     // the cloning is not observable), and therefore we can end up with a
@@ -1494,16 +1499,66 @@ void MacroAssembler::loadBigInt64(Regist
 
   branchTest32(Assembler::Zero, Address(bigInt, BigInt::offsetOfFlags()),
                Imm32(BigInt::signBitMask()), &done);
   neg64(dest);
 
   bind(&done);
 }
 
+void MacroAssembler::initializeBigInt64(Scalar::Type type, Register bigInt,
+                                        Register64 val) {
+  MOZ_ASSERT(Scalar::isBigIntType(type));
+
+  store32(Imm32(0), Address(bigInt, BigInt::offsetOfFlags()));
+
+  Label done, nonZero;
+  branch64(Assembler::NotEqual, val, Imm64(0), &nonZero);
+  {
+    store32(Imm32(0), Address(bigInt, BigInt::offsetOfLength()));
+    jump(&done);
+  }
+  bind(&nonZero);
+
+  if (type == Scalar::BigInt64) {
+    // Set the sign-bit for negative values and then continue with the two's
+    // complement.
+    Label isPositive;
+    branch64(Assembler::GreaterThan, val, Imm64(0), &isPositive);
+    {
+      store32(Imm32(BigInt::signBitMask()),
+              Address(bigInt, BigInt::offsetOfFlags()));
+      neg64(val);
+    }
+    bind(&isPositive);
+  }
+
+  store32(Imm32(1), Address(bigInt, BigInt::offsetOfLength()));
+
+  static_assert(sizeof(BigInt::Digit) == sizeof(uintptr_t),
+                "BigInt Digit size matches uintptr_t, so there's a single "
+                "store on 64-bit and up to two stores on 32-bit");
+
+#ifndef JS_PUNBOX64
+  Label singleDigit;
+  branchTest32(Assembler::Zero, val.high, val.high, &singleDigit);
+  store32(Imm32(2), Address(bigInt, BigInt::offsetOfLength()));
+  bind(&singleDigit);
+
+  // We can perform a single store64 on 32-bit platforms, because inline
+  // storage can store at least two 32-bit integers.
+  static_assert(BigInt::inlineDigitsLength() >= 2,
+                "BigInt inline storage can store at least two digits");
+#endif
+
+  store64(val, Address(bigInt, js::BigInt::offsetOfInlineDigits()));
+
+  bind(&done);
+}
+
 void MacroAssembler::typeOfObject(Register obj, Register scratch, Label* slow,
                                   Label* isObject, Label* isCallable,
                                   Label* isUndefined) {
   loadObjClassUnsafe(obj, scratch);
 
   // Proxies can emulate undefined and have complex isCallable behavior.
   branchTestClassIsProxy(true, scratch, slow);
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -2544,16 +2544,21 @@ class MacroAssembler : public MacroAssem
    */
   void addToCharPtr(Register chars, Register index, CharEncoding encoding);
 
   /**
    * Load the first [u]int64 value from |bigInt| into |dest|.
    */
   void loadBigInt64(Register bigInt, Register64 dest);
 
+  /**
+   * Initialize a BigInt from |dest|. Clobbers |val|!
+   */
+  void initializeBigInt64(Scalar::Type type, Register bigInt, Register64 val);
+
   void loadJSContext(Register dest);
 
   void switchToRealm(Register realm);
   void switchToRealm(const void* realm, Register scratch);
   void switchToObjectRealm(Register obj, Register scratch);
   void switchToBaselineFrameRealm(Register scratch);
   void switchToWasmTlsRealm(Register scratch1, Register scratch2);
   void debugAssertContextRealm(const void* realm, Register scratch);
@@ -2862,16 +2867,18 @@ class MacroAssembler : public MacroAssem
                            TypedArrayObject* templateObj,
                            TypedArrayLength lengthKind);
 
   void newGCString(Register result, Register temp, Label* fail,
                    bool attemptNursery);
   void newGCFatInlineString(Register result, Register temp, Label* fail,
                             bool attemptNursery);
 
+  void newGCBigInt(Register result, Register temp, Label* fail);
+
   // Compares two strings for equality based on the JSOP.
   // This checks for identical pointers, atoms and length and fails for
   // everything else.
   void compareStrings(JSOp op, Register left, Register right, Register result,
                       Label* fail);
 
   // Result of the typeof operation. Falls back to slow-path for proxies.
   void typeOfObject(Register objReg, Register scratch, Label* slow,
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1122,16 +1122,20 @@ class MacroAssemblerARMCompat : public M
 
   void load32(const Address& address, Register dest);
   void load32(const BaseIndex& address, Register dest);
   void load32(AbsoluteAddress address, Register dest);
   void load64(const Address& address, Register64 dest) {
     load32(LowWord(address), dest.low);
     load32(HighWord(address), dest.high);
   }
+  void load64(const BaseIndex& address, Register64 dest) {
+    load32(LowWord(address), dest.low);
+    load32(HighWord(address), dest.high);
+  }
 
   void loadPtr(const Address& address, Register dest);
   void loadPtr(const BaseIndex& src, Register dest);
   void loadPtr(AbsoluteAddress address, Register dest);
   void loadPtr(wasm::SymbolicAddress address, Register dest);
 
   void loadPrivate(const Address& address, Register dest);
 
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1198,16 +1198,19 @@ class MacroAssemblerCompat : public vixl
     vixl::UseScratchRegisterScope temps(this);
     const ARMRegister scratch64 = temps.AcquireX();
     movePtr(ImmWord((uintptr_t)address.addr), scratch64.asUnsized());
     ldr(ARMRegister(dest, 32), MemOperand(scratch64));
   }
   void load64(const Address& address, Register64 dest) {
     loadPtr(address, dest.reg);
   }
+  void load64(const BaseIndex& address, Register64 dest) {
+    loadPtr(address, dest.reg);
+  }
 
   void load8SignExtend(const Address& address, Register dest) {
     Ldrsb(ARMRegister(dest, 32), toMemOperand(address));
   }
   void load8SignExtend(const BaseIndex& src, Register dest) {
     doBaseIndex(ARMRegister(dest, 32), src, vixl::LDRSB_w);
   }
 
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -579,16 +579,19 @@ class MacroAssemblerX64 : public MacroAs
       ScratchRegisterScope scratch(asMasm());
       mov(ImmPtr(address.addr), scratch);
       load32(Address(scratch, 0x0), dest);
     }
   }
   void load64(const Address& address, Register64 dest) {
     movq(Operand(address), dest.reg);
   }
+  void load64(const BaseIndex& address, Register64 dest) {
+    movq(Operand(address), dest.reg);
+  }
   template <typename T>
   void storePtr(ImmWord imm, T address) {
     if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
       movq(Imm32((int32_t)imm.value), Operand(address));
     } else {
       ScratchRegisterScope scratch(asMasm());
       mov(imm, scratch);
       movq(scratch, Operand(address));
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -385,16 +385,18 @@ class BigInt final
   using Base::offsetOfLength;
 
   static size_t offsetOfInlineDigits() {
     return offsetof(BigInt, inlineDigits_);
   }
 
   static size_t offsetOfHeapDigits() { return offsetof(BigInt, heapDigits_); }
 
+  static constexpr size_t inlineDigitsLength() { return InlineDigitsLength; }
+
   static constexpr size_t nonInlineDigitsLengthMask() {
     static_assert(mozilla::IsPowerOfTwo(InlineDigitsLength),
                   "inline digits length is a power of two");
     return ~(InlineDigitsLength - 1) & ~InlineDigitsLength;
   }
 
   static constexpr size_t signBitMask() { return SignBit; }
 };