bug 1366287 - Part 2.0: Use GMP integers to represent BigInt values. r=jwalden

Also link to libgmp and initialize it with custom memory allocation
functions.

--HG--
extra : rebase_source : 3aab0578a0b9e61c4aea5c7b7d1d572316f63b46
This commit is contained in:
Robin Templeton 2018-05-11 19:42:48 -07:00
parent 798233c7bc
commit f6e5382e6a
5 changed files with 83 additions and 9 deletions

View File

@ -1335,6 +1335,11 @@ if CONFIG['MOZ_SYSTEM_ICU']:
'unicode/utypes.h',
]
if CONFIG['ENABLE_BIGINT']:
system_headers += [
'gmp.h'
]
if CONFIG['MOZ_WAYLAND']:
system_headers += [
'wayland-client.h',

View File

@ -34,6 +34,11 @@ if CONFIG['ENABLE_INTL_API']:
'icu',
]
if CONFIG['ENABLE_BIGINT']:
OS_LIBS += [
'gmp',
]
USE_LIBS += [
'nspr',
'zlib',

View File

@ -9,43 +9,82 @@
#include "mozilla/FloatingPoint.h"
#include "mozilla/HashFunctions.h"
#include <gmp.h>
#include <math.h>
#include "jsapi.h"
#include "gc/Allocator.h"
#include "gc/Tracer.h"
#include "js/Utility.h"
#include "vm/JSContext.h"
#include "vm/SelfHosting.h"
using namespace js;
// The following functions are wrappers for use with
// mp_set_memory_functions. GMP passes extra arguments to the realloc
// and free functions not needed by the JS allocation interface.
// js_malloc has the signature expected for GMP's malloc function, so no
// wrapper is required.
static void*
js_mp_realloc(void* ptr, size_t old_size, size_t new_size)
{
return js_realloc(ptr, new_size);
}
static void
js_mp_free(void* ptr, size_t size)
{
return js_free(ptr);
}
void
BigInt::init()
{
mp_set_memory_functions(js_malloc, js_mp_realloc, js_mp_free);
}
BigInt*
BigInt::create(JSContext* cx)
{
BigInt* x = Allocate<BigInt>(cx);
if (!x)
return nullptr;
mpz_init(x->num_); // to zero
return x;
}
BigInt*
BigInt::copy(JSContext* cx, HandleBigInt x)
{
BigInt* bi = create(cx);
BigInt* bi = Allocate<BigInt>(cx);
if (!bi)
return nullptr;
mpz_init_set(bi->num_, x->num_);
return bi;
}
JSLinearString*
BigInt::toString(JSContext* cx, BigInt* x)
{
return nullptr;
// We need two extra chars for '\0' and potentially '-'.
size_t strSize = mpz_sizeinbase(x->num_, 10) + 2;
UniqueChars str(static_cast<char*>(js_malloc(strSize)));
if (!str) {
ReportOutOfMemory(cx);
return nullptr;
}
mpz_get_str(str.get(), 10, x->num_);
return NewStringCopyZ<CanGC>(cx, str.get());
}
void
BigInt::finalize(js::FreeOp* fop)
{
return;
mpz_clear(num_);
}
JSAtom*
@ -60,24 +99,35 @@ js::BigIntToAtom(JSContext* cx, BigInt* bi)
bool
BigInt::toBoolean()
{
return false;
return mpz_sgn(num_) != 0;
}
js::HashNumber
BigInt::hash()
{
return 0;
const mp_limb_t* limbs = mpz_limbs_read(num_);
size_t limbCount = mpz_size(num_);
uint32_t hash = mozilla::HashBytes(limbs, limbCount * sizeof(mp_limb_t));
hash = mozilla::AddToHash(hash, mpz_sgn(num_));
return hash;
}
size_t
BigInt::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return 0;
// Use the total number of limbs allocated when calculating the size
// (_mp_alloc), not the number of limbs currently in use (_mp_size).
// See the Info node `(gmp)Integer Internals` for details.
mpz_srcptr n = static_cast<mpz_srcptr>(num_);
return sizeof(*n) + sizeof(mp_limb_t) * n->_mp_alloc;
}
JS::ubi::Node::Size
JS::ubi::Concrete<BigInt>::size(mozilla::MallocSizeOf mallocSizeOf) const
{
MOZ_ASSERT(get().isTenured());
return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
BigInt& bi = get();
MOZ_ASSERT(bi.isTenured());
size_t size = js::gc::Arena::thingSize(bi.asTenured().getAllocKind());
size += bi.sizeOfExcludingThis(mallocSizeOf);
return size;
}

View File

@ -7,6 +7,8 @@
#ifndef vm_BigIntType_h
#define vm_BigIntType_h
#include <gmp.h>
#include "gc/Barrier.h"
#include "gc/GC.h"
#include "gc/Heap.h"
@ -23,7 +25,10 @@ class BigInt final : public js::gc::TenuredCell
private:
// The minimum allocation size is currently 16 bytes (see
// SortedArenaList in gc/ArenaList.h).
uint8_t unused_[js::gc::MinCellSize];
union {
mpz_t num_;
uint8_t unused_[js::gc::MinCellSize];
};
public:
// Allocate and initialize a BigInt value
@ -42,6 +47,8 @@ class BigInt final : public js::gc::TenuredCell
static JSLinearString* toString(JSContext* cx, BigInt* x);
bool toBoolean();
static void init();
static BigInt* copy(JSContext* cx, Handle<BigInt*> x);
};

View File

@ -25,6 +25,9 @@
#include "unicode/uclean.h"
#include "unicode/utypes.h"
#endif // ENABLE_INTL_API
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/DateTime.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
@ -134,6 +137,10 @@ JS::detail::InitWithFailureDiagnostic(bool isDebugBuild)
RETURN_IF_FAIL(js::jit::SimulatorProcess::initialize());
#endif
#ifdef ENABLE_BIGINT
JS::BigInt::init();
#endif
libraryInitState = InitState::Running;
return nullptr;
}