Bug 1366287 - Part 1.0: Define a new BigInt primitive type, with a GDB prettyprinter, Rust binding support, and a new out-of-line TraceKind. (Disabled by default, implemented only incompletely, currently passing --enable-bigint will disable JITs, will be flipped on Eventually once every sub-aspect is in place, Don't Have A Cow, Man.) r=jwalden, r=Ms2ger, r=sfink

--HG--
extra : rebase_source : aa13bd94bc6157ff8134894e3ba2e7a2b53e28d9
This commit is contained in:
Robin Templeton 2018-05-24 11:26:09 -07:00
parent dd94407236
commit de41c625dd
54 changed files with 718 additions and 29 deletions

View File

@ -102,13 +102,29 @@ def disable_export_js(value):
die('Setting %s is deprecated, use %s instead.',
value.format('DISABLE_EXPORT_JS'), suggestion)
# Experimental BigInt support
# =======================================================
js_option('--enable-bigint',
default=False,
help='Enable BigInt')
@depends('--enable-bigint')
def enable_bigint(value):
if value:
return True
set_config('ENABLE_BIGINT', enable_bigint)
set_define('ENABLE_BIGINT', enable_bigint)
# JIT support
# =======================================================
@depends(target)
def ion_default(target):
@depends(target, '--enable-bigint')
def ion_default(target, enable_bigint):
if enable_bigint:
return False
if target.cpu in ('x86', 'x86_64', 'arm', 'aarch64', 'mips32', 'mips64'):
return True
return False
js_option('--enable-ion',
default=ion_default,

View File

@ -122,7 +122,7 @@ ToBoolean(HandleValue v)
if (v.isSymbol())
return true;
/* The slow path handles strings and objects. */
/* The slow path handles strings, BigInts and objects. */
return js::ToBooleanSlow(v);
}

View File

@ -50,6 +50,7 @@
// Expand the given macro D for each public GC pointer.
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
D(JS::Symbol*) \
IF_BIGINT(D(JS::BigInt*),) \
D(JSAtom*) \
D(JSFunction*) \
D(JSObject*) \
@ -127,6 +128,9 @@ struct GCPointerPolicy
}
};
template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
#ifdef ENABLE_BIGINT
template <> struct GCPolicy<JS::BigInt*> : public GCPointerPolicy<JS::BigInt*> {};
#endif
template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};

View File

@ -629,6 +629,7 @@ struct UnusedGCThingSizes
macro(Other, GCHeapUnused, objectGroup) \
macro(Other, GCHeapUnused, string) \
macro(Other, GCHeapUnused, symbol) \
IF_BIGINT(macro(Other, GCHeapUnused, bigInt),) \
macro(Other, GCHeapUnused, jitcode) \
macro(Other, GCHeapUnused, scope) \
macro(Other, GCHeapUnused, regExpShared)
@ -648,6 +649,9 @@ struct UnusedGCThingSizes
case JS::TraceKind::Object: object += n; break;
case JS::TraceKind::String: string += n; break;
case JS::TraceKind::Symbol: symbol += n; break;
#ifdef ENABLE_BIGINT
case JS::TraceKind::BigInt: bigInt += n; break;
#endif
case JS::TraceKind::Script: script += n; break;
case JS::TraceKind::Shape: shape += n; break;
case JS::TraceKind::BaseShape: baseShape += n; break;
@ -689,6 +693,8 @@ struct ZoneStats
{
#define FOR_EACH_SIZE(macro) \
macro(Other, GCHeapUsed, symbolsGCHeap) \
IF_BIGINT(macro(Other, GCHeapUsed, bigIntsGCHeap),) \
IF_BIGINT(macro(Other, MallocHeap, bigIntsMallocHeap),) \
macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \
macro(Other, GCHeapUsed, lazyScriptsGCHeap) \
macro(Other, MallocHeap, lazyScriptsMallocHeap) \

View File

@ -61,7 +61,10 @@ enum class TraceKind
JitCode = 0x1F,
LazyScript = 0x2F,
Scope = 0x3F,
RegExpShared = 0x4F
RegExpShared = 0x4F,
#ifdef ENABLE_BIGINT
BigInt = 0x5F
#endif
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
@ -97,6 +100,7 @@ struct MapTypeToTraceKind {
D(Shape, js::Shape, true) \
D(String, JSString, false) \
D(Symbol, JS::Symbol, false) \
IF_BIGINT(D(BigInt, JS::BigInt, false),) \
D(RegExpShared, js::RegExpShared, true)
// Map from all public types to their trace kind.

View File

@ -151,6 +151,9 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); }
virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); }
virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); }
#ifdef ENABLE_BIGINT
virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); }
#endif
virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
virtual void onShapeEdge(js::Shape** shapep) {
onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
@ -243,6 +246,9 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); }
void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); }
void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); }
#ifdef ENABLE_BIGINT
void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); }
#endif
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }

View File

@ -41,6 +41,9 @@ namespace JS {
typedef unsigned char Latin1Char;
class Symbol;
#ifdef ENABLE_BIGINT
class BigInt;
#endif
union Value;
class Realm;
struct Runtime;
@ -57,6 +60,9 @@ typedef Handle<JSObject*> HandleObject;
typedef Handle<JSScript*> HandleScript;
typedef Handle<JSString*> HandleString;
typedef Handle<JS::Symbol*> HandleSymbol;
#ifdef ENABLE_BIGINT
typedef Handle<JS::BigInt*> HandleBigInt;
#endif
typedef Handle<Value> HandleValue;
typedef MutableHandle<JSFunction*> MutableHandleFunction;
@ -65,6 +71,9 @@ typedef MutableHandle<JSObject*> MutableHandleObject;
typedef MutableHandle<JSScript*> MutableHandleScript;
typedef MutableHandle<JSString*> MutableHandleString;
typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
#ifdef ENABLE_BIGINT
typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
#endif
typedef MutableHandle<Value> MutableHandleValue;
typedef Rooted<JSObject*> RootedObject;
@ -72,6 +81,9 @@ typedef Rooted<JSFunction*> RootedFunction;
typedef Rooted<JSScript*> RootedScript;
typedef Rooted<JSString*> RootedString;
typedef Rooted<JS::Symbol*> RootedSymbol;
#ifdef ENABLE_BIGINT
typedef Rooted<JS::BigInt*> RootedBigInt;
#endif
typedef Rooted<jsid> RootedId;
typedef Rooted<JS::Value> RootedValue;
@ -81,8 +93,17 @@ typedef PersistentRooted<JSObject*> PersistentRootedObject;
typedef PersistentRooted<JSScript*> PersistentRootedScript;
typedef PersistentRooted<JSString*> PersistentRootedString;
typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
#ifdef ENABLE_BIGINT
typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
#endif
typedef PersistentRooted<Value> PersistentRootedValue;
} // namespace JS
#ifdef ENABLE_BIGINT
#define IF_BIGINT(x, y) x
#else
#define IF_BIGINT(x, y) y
#endif
#endif /* js_TypeDecls_h */

View File

@ -1056,6 +1056,24 @@ class JS_PUBLIC_API(Concrete<JS::Symbol>) : TracerConcrete<JS::Symbol> {
static const char16_t concreteTypeName[];
};
#ifdef ENABLE_BIGINT
template<>
class JS_PUBLIC_API(Concrete<JS::BigInt>) : TracerConcrete<JS::BigInt> {
protected:
explicit Concrete(JS::BigInt* ptr) : TracerConcrete(ptr) {}
public:
static void construct(void* storage, JS::BigInt* ptr) {
new (storage) Concrete(ptr);
}
Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
const char16_t* typeName() const override { return concreteTypeName; }
static const char16_t concreteTypeName[];
};
#endif
template<>
class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
protected:

View File

@ -59,6 +59,9 @@ enum JSValueType : uint8_t
JSVAL_TYPE_STRING = 0x06,
JSVAL_TYPE_SYMBOL = 0x07,
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
#ifdef ENABLE_BIGINT
JSVAL_TYPE_BIGINT = 0x09,
#endif
JSVAL_TYPE_OBJECT = 0x0c,
/* These never appear in a jsval; they are only provided as an out-of-band value. */
@ -82,6 +85,9 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING,
JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING,
#ifdef ENABLE_BIGINT
JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
#endif
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT
} JS_ENUM_FOOTER(JSValueTag);
@ -101,6 +107,9 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING,
JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING,
#ifdef ENABLE_BIGINT
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
#endif
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT
} JS_ENUM_FOOTER(JSValueTag);
@ -118,6 +127,9 @@ enum JSValueShiftedTag : uint64_t
JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT),
#ifdef ENABLE_BIGINT
JSVAL_SHIFTED_TAG_BIGINT = (((uint64_t)JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
#endif
JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT)
};
@ -261,7 +273,7 @@ CanonicalizeNaN(double d)
*
* - JS::Value has setX() and isX() members for X in
*
* { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
* { Int32, Double, String, Symbol, BigInt, Boolean, Undefined, Null, Object, Magic }
*
* JS::Value also contains toX() for each of the non-singleton types.
*
@ -343,6 +355,9 @@ union MOZ_NON_PARAM alignas(8) Value
uint32_t boo_; // Don't use |bool| -- it must be four bytes.
JSString* str_;
JS::Symbol* sym_;
#ifdef ENABLE_BIGINT
JS::BigInt* bi_;
#endif
JSObject* obj_;
js::gc::Cell* cell_;
void* ptr_;
@ -454,6 +469,13 @@ union MOZ_NON_PARAM alignas(8) Value
asBits_ = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
}
#ifdef ENABLE_BIGINT
void setBigInt(JS::BigInt* bi) {
MOZ_ASSERT(js::gc::IsCellPointerValid(bi));
asBits_ = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
}
#endif
void setObject(JSObject& obj) {
MOZ_ASSERT(js::gc::IsCellPointerValid(&obj));
@ -620,6 +642,12 @@ union MOZ_NON_PARAM alignas(8) Value
return toTag() == JSVAL_TAG_SYMBOL;
}
#ifdef ENABLE_BIGINT
bool isBigInt() const {
return toTag() == JSVAL_TAG_BIGINT;
}
#endif
bool isObject() const {
#if defined(JS_NUNBOX32)
return toTag() == JSVAL_TAG_OBJECT;
@ -681,6 +709,10 @@ union MOZ_NON_PARAM alignas(8) Value
"Value type tags must correspond with JS::TraceKinds.");
if (MOZ_UNLIKELY(isPrivateGCThing()))
return JS::GCThingTraceKind(toGCThing());
#ifdef ENABLE_BIGINT
if (MOZ_UNLIKELY(isBigInt()))
return JS::TraceKind::BigInt;
#endif
return JS::TraceKind(toTag() & 0x03);
}
@ -745,6 +777,17 @@ union MOZ_NON_PARAM alignas(8) Value
#endif
}
#ifdef ENABLE_BIGINT
JS::BigInt* toBigInt() const {
MOZ_ASSERT(isBigInt());
#if defined(JS_NUNBOX32)
return s_.payload_.bi_;
#elif defined(JS_PUNBOX64)
return reinterpret_cast<JS::BigInt*>(asBits_ ^ JSVAL_SHIFTED_TAG_BIGINT);
#endif
}
#endif
JSObject& toObject() const {
MOZ_ASSERT(isObject());
#if defined(JS_NUNBOX32)
@ -862,6 +905,10 @@ union MOZ_NON_PARAM alignas(8) Value
"Private GC thing Values must not be strings. Make a StringValue instead.");
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Symbol,
"Private GC thing Values must not be symbols. Make a SymbolValue instead.");
#ifdef ENABLE_BIGINT
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
"Private GC thing Values must not be BigInts. Make a BigIntValue instead.");
#endif
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
"Private GC thing Values must not be objects. Make an ObjectValue instead.");
@ -987,6 +1034,16 @@ SymbolValue(JS::Symbol* sym)
return v;
}
#ifdef ENABLE_BIGINT
static inline Value
BigIntValue(JS::BigInt* bi)
{
Value v;
v.setBigInt(bi);
return v;
}
#endif
static inline Value
BooleanValue(bool boo)
{
@ -1242,6 +1299,9 @@ class WrappedPtrOperations<JS::Value, Wrapper>
bool isDouble() const { return value().isDouble(); }
bool isString() const { return value().isString(); }
bool isSymbol() const { return value().isSymbol(); }
#ifdef ENABLE_BIGINT
bool isBigInt() const { return value().isBigInt(); }
#endif
bool isObject() const { return value().isObject(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
@ -1257,6 +1317,9 @@ class WrappedPtrOperations<JS::Value, Wrapper>
double toDouble() const { return value().toDouble(); }
JSString* toString() const { return value().toString(); }
JS::Symbol* toSymbol() const { return value().toSymbol(); }
#ifdef ENABLE_BIGINT
JS::BigInt* toBigInt() const { return value().toBigInt(); }
#endif
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
@ -1294,6 +1357,9 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperati
bool setNumber(double d) { return value().setNumber(d); }
void setString(JSString* str) { this->value().setString(str); }
void setSymbol(JS::Symbol* sym) { this->value().setSymbol(sym); }
#ifdef ENABLE_BIGINT
void setBigInt(JS::BigInt* bi) { this->value().setBigInt(bi); }
#endif
void setObject(JSObject& obj) { this->value().setObject(obj); }
void setObjectOrNull(JSObject* arg) { this->value().setObjectOrNull(arg); }
void setPrivate(void* ptr) { this->value().setPrivate(ptr); }
@ -1322,6 +1388,9 @@ class HeapBase<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrap
void setMagic(JSWhyMagic why) { setBarriered(JS::MagicValue(why)); }
void setString(JSString* str) { setBarriered(JS::StringValue(str)); }
void setSymbol(JS::Symbol* sym) { setBarriered(JS::SymbolValue(sym)); }
#ifdef ENABLE_BIGINT
void setBigInt(JS::BigInt* bi) { setBarriered(JS::BigIntValue(bi)); }
#endif
void setObject(JSObject& obj) { setBarriered(JS::ObjectValue(obj)); }
void setPrivateGCThing(js::gc::Cell* cell) { setBarriered(JS::PrivateGCThingValue(cell)); }
@ -1378,6 +1447,13 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args)
MOZ_ASSERT(gc::IsCellPointerValid(sym));
return f(sym, mozilla::Forward<Args>(args)...);
}
#ifdef ENABLE_BIGINT
if (val.isBigInt()) {
JS::BigInt* bi = val.toBigInt();
MOZ_ASSERT(gc::IsCellPointerValid(bi));
return f(bi, mozilla::Forward<Args>(args)...);
}
#endif
if (MOZ_UNLIKELY(val.isPrivateGCThing())) {
MOZ_ASSERT(gc::IsCellPointerValid(val.toGCThing()));
return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);

View File

@ -39,6 +39,7 @@ doctest = false
debugmozjs = ['mozjs_sys/debugmozjs']
promises = ['mozjs_sys/promises']
nonzero = []
bigint = ['mozjs_sys/bigint']
[dependencies.mozjs_sys]
path = "../src"

View File

@ -73,6 +73,10 @@ fn build_jsapi_bindings() {
.clang_arg("-DJS_DEBUG");
}
if cfg!(feature = "bigint") {
builder = builder.clang_arg("-DENABLE_BIGINT");
}
let include_dir = get_mozjs_include_dir();
let include_dir = include_dir.to_str()
.expect("Path to mozjs include dir should be utf-8");
@ -99,6 +103,10 @@ fn build_jsapi_bindings() {
builder = builder.whitelist_function(func);
}
if cfg!(feature = "bigint") {
builder = builder.whitelist_type("JS::BigInt");
}
for ty in OPAQUE_TYPES {
builder = builder.opaque_type(ty);
}

View File

@ -25,6 +25,8 @@ enum ValueTag {
UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32),
SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
#[cfg(feature = "bigint")]
BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32),
BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32),
NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32),
@ -41,6 +43,8 @@ enum ValueTag {
UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32),
STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32),
SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32),
#[cfg(feature = "bigint")]
BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32),
BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32),
MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32),
NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32),
@ -57,6 +61,8 @@ enum ValueShiftedTag {
UNDEFINED = ((ValueTag::UNDEFINED as u64) << JSVAL_TAG_SHIFT),
STRING = ((ValueTag::STRING as u64) << JSVAL_TAG_SHIFT),
SYMBOL = ((ValueTag::SYMBOL as u64) << JSVAL_TAG_SHIFT),
#[cfg(feature = "bigint")]
BIGINT = ((ValueTag::BIGINT as u64) << JSVAL_TAG_SHIFT),
BOOLEAN = ((ValueTag::BOOLEAN as u64) << JSVAL_TAG_SHIFT),
MAGIC = ((ValueTag::MAGIC as u64) << JSVAL_TAG_SHIFT),
NULL = ((ValueTag::NULL as u64) << JSVAL_TAG_SHIFT),
@ -187,6 +193,23 @@ pub fn PrivateValue(o: *const c_void) -> JS::Value {
BuildJSVal(ValueTag::PRIVATE, ptrBits)
}
#[inline(always)]
#[cfg(feature = "bigint")]
#[cfg(target_pointer_width = "64")]
pub fn BigIntValue(b: &JS::BigInt) -> JS::Value {
let bits = b as *const JS::BigInt as usize as u64;
assert!((bits >> JSVAL_TAG_SHIFT) == 0);
BuildJSVal(ValueTag::BIGINT, bits)
}
#[inline(always)]
#[cfg(target_pointer_width = "32")]
#[inline(always)]
pub fn BigIntValue(s: &JS::BigInt) -> JS::Value {
let bits = s as *const JS::BigInt as usize as u64;
BuildJSVal(ValueTag::BIGINT, bits)
}
impl JS::Value {
#[inline(always)]
unsafe fn asBits(&self) -> u64 {
@ -363,6 +386,24 @@ impl JS::Value {
}
}
#[inline(always)]
#[cfg(feature = "bigint")]
#[cfg(target_pointer_width = "64")]
pub fn is_bigint(&self) -> bool {
unsafe {
(self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64
}
}
#[inline(always)]
#[cfg(feature = "bigint")]
#[cfg(target_pointer_width = "32")]
pub fn is_bigint(&self) -> bool {
unsafe {
(self.asBits() >> 32) == ValueTag::BIGINT as u64
}
}
#[inline(always)]
#[cfg(target_pointer_width = "64")]
pub fn to_boolean(&self) -> bool {

View File

@ -306,6 +306,12 @@ impl RootKind for *mut JS::Symbol {
fn rootKind() -> JS::RootKind { JS::RootKind::Symbol }
}
#[cfg(feature = "bigint")]
impl RootKind for *mut JS::BigInt {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::BigInt }
}
impl RootKind for *mut JSScript {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::Script }

View File

@ -8,6 +8,7 @@ build = "build.rs"
[features]
debugmozjs = []
promises = []
bigint = []
[lib]
name = "mozjs_sys"

View File

@ -47,6 +47,9 @@ class PropertyResult;
enum class SymbolCode: uint32_t;
#ifdef ENABLE_BIGINT
class BigInt;
#endif
} // namespace JS
// Do the importing.
@ -112,6 +115,9 @@ using JS::RootedObject;
using JS::RootedScript;
using JS::RootedString;
using JS::RootedSymbol;
#ifdef ENABLE_BIGINT
using JS::RootedBigInt;
#endif
using JS::RootedValue;
using JS::PersistentRooted;
@ -121,6 +127,9 @@ using JS::PersistentRootedObject;
using JS::PersistentRootedScript;
using JS::PersistentRootedString;
using JS::PersistentRootedSymbol;
#ifdef ENABLE_BIGINT
using JS::PersistentRootedBigInt;
#endif
using JS::PersistentRootedValue;
using JS::Handle;
@ -130,6 +139,9 @@ using JS::HandleObject;
using JS::HandleScript;
using JS::HandleString;
using JS::HandleSymbol;
#ifdef ENABLE_BIGINT
using JS::HandleBigInt;
#endif
using JS::HandleValue;
using JS::MutableHandle;
@ -139,6 +151,9 @@ using JS::MutableHandleObject;
using JS::MutableHandleScript;
using JS::MutableHandleString;
using JS::MutableHandleSymbol;
#ifdef ENABLE_BIGINT
using JS::MutableHandleBigInt;
#endif
using JS::MutableHandleValue;
using JS::NullHandleValue;
@ -157,6 +172,9 @@ using JS::Zone;
using JS::Symbol;
using JS::SymbolCode;
#ifdef ENABLE_BIGINT
using JS::BigInt;
#endif
} /* namespace js */
#endif /* NamespaceImports_h */

View File

@ -16,11 +16,9 @@ fn main() {
env::set_var("MAKEFLAGS", format!("-j{}", num_cpus::get()));
env::set_current_dir(&js_src).unwrap();
let variant = if cfg!(feature = "debugmozjs") {
"plaindebug"
} else {
"plain"
};
let variant = format!("{}{}",
if cfg!(feature = "bigint") { "bigint" } else { "plain" },
if cfg!(feature = "debugmozjs") { "debug" } else { "" });
let python = env::var("PYTHON").unwrap_or("python2.7".into());
let mut cmd = Command::new(&python);
@ -36,7 +34,7 @@ fn main() {
// already exists but wasn't created by autospider.
"--dep",
"--objdir", &out_dir,
variant])
&variant])
.env("SOURCE", &js_src)
.env("PWD", &js_src)
.stdout(Stdio::inherit())
@ -54,6 +52,10 @@ fn main() {
println!("cargo:rustc-link-search=native={}/dist/bin", out_dir);
println!("cargo:rustc-link-lib=nspr4");
if cfg!(feature = "bigint") {
println!("cargo:rustc-link-lib=gmp");
}
if target.contains("windows") {
println!("cargo:rustc-link-lib=winmm");
if target.contains("gnu") {

View File

@ -1272,6 +1272,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleNativeObject obj, u
* with those as well.
*/
break;
} else if (IF_BIGINT(elem.isBigInt(), false)) {
// ToString(bigint) doesn't access bigint.toString or
// anything like that, so it can't mutate the array we're
// walking through, so it *could* be handled here. We don't
// do so yet for reasons of initial-implementation economy.
break;
} else {
MOZ_ASSERT(elem.isMagic(JS_ELEMENTS_HOLE) || elem.isNullOrUndefined());
}

View File

@ -15,6 +15,9 @@
#include "jit/InlinableNatives.h"
#include "util/StringBuffer.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/GlobalObject.h"
#include "vm/JSAtom.h"
#include "vm/JSContext.h"
@ -164,6 +167,10 @@ js::ToBooleanSlow(HandleValue v)
{
if (v.isString())
return v.toString()->length() != 0;
#ifdef ENABLE_BIGINT
if (v.isBigInt())
return v.toBigInt()->toBoolean();
#endif
MOZ_ASSERT(v.isObject());
return !EmulatesUndefined(&v.toObject());

View File

@ -587,6 +587,13 @@ Str(JSContext* cx, const Value& v, StringifyContext* scx)
return NumberValueToStringBuffer(cx, v, scx->sb);
}
#ifdef ENABLE_BIGINT
if (v.isBigInt()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE);
return false;
}
#endif
/* Step 10. */
MOZ_ASSERT(v.isObject());
RootedObject obj(cx, &v.toObject());

View File

@ -57,7 +57,8 @@ HashableValue::setValue(JSContext* cx, HandleValue v)
}
MOZ_ASSERT(value.isUndefined() || value.isNull() || value.isBoolean() || value.isNumber() ||
value.isString() || value.isSymbol() || value.isObject());
value.isString() || value.isSymbol() || value.isObject() ||
IF_BIGINT(value.isBigInt(), false));
return true;
}
@ -77,6 +78,10 @@ HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
return v.toString()->asAtom().hash();
if (v.isSymbol())
return v.toSymbol()->hash();
#ifdef ENABLE_BIGINT
if (v.isBigInt())
return v.toBigInt()->hash();
#endif
if (v.isObject())
return hcs.scramble(v.asRawBits());
@ -96,12 +101,24 @@ HashableValue::operator==(const HashableValue& other) const
// Two HashableValues are equal if they have equal bits.
bool b = (value.asRawBits() == other.value.asRawBits());
#ifdef ENABLE_BIGINT
// BigInt values are considered equal if they represent the same
// integer. This test should use a comparison function that doesn't
// require a JSContext once one is defined in the BigInt class.
if (!b && (value.isBigInt() && other.value.isBigInt())) {
JSContext* cx = TlsContext.get();
RootedValue valueRoot(cx, value);
RootedValue otherRoot(cx, other.value);
SameValue(cx, valueRoot, otherRoot, &b);
}
#endif
#ifdef DEBUG
bool same;
JSContext* cx = TlsContext.get();
RootedValue valueRoot(cx, value);
RootedValue otherRoot(cx, other.value);
MOZ_ASSERT(SameValue(nullptr, valueRoot, otherRoot, &same));
MOZ_ASSERT(SameValue(cx, valueRoot, otherRoot, &same));
MOZ_ASSERT(same == b);
#endif
return b;

View File

@ -0,0 +1,7 @@
{
"configure-args": "--enable-bigint",
"optimize": true,
"env": {
"JSTESTS_EXTRA_ARGS": "--jitflags=all"
}
}

View File

@ -0,0 +1,7 @@
{
"configure-args": "--enable-bigint",
"debug": true,
"env": {
"JSTESTS_EXTRA_ARGS": "--jitflags=debug"
}
}

View File

@ -64,6 +64,7 @@ namespace gc {
D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom, true, false) \
D(ATOM, String, js::NormalAtom, js::NormalAtom, true, false) \
D(SYMBOL, Symbol, JS::Symbol, JS::Symbol, true, false) \
IF_BIGINT(D(BIGINT, BigInt, JS::BigInt, JS::BigInt, true, false),) \
D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode, false, false) \
D(SCOPE, Scope, js::Scope, js::Scope, true, false) \
D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared, true, false)

View File

@ -190,7 +190,10 @@ AtomMarkingRuntime::markAtomValue(JSContext* cx, const Value& value)
markAtom(cx, value.toSymbol());
return;
}
MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing());
MOZ_ASSERT_IF(value.isGCThing(),
value.isObject() ||
value.isPrivateGCThing() ||
IF_BIGINT(value.isBigInt(), false));
}
void
@ -272,7 +275,10 @@ AtomMarkingRuntime::valueIsMarked(Zone* zone, const Value& value)
if (value.isSymbol())
return atomIsMarked(zone, value.toSymbol());
MOZ_ASSERT_IF(value.isGCThing(), value.isObject() || value.isPrivateGCThing());
MOZ_ASSERT_IF(value.isGCThing(),
value.isObject() ||
value.isPrivateGCThing() ||
IF_BIGINT(value.isBigInt(), false));
return true;
}

View File

@ -8,6 +8,9 @@
#define gc_DeletePolicy_h
#include "js/TracingAPI.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
namespace js {
namespace gc {
@ -26,6 +29,9 @@ struct ClearEdgesTracer : public JS::CallbackTracer
void onObjectEdge(JSObject** objp) override;
void onStringEdge(JSString** strp) override;
void onSymbolEdge(JS::Symbol** symp) override;
#ifdef ENABLE_BIGINT
void onBigIntEdge(JS::BigInt** bip) override;
#endif
void onScriptEdge(JSScript** scriptp) override;
void onShapeEdge(js::Shape** shapep) override;
void onObjectGroupEdge(js::ObjectGroup** groupp) override;

View File

@ -224,6 +224,9 @@
#include "js/SliceBudget.h"
#include "proxy/DeadObjectProxy.h"
#include "util/Windows.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/Debugger.h"
#include "vm/GeckoProfiler.h"
#include "vm/JSAtom.h"
@ -495,7 +498,10 @@ static const FinalizePhase BackgroundFinalizePhases[] = {
AllocKind::EXTERNAL_STRING,
AllocKind::FAT_INLINE_ATOM,
AllocKind::ATOM,
AllocKind::SYMBOL
AllocKind::SYMBOL,
#ifdef ENABLE_BIGINT
AllocKind::BIGINT
#endif
}
},
{
@ -8436,6 +8442,10 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
ptr = checkedCast(&v.toObject(), JS::TraceKind::Object);
else if (v.isSymbol())
ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol);
#ifdef ENABLE_BIGINT
else if (v.isBigInt())
ptr = checkedCast(v.toBigInt(), JS::TraceKind::BigInt);
#endif
else if (v.isPrivateGCThing())
ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind());
else
@ -9138,6 +9148,9 @@ js::gc::ClearEdgesTracer::clearEdge(S** thingp)
void js::gc::ClearEdgesTracer::onObjectEdge(JSObject** objp) { clearEdge(objp); }
void js::gc::ClearEdgesTracer::onStringEdge(JSString** strp) { clearEdge(strp); }
void js::gc::ClearEdgesTracer::onSymbolEdge(JS::Symbol** symp) { clearEdge(symp); }
#ifdef ENABLE_BIGINT
void js::gc::ClearEdgesTracer::onBigIntEdge(JS::BigInt** bip) { clearEdge(bip); }
#endif
void js::gc::ClearEdgesTracer::onScriptEdge(JSScript** scriptp) { clearEdge(scriptp); }
void js::gc::ClearEdgesTracer::onShapeEdge(js::Shape** shapep) { clearEdge(shapep); }
void js::gc::ClearEdgesTracer::onObjectGroupEdge(js::ObjectGroup** groupp) { clearEdge(groupp); }

View File

@ -11,6 +11,10 @@
#include "gc/RelocationOverlay.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
namespace js {
namespace gc {

View File

@ -21,6 +21,9 @@
#include "js/SliceBudget.h"
#include "vm/ArgumentsObject.h"
#include "vm/ArrayObject.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/RegExpObject.h"
@ -894,6 +897,9 @@ js::GCMarker::markAndTraceChildren(T* thing)
namespace js {
template <> void GCMarker::traverse(BaseShape* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(JS::Symbol* thing) { markAndTraceChildren(thing); }
#ifdef ENABLE_BIGINT
template <> void GCMarker::traverse(JS::BigInt* thing) { markAndTraceChildren(thing); }
#endif
template <> void GCMarker::traverse(RegExpShared* thing) { markAndTraceChildren(thing); }
} // namespace js
@ -1550,6 +1556,14 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
traverseEdge(group, static_cast<JSObject*>(fun));
}
#ifdef ENABLE_BIGINT
void
JS::BigInt::traceChildren(JSTracer* trc)
{
return;
}
#endif
struct TraverseObjectFunctor
{
template <typename T>
@ -1694,7 +1708,8 @@ ObjectDenseElementsMayBeMarkable(NativeObject* nobj)
return true;
static const uint32_t flagMask =
TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT;
TYPE_FLAG_STRING | TYPE_FLAG_SYMBOL | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT |
IF_BIGINT(TYPE_FLAG_BIGINT, 0);
bool mayBeMarkable = typeSet->hasAnyFlag(flagMask) || typeSet->getObjectCount() != 0;
#ifdef DEBUG
@ -1808,7 +1823,13 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
}
} else if (v.isSymbol()) {
traverseEdge(obj, v.toSymbol());
} else if (v.isPrivateGCThing()) {
}
#ifdef ENABLE_BIGINT
else if (v.isBigInt()) {
traverseEdge(obj, v.toBigInt());
}
#endif
else if (v.isPrivateGCThing()) {
// v.toGCCellPtr cannot be inlined, so construct one manually.
Cell* cell = v.toGCThing();
traverseEdge(obj, JS::GCCellPtr(cell, cell->getTraceKind()));

View File

@ -109,6 +109,9 @@ struct RewrapTaggedPointer{};
DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, );
DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, );
DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, );
#ifdef ENABLE_BIGINT
DECLARE_REWRAP(JS::Value, JS::BigInt, JS::BigIntValue, );
#endif
DECLARE_REWRAP(jsid, JSString, NON_INTEGER_ATOM_TO_JSID, (JSAtom*));
DECLARE_REWRAP(jsid, JS::Symbol, SYMBOL_TO_JSID, );
DECLARE_REWRAP(js::TaggedProto, JSObject, js::TaggedProto, );
@ -119,7 +122,11 @@ struct IsPrivateGCThingInValue
: public mozilla::EnableIf<mozilla::IsBaseOf<Cell, T>::value &&
!mozilla::IsBaseOf<JSObject, T>::value &&
!mozilla::IsBaseOf<JSString, T>::value &&
!mozilla::IsBaseOf<JS::Symbol, T>::value, T>
!mozilla::IsBaseOf<JS::Symbol, T>::value
#ifdef ENABLE_BIGINT
&& !mozilla::IsBaseOf<JS::BigInt, T>::value
#endif
, T>
{
static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
"T must not be Cell or TenuredCell");

View File

@ -16,6 +16,9 @@
#include "gc/PublicIterators.h"
#include "gc/Zone.h"
#include "util/Text.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/JSFunction.h"
#include "vm/JSScript.h"
#include "vm/Shape.h"
@ -396,6 +399,12 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
name = "symbol";
break;
#ifdef ENABLE_BIGINT
case JS::TraceKind::BigInt:
name = "BigInt";
break;
#endif
default:
name = "INVALID";
break;

View File

@ -69,6 +69,13 @@ def assert_subprinter_registered(printer, subprinter):
"'info pretty-printer' says:\n"
"%s" % (printer, subprinter, output))
enable_bigint = False
try:
if gdb.lookup_type('JS::BigInt'):
enable_bigint = True
except:
pass
# Request full stack traces for Python errors.
gdb.execute('set python print-stack full')

View File

@ -146,6 +146,15 @@ class JSValueTypeCache(object):
self.NULL = get('JSVAL_TYPE_NULL')
self.OBJECT = get('JSVAL_TYPE_OBJECT')
self.enable_bigint = False
try:
# Looking up the tag will throw an exception if BigInt is not
# enabled.
self.BIGINT = get('JSVAL_TYPE_BIGINT')
self.enable_bigint = True
except:
pass
# Let self.magic_names be an array whose i'th element is the name of
# the i'th magic value.
d = gdb.types.make_enum_dict(gdb.lookup_type('JSWhyMagic'))
@ -198,6 +207,8 @@ class JSValue(object):
value = self.box.as_address().cast(self.cache.JSObject_ptr_t)
elif tag == self.jtc.SYMBOL:
value = self.box.as_address().cast(self.cache.JSSymbol_ptr_t)
elif self.jtc.enable_bigint and tag == self.jtc.BIGINT:
return '$JS::BigIntValue()'
else:
value = 'unrecognized!'
return '$JS::Value(%s)' % (value,)

View File

@ -1,6 +1,10 @@
#include "gdb-tests.h"
#include "jsapi.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
FRAGMENT(jsval, simple) {
using namespace JS;
@ -18,6 +22,9 @@ FRAGMENT(jsval, simple) {
RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!"));
RootedValue friendly_string(cx, StringValue(hello));
RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
#ifdef ENABLE_BIGINT
RootedValue bi(cx, BigIntValue(BigInt::create(cx)));
#endif
RootedValue global(cx);
global.setObject(*CurrentGlobalOrNull(cx));
@ -38,5 +45,8 @@ FRAGMENT(jsval, simple) {
use(empty_string);
use(friendly_string);
use(symbol);
#ifdef ENABLE_BIGINT
use(bi);
#endif
use(global);
}

View File

@ -15,5 +15,7 @@ assert_pretty('elements_hole', '$JS::MagicValue(JS_ELEMENTS_HOLE)')
assert_pretty('empty_string', '$JS::Value("")')
assert_pretty('friendly_string', '$JS::Value("Hello!")')
assert_pretty('symbol', '$JS::Value(Symbol.for("Hello!"))')
if enable_bigint:
assert_pretty('bi', '$JS::BigIntValue()')
assert_pretty('global', '$JS::Value((JSObject *) [object global] delegate)')
assert_pretty('onehundredthirtysevenonehundredtwentyeighths', '$JS::DoubleValue(1.0703125)')

View File

@ -647,3 +647,12 @@ MSG_DEF(JSMSG_BAD_RESPONSE_MIME_TYPE, 0, JSEXN_TYPEERR, "Res
MSG_DEF(JSMSG_BAD_RESPONSE_CORS_SAME_ORIGIN, 0, JSEXN_TYPEERR, "Response.type must be 'basic', 'cors' or 'default'")
MSG_DEF(JSMSG_BAD_RESPONSE_STATUS, 0, JSEXN_TYPEERR, "Response does not have ok status")
MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Response already consumed")
// BigInt
MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")
MSG_DEF(JSMSG_NOT_BIGINT, 0, JSEXN_TYPEERR, "not a BigInt")
MSG_DEF(JSMSG_BIGINT_NOT_SERIALIZABLE, 0, JSEXN_TYPEERR, "BigInt value can't be serialized in JSON")

View File

@ -1591,9 +1591,21 @@ js::ToNumberSlow(JSContext* cx, HandleValue v_, double* out)
return false;
}
MOZ_ASSERT(v.isUndefined());
*out = GenericNaN();
return true;
if (v.isUndefined()) {
*out = GenericNaN();
return true;
}
MOZ_ASSERT(v.isSymbol() || IF_BIGINT(v.isBigInt(), false));
if (!cx->helperThread()) {
unsigned errnum = JSMSG_SYMBOL_TO_NUMBER;
#ifdef ENABLE_BIGINT
if (v.isBigInt())
errnum = JSMSG_BIGINT_TO_NUMBER;
#endif
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errnum);
}
return false;
}
/*

View File

@ -49,6 +49,9 @@ enum JSType {
JSTYPE_BOOLEAN, /* boolean */
JSTYPE_NULL, /* null */
JSTYPE_SYMBOL, /* symbol */
#ifdef ENABLE_BIGINT
JSTYPE_BIGINT, /* BigInt */
#endif
JSTYPE_LIMIT
};

View File

@ -458,6 +458,11 @@ SOURCES += [
'vm/ProfilingStack.cpp',
]
if CONFIG['ENABLE_BIGINT']:
SOURCES += [
'vm/BigIntType.cpp',
]
if CONFIG['JS_POSIX_NSPR']:
UNIFIED_SOURCES += [
'vm/PosixNSPR.cpp',

View File

@ -164,6 +164,14 @@ js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, StringBuffer& sb)
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SYMBOL_TO_STRING);
return false;
}
#ifdef ENABLE_BIGINT
if (v.isBigInt()) {
JSString* str = BigInt::toString(cx, v.toBigInt());
if (!str)
return false;
return sb.append(str);
}
#endif
MOZ_ASSERT(v.isUndefined());
return sb.append(cx->names().undefined);
}

83
js/src/vm/BigIntType.cpp Normal file
View File

@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/BigIntType.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/HashFunctions.h"
#include "jsapi.h"
#include "gc/Allocator.h"
#include "gc/Tracer.h"
#include "vm/JSContext.h"
#include "vm/SelfHosting.h"
using namespace js;
BigInt*
BigInt::create(JSContext* cx)
{
BigInt* x = Allocate<BigInt>(cx);
if (!x)
return nullptr;
return x;
}
BigInt*
BigInt::copy(JSContext* cx, HandleBigInt x)
{
BigInt* bi = create(cx);
if (!bi)
return nullptr;
return bi;
}
JSLinearString*
BigInt::toString(JSContext* cx, BigInt* x)
{
return nullptr;
}
void
BigInt::finalize(js::FreeOp* fop)
{
return;
}
JSAtom*
js::BigIntToAtom(JSContext* cx, BigInt* bi)
{
JSString* str = BigInt::toString(cx, bi);
if (!str)
return nullptr;
return AtomizeString(cx, str);
}
bool
BigInt::toBoolean()
{
return false;
}
js::HashNumber
BigInt::hash()
{
return 0;
}
size_t
BigInt::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return 0;
}
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());
}

60
js/src/vm/BigIntType.h Normal file
View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_BigIntType_h
#define vm_BigIntType_h
#include "gc/Barrier.h"
#include "gc/GC.h"
#include "gc/Heap.h"
#include "js/AllocPolicy.h"
#include "js/GCHashTable.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "vm/StringType.h"
namespace JS {
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];
public:
// Allocate and initialize a BigInt value
static BigInt* create(JSContext* cx);
static const JS::TraceKind TraceKind = JS::TraceKind::BigInt;
void traceChildren(JSTracer* trc);
void finalize(js::FreeOp* fop);
js::HashNumber hash();
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
static JSLinearString* toString(JSContext* cx, BigInt* x);
bool toBoolean();
static BigInt* copy(JSContext* cx, Handle<BigInt*> x);
};
static_assert(sizeof(BigInt) >= js::gc::MinCellSize,
"sizeof(BigInt) must be greater than the minimum allocation size");
} // namespace JS
namespace js {
extern JSAtom*
BigIntToAtom(JSContext* cx, JS::BigInt* bi);
} // namespace js
#endif

View File

@ -464,6 +464,7 @@
macro(boolean, boolean, "boolean") \
macro(null, null, "null") \
macro(symbol, symbol, "symbol") \
macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty") \
macro(bigint, bigint, "bigint") \
macro(defineDataPropertyIntrinsic, defineDataPropertyIntrinsic, "_DefineDataProperty")
#endif /* vm_CommonPropertyNames_h */

View File

@ -32,6 +32,9 @@
#include "util/StringBuffer.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/BytecodeUtil.h"
#include "vm/Debugger.h"
#include "vm/GeneratorObject.h"
@ -969,6 +972,10 @@ js::TypeOfValue(const Value& v)
return TypeOfObject(&v.toObject());
if (v.isBoolean())
return JSTYPE_BOOLEAN;
#ifdef ENABLE_BIGINT
if (v.isBigInt())
return JSTYPE_BIGINT;
#endif
MOZ_ASSERT(v.isSymbol());
return JSTYPE_SYMBOL;
}
@ -4383,7 +4390,10 @@ js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name, MutableHa
// Optimize common cases like (2).toString() or "foo".valueOf() to not
// create a wrapper object.
if (v.isPrimitive() && !v.isNullOrUndefined()) {
if (v.isPrimitive() &&
!v.isNullOrUndefined() &&
IF_BIGINT(!v.isBigInt(), true))
{
NativeObject* proto;
if (v.isNumber()) {
proto = GlobalObject::getOrCreateNumberPrototype(cx, cx->global());

View File

@ -636,6 +636,14 @@ ToAtomSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
}
return nullptr;
}
#ifdef ENABLE_BIGINT
if (v.isBigInt()) {
JSAtom* atom = BigIntToAtom(cx, v.toBigInt());
if (!allowGC && !atom)
cx->recoverFromOutOfMemory();
return atom;
}
#endif
MOZ_ASSERT(v.isUndefined());
return cx->names().undefined;
}

View File

@ -121,6 +121,16 @@ JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp)
return true;
}
#ifdef ENABLE_BIGINT
if (vp.isBigInt()) {
JS::RootedBigInt bi(cx, vp.toBigInt());
if (!wrap(cx, &bi))
return false;
vp.setBigInt(bi);
return true;
}
#endif
MOZ_ASSERT(vp.isObject());
/*

View File

@ -345,6 +345,23 @@ JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
return true;
}
#ifdef ENABLE_BIGINT
bool
JSCompartment::wrap(JSContext* cx, MutableHandleBigInt bi)
{
MOZ_ASSERT(cx->compartment() == this);
if (bi->zone() == cx->zone())
return true;
BigInt* copy = BigInt::copy(cx, bi);
if (!copy)
return false;
bi.set(copy);
return true;
}
#endif
bool
JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
{

View File

@ -636,6 +636,9 @@ struct JSCompartment
MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
#ifdef ENABLE_BIGINT
MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle<JS::BigInt*> bi);
#endif
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandleObject obj);
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<js::PropertyDescriptor> desc);
MOZ_MUST_USE bool wrap(JSContext* cx, JS::MutableHandle<JS::GCVector<JS::Value>> vec);

View File

@ -3251,9 +3251,20 @@ js::PrimitiveToObject(JSContext* cx, const Value& v)
return NumberObject::create(cx, v.toNumber());
if (v.isBoolean())
return BooleanObject::create(cx, v.toBoolean());
#ifdef ENABLE_BIGINT
if (v.isSymbol()) {
RootedSymbol symbol(cx, v.toSymbol());
return SymbolObject::create(cx, symbol);
}
MOZ_ASSERT(v.isBigInt());
RootedBigInt bigInt(cx, v.toBigInt());
// Return nullptr because BigIntObject has not been defined yet.
return nullptr;
#else
MOZ_ASSERT(v.isSymbol());
RootedSymbol symbol(cx, v.toSymbol());
return SymbolObject::create(cx, symbol);
#endif
}
/*

View File

@ -13,6 +13,9 @@
#include "jit/BaselineJIT.h"
#include "jit/Ion.h"
#include "vm/ArrayObject.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/HelperThreads.h"
#include "vm/JSCompartment.h"
#include "vm/JSObject.h"
@ -556,6 +559,15 @@ StatsCellCallback(JSRuntime* rt, void* data, void* thing, JS::TraceKind traceKin
zStats->symbolsGCHeap += thingSize;
break;
#ifdef ENABLE_BIGINT
case JS::TraceKind::BigInt: {
JS::BigInt* bi = static_cast<BigInt*>(thing);
zStats->bigIntsGCHeap += thingSize;
zStats->bigIntsMallocHeap += bi->sizeOfExcludingThis(rtStats->mallocSizeOf_);
break;
}
#endif
case JS::TraceKind::BaseShape: {
JS::ShapeInfo info; // This zeroes all the sizes.
info.shapesGCHeapBase += thingSize;

View File

@ -2071,7 +2071,15 @@ js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType
JSMSG_SYMBOL_TO_STRING);
}
return nullptr;
} else {
}
#ifdef ENABLE_BIGINT
else if (v.isBigInt()) {
if (!allowGC)
return nullptr;
str = BigInt::toString(cx, v.toBigInt());
}
#endif
else {
MOZ_ASSERT(v.isUndefined());
str = cx->names().undefined;
}

View File

@ -190,6 +190,10 @@ PrimitiveTypeFlag(JSValueType type)
return TYPE_FLAG_STRING;
case JSVAL_TYPE_SYMBOL:
return TYPE_FLAG_SYMBOL;
#ifdef ENABLE_BIGINT
case JSVAL_TYPE_BIGINT:
return TYPE_FLAG_BIGINT;
#endif
case JSVAL_TYPE_MAGIC:
return TYPE_FLAG_LAZYARGS;
default:
@ -215,6 +219,10 @@ TypeFlagPrimitive(TypeFlags flags)
return JSVAL_TYPE_STRING;
case TYPE_FLAG_SYMBOL:
return JSVAL_TYPE_SYMBOL;
#ifdef ENABLE_BIGINT
case TYPE_FLAG_BIGINT:
return JSVAL_TYPE_BIGINT;
#endif
case TYPE_FLAG_LAZYARGS:
return JSVAL_TYPE_MAGIC;
default:

View File

@ -113,6 +113,10 @@ TypeSet::NonObjectTypeString(TypeSet::Type type)
return "string";
case JSVAL_TYPE_SYMBOL:
return "symbol";
#ifdef ENABLE_BIGINT
case JSVAL_TYPE_BIGINT:
return "BigInt";
#endif
case JSVAL_TYPE_MAGIC:
return "lazyargs";
default:
@ -785,6 +789,10 @@ TypeSet::print(FILE* fp)
fprintf(fp, " string");
if (flags & TYPE_FLAG_SYMBOL)
fprintf(fp, " symbol");
#ifdef ENABLE_BIGINT
if (flags & TYPE_FLAG_BIGINT)
fprintf(fp, " BigInt");
#endif
if (flags & TYPE_FLAG_LAZYARGS)
fprintf(fp, " lazyargs");

View File

@ -60,17 +60,29 @@ enum : uint32_t {
TYPE_FLAG_DOUBLE = 0x10,
TYPE_FLAG_STRING = 0x20,
TYPE_FLAG_SYMBOL = 0x40,
TYPE_FLAG_LAZYARGS = 0x80,
#ifdef ENABLE_BIGINT
TYPE_FLAG_BIGINT = 0x80,
TYPE_FLAG_LAZYARGS = 0x100,
TYPE_FLAG_ANYOBJECT = 0x200,
#else
TYPE_FLAG_LAZYARGS = 0x80,
TYPE_FLAG_ANYOBJECT = 0x100,
#endif
/* Mask containing all primitives */
TYPE_FLAG_PRIMITIVE = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_BOOLEAN |
TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE | TYPE_FLAG_STRING |
TYPE_FLAG_SYMBOL,
TYPE_FLAG_SYMBOL |
IF_BIGINT(TYPE_FLAG_BIGINT, 0),
/* Mask/shift for the number of objects in objectSet */
#ifdef ENABLE_BIGINT
TYPE_FLAG_OBJECT_COUNT_MASK = 0x3c00,
TYPE_FLAG_OBJECT_COUNT_SHIFT = 10,
#else
TYPE_FLAG_OBJECT_COUNT_MASK = 0x3e00,
TYPE_FLAG_OBJECT_COUNT_SHIFT = 9,
#endif
TYPE_FLAG_OBJECT_COUNT_LIMIT = 7,
TYPE_FLAG_DOMOBJECT_COUNT_LIMIT =
TYPE_FLAG_OBJECT_COUNT_MASK >> TYPE_FLAG_OBJECT_COUNT_SHIFT,
@ -79,7 +91,7 @@ enum : uint32_t {
TYPE_FLAG_UNKNOWN = 0x00004000,
/* Mask of normal type flags on a type set. */
TYPE_FLAG_BASE_MASK = 0x000041ff,
TYPE_FLAG_BASE_MASK = TYPE_FLAG_PRIMITIVE | TYPE_FLAG_LAZYARGS | TYPE_FLAG_ANYOBJECT | TYPE_FLAG_UNKNOWN,
/* Additional flags for HeapTypeSet sets. */
@ -110,6 +122,10 @@ enum : uint32_t {
};
typedef uint32_t TypeFlags;
static_assert(TYPE_FLAG_PRIMITIVE < TYPE_FLAG_ANYOBJECT &&
TYPE_FLAG_LAZYARGS < TYPE_FLAG_ANYOBJECT,
"TYPE_FLAG_ANYOBJECT should be greater than primitive type flags");
/* Flags and other state stored in ObjectGroup::Flags */
enum : uint32_t {
/* Whether this group is associated with some allocation site. */
@ -366,6 +382,9 @@ class TypeSet
static inline Type DoubleType() { return Type(JSVAL_TYPE_DOUBLE); }
static inline Type StringType() { return Type(JSVAL_TYPE_STRING); }
static inline Type SymbolType() { return Type(JSVAL_TYPE_SYMBOL); }
#ifdef ENABLE_BIGINT
static inline Type BigIntType() { return Type(JSVAL_TYPE_BIGINT); }
#endif
static inline Type MagicArgType() { return Type(JSVAL_TYPE_MAGIC); }
static inline Type AnyObjectType() { return Type(JSVAL_TYPE_OBJECT); }
static inline Type UnknownType() { return Type(JSVAL_TYPE_UNKNOWN); }

View File

@ -22,6 +22,9 @@
#include "js/Utility.h"
#include "js/Vector.h"
#include "util/Text.h"
#ifdef ENABLE_BIGINT
#include "vm/BigIntType.h"
#endif
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/GlobalObject.h"
@ -203,7 +206,13 @@ Node::exposeToJS() const
v.setString(as<JSString>());
} else if (is<JS::Symbol>()) {
v.setSymbol(as<JS::Symbol>());
} else {
}
#ifdef ENABLE_BIGINT
else if (is<BigInt>()) {
v.setBigInt(as<BigInt>());
}
#endif
else {
v.setUndefined();
}
@ -315,6 +324,9 @@ template JS::Zone* TracerConcrete<js::ObjectGroup>::zone() const;
template JS::Zone* TracerConcrete<js::RegExpShared>::zone() const;
template JS::Zone* TracerConcrete<js::Scope>::zone() const;
template JS::Zone* TracerConcrete<JS::Symbol>::zone() const;
#ifdef ENABLE_BIGINT
template JS::Zone* TracerConcrete<BigInt>::zone() const;
#endif
template JS::Zone* TracerConcrete<JSString>::zone() const;
template<typename Referent>
@ -338,6 +350,9 @@ template UniquePtr<EdgeRange> TracerConcrete<js::ObjectGroup>::edges(JSContext*
template UniquePtr<EdgeRange> TracerConcrete<js::RegExpShared>::edges(JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<js::Scope>::edges(JSContext* cx, bool wantNames) const;
template UniquePtr<EdgeRange> TracerConcrete<JS::Symbol>::edges(JSContext* cx, bool wantNames) const;
#ifdef ENABLE_BIGINT
template UniquePtr<EdgeRange> TracerConcrete<BigInt>::edges(JSContext* cx, bool wantNames) const;
#endif
template UniquePtr<EdgeRange> TracerConcrete<JSString>::edges(JSContext* cx, bool wantNames) const;
template<typename Referent>
@ -393,6 +408,9 @@ Concrete<JSObject>::jsObjectConstructorName(JSContext* cx, UniqueTwoByteChars& o
}
const char16_t Concrete<JS::Symbol>::concreteTypeName[] = u"JS::Symbol";
#ifdef ENABLE_BIGINT
const char16_t Concrete<BigInt>::concreteTypeName[] = u"JS::BigInt";
#endif
const char16_t Concrete<JSScript>::concreteTypeName[] = u"JSScript";
const char16_t Concrete<js::LazyScript>::concreteTypeName[] = u"js::LazyScript";
const char16_t Concrete<js::jit::JitCode>::concreteTypeName[] = u"js::jit::JitCode";