Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2023-07-25 09:16:25 +08:00
commit 1977864a3a
131 changed files with 6239 additions and 442 deletions

View file

@ -1037,11 +1037,17 @@ MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
return MaybeWrapStringValue(cx, rval);
}
if (!rval.isObject()) {
return true;
if (rval.isObject()) {
return MaybeWrapObjectValue(cx, rval);
}
return MaybeWrapObjectValue(cx, rval);
// This could be optimized by checking the zone first, similar to
// the way strings are handled. At present, this is used primarily
// for structured cloning, so avoiding the overhead of JS_WrapValue
// calls is less important than for other types.
if (rval.isBigInt()) {
return JS_WrapValue(cx, rval);
}
return true;
}
namespace binding_detail {

View file

@ -1100,6 +1100,7 @@ enum class ESClass {
SetIterator,
Arguments,
Error,
BigInt,
/** None of the above. */
Other

View file

@ -11,6 +11,7 @@
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/WrappingOperations.h"
#include <math.h>
@ -120,7 +121,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

@ -47,6 +47,7 @@
// Expand the given macro D for each public GC pointer.
#define FOR_EACH_PUBLIC_GC_POINTER_TYPE(D) \
D(JS::Symbol*) \
D(JS::BigInt*) \
D(JSAtom*) \
D(JSFunction*) \
D(JSObject*) \
@ -125,6 +126,7 @@ struct GCPointerPolicy
}
};
template <> struct GCPolicy<JS::Symbol*> : public GCPointerPolicy<JS::Symbol*> {};
template <> struct GCPolicy<JS::BigInt*> : public GCPointerPolicy<JS::BigInt*> {};
template <> struct GCPolicy<JSAtom*> : public GCPointerPolicy<JSAtom*> {};
template <> struct GCPolicy<JSFunction*> : public GCPointerPolicy<JSFunction*> {};
template <> struct GCPolicy<JSObject*> : public GCPointerPolicy<JSObject*> {};

View file

@ -580,6 +580,7 @@ struct UnusedGCThingSizes
macro(Other, GCHeapUnused, objectGroup) \
macro(Other, GCHeapUnused, string) \
macro(Other, GCHeapUnused, symbol) \
macro(Other, GCHeapUnused, bigInt) \
macro(Other, GCHeapUnused, jitcode) \
macro(Other, GCHeapUnused, scope) \
macro(Other, GCHeapUnused, regExpShared)
@ -599,6 +600,7 @@ struct UnusedGCThingSizes
case JS::TraceKind::Object: object += n; break;
case JS::TraceKind::String: string += n; break;
case JS::TraceKind::Symbol: symbol += n; break;
case JS::TraceKind::BigInt: bigInt += n; break;
case JS::TraceKind::Script: script += n; break;
case JS::TraceKind::Shape: shape += n; break;
case JS::TraceKind::BaseShape: baseShape += n; break;
@ -640,6 +642,8 @@ struct ZoneStats
{
#define FOR_EACH_SIZE(macro) \
macro(Other, GCHeapUsed, symbolsGCHeap) \
macro(Other, GCHeapUsed, bigIntsGCHeap) \
macro(Other, MallocHeap, bigIntsMallocHeap) \
macro(Other, GCHeapAdmin, gcHeapArenaAdmin) \
macro(Other, GCHeapUsed, lazyScriptsGCHeap) \
macro(Other, MallocHeap, lazyScriptsMallocHeap) \

View file

@ -60,7 +60,8 @@ enum class TraceKind
JitCode = 0x1F,
LazyScript = 0x2F,
Scope = 0x3F,
RegExpShared = 0x4F
RegExpShared = 0x4F,
BigInt = 0x5F
};
const static uintptr_t OutOfLineTraceKindMask = 0x07;
static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
@ -91,6 +92,7 @@ struct MapTypeToTraceKind {
D(Shape, js::Shape, true) \
D(String, JSString, false) \
D(Symbol, JS::Symbol, false) \
D(BigInt, JS::BigInt, false) \
D(RegExpShared, js::RegExpShared, true)
// Map from all public types to their trace kind.

View file

@ -141,6 +141,7 @@ 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)); }
virtual void onBigIntEdge(JS::BigInt** bip) { onChild(JS::GCCellPtr(*bip)); }
virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); }
virtual void onShapeEdge(js::Shape** shapep) {
onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape));
@ -226,6 +227,7 @@ 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); }
void dispatchToOnEdge(JS::BigInt** bip) { onBigIntEdge(bip); }
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); }
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); }
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); }

View file

@ -39,6 +39,7 @@ namespace JS {
typedef unsigned char Latin1Char;
class Symbol;
class BigInt;
class Value;
template <typename T> class Handle;
template <typename T> class MutableHandle;
@ -53,6 +54,7 @@ typedef Handle<JSObject*> HandleObject;
typedef Handle<JSScript*> HandleScript;
typedef Handle<JSString*> HandleString;
typedef Handle<JS::Symbol*> HandleSymbol;
typedef Handle<JS::BigInt*> HandleBigInt;
typedef Handle<Value> HandleValue;
typedef Handle<StackGCVector<Value>> HandleValueVector;
@ -62,6 +64,7 @@ typedef MutableHandle<JSObject*> MutableHandleObject;
typedef MutableHandle<JSScript*> MutableHandleScript;
typedef MutableHandle<JSString*> MutableHandleString;
typedef MutableHandle<JS::Symbol*> MutableHandleSymbol;
typedef MutableHandle<JS::BigInt*> MutableHandleBigInt;
typedef MutableHandle<Value> MutableHandleValue;
typedef MutableHandle<StackGCVector<Value>> MutableHandleValueVector;
@ -70,6 +73,7 @@ typedef Rooted<JSFunction*> RootedFunction;
typedef Rooted<JSScript*> RootedScript;
typedef Rooted<JSString*> RootedString;
typedef Rooted<JS::Symbol*> RootedSymbol;
typedef Rooted<JS::BigInt*> RootedBigInt;
typedef Rooted<jsid> RootedId;
typedef Rooted<JS::Value> RootedValue;
@ -81,6 +85,7 @@ typedef PersistentRooted<JSObject*> PersistentRootedObject;
typedef PersistentRooted<JSScript*> PersistentRootedScript;
typedef PersistentRooted<JSString*> PersistentRootedString;
typedef PersistentRooted<JS::Symbol*> PersistentRootedSymbol;
typedef PersistentRooted<JS::BigInt*> PersistentRootedBigInt;
typedef PersistentRooted<Value> PersistentRootedValue;

View file

@ -1056,6 +1056,22 @@ class JS_PUBLIC_API(Concrete<JS::Symbol>) : TracerConcrete<JS::Symbol> {
static const char16_t concreteTypeName[];
};
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[];
};
template<>
class JS_PUBLIC_API(Concrete<JSScript>) : TracerConcreteWithCompartment<JSScript> {
protected:

View file

@ -14,6 +14,7 @@
#include "mozilla/Scoped.h"
#include "mozilla/TemplateLib.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WrappingOperations.h"
#include <stdlib.h>
#include <string.h>
@ -539,7 +540,7 @@ ScrambleHashCode(HashNumber h)
* are stored in a hash table; see Knuth for details.
*/
static const HashNumber goldenRatio = 0x9E3779B9U;
return h * goldenRatio;
return mozilla::WrappingMultiply(h, goldenRatio);
}
} /* namespace detail */

View file

@ -56,6 +56,7 @@ JS_ENUM_HEADER(JSValueType, uint8_t)
JSVAL_TYPE_STRING = 0x06,
JSVAL_TYPE_SYMBOL = 0x07,
JSVAL_TYPE_PRIVATE_GCTHING = 0x08,
JSVAL_TYPE_BIGINT = 0x09,
JSVAL_TYPE_OBJECT = 0x0c,
/* These never appear in a jsval; they are only provided as an out-of-band value. */
@ -80,6 +81,7 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC,
JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT,
JSVAL_TAG_BIGINT = JSVAL_TAG_CLEAR | JSVAL_TYPE_BIGINT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@ -100,6 +102,7 @@ JS_ENUM_HEADER(JSValueTag, uint32_t)
JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN,
JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC,
JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT,
JSVAL_TAG_BIGINT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BIGINT,
JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING
} JS_ENUM_FOOTER(JSValueTag);
@ -117,6 +120,7 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t)
JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_BIGINT = (((uint64_t)JSVAL_TAG_BIGINT) << JSVAL_TAG_SHIFT),
JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT)
} JS_ENUM_FOOTER(JSValueShiftedTag);
@ -275,7 +279,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.
*
@ -370,6 +374,11 @@ class MOZ_NON_PARAM alignas(8) Value
data.asBits = bitsFromTagAndPayload(JSVAL_TAG_SYMBOL, PayloadType(sym));
}
void setBigInt(JS::BigInt* bi) {
MOZ_ASSERT(uintptr_t(bi) > 0x1000);
data.asBits = bitsFromTagAndPayload(JSVAL_TAG_BIGINT, PayloadType(bi));
}
void setObject(JSObject& obj) {
MOZ_ASSERT(uintptr_t(&obj) > 0x1000 || uintptr_t(&obj) == 0x48);
#if defined(JS_PUNBOX64)
@ -498,7 +507,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32)
return uint32_t(toTag()) <= uint32_t(JSVAL_TAG_CLEAR);
#elif defined(JS_PUNBOX64)
return (data.asBits | mozilla::DoubleTypeTraits::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
return (data.asBits | mozilla::FloatingPoint<double>::kSignBit) <= JSVAL_SHIFTED_TAG_MAX_DOUBLE;
#endif
}
@ -519,6 +528,10 @@ class MOZ_NON_PARAM alignas(8) Value
return toTag() == JSVAL_TAG_SYMBOL;
}
bool isBigInt() const {
return toTag() == JSVAL_TAG_BIGINT;
}
bool isObject() const {
#if defined(JS_NUNBOX32)
return toTag() == JSVAL_TAG_OBJECT;
@ -583,6 +596,8 @@ class MOZ_NON_PARAM alignas(8) Value
"Value type tags must correspond with JS::TraceKinds.");
if (MOZ_UNLIKELY(isPrivateGCThing()))
return JS::GCThingTraceKind(toGCThing());
if (MOZ_UNLIKELY(isBigInt()))
return JS::TraceKind::BigInt;
return JS::TraceKind(toTag() & 0x03);
}
@ -647,6 +662,15 @@ class MOZ_NON_PARAM alignas(8) Value
#endif
}
JS::BigInt* toBigInt() const {
MOZ_ASSERT(isBigInt());
#if defined(JS_NUNBOX32)
return data.s.payload.bi;
#elif defined(JS_PUNBOX64)
return reinterpret_cast<JS::BigInt*>(data.asBits & JSVAL_PAYLOAD_MASK);
#endif
}
JSObject& toObject() const {
MOZ_ASSERT(isObject());
#if defined(JS_NUNBOX32)
@ -759,6 +783,8 @@ class 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.");
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::BigInt,
"Private GC thing Values must not be BigInts. Make a BigIntValue instead.");
MOZ_ASSERT(JS::GCThingTraceKind(cell) != JS::TraceKind::Object,
"Private GC thing Values must not be objects. Make an ObjectValue instead.");
@ -811,6 +837,7 @@ class MOZ_NON_PARAM alignas(8) Value
uint32_t boo; // Don't use |bool| -- it must be four bytes.
JSString* str;
JS::Symbol* sym;
JS::BigInt* bi;
JSObject* obj;
js::gc::Cell* cell;
void* ptr;
@ -866,6 +893,7 @@ class MOZ_NON_PARAM alignas(8) Value
uint32_t boo; // Don't use |bool| -- it must be four bytes.
JSString* str;
JS::Symbol* sym;
JS::BigInt* bi;
JSObject* obj;
js::gc::Cell* cell;
void* ptr;
@ -1062,7 +1090,7 @@ IsCanonicalized(double d)
uint64_t bits;
mozilla::BitwiseCast<uint64_t>(d, &bits);
return (bits & ~mozilla::DoubleTypeTraits::kSignBit) == detail::CanonicalizedNaNBits;
return (bits & ~mozilla::FloatingPoint<double>::kSignBit) == detail::CanonicalizedNaNBits;
}
static inline Value
@ -1097,6 +1125,14 @@ SymbolValue(JS::Symbol* sym)
return v;
}
static inline Value
BigIntValue(JS::BigInt* bi)
{
Value v;
v.setBigInt(bi);
return v;
}
static inline Value
BooleanValue(bool boo)
{
@ -1365,6 +1401,7 @@ class WrappedPtrOperations<JS::Value, Wrapper>
bool isDouble() const { return value().isDouble(); }
bool isString() const { return value().isString(); }
bool isSymbol() const { return value().isSymbol(); }
bool isBigInt() const { return value().isBigInt(); }
bool isObject() const { return value().isObject(); }
bool isMagic() const { return value().isMagic(); }
bool isMagic(JSWhyMagic why) const { return value().isMagic(why); }
@ -1380,6 +1417,7 @@ class WrappedPtrOperations<JS::Value, Wrapper>
double toDouble() const { return value().toDouble(); }
JSString* toString() const { return value().toString(); }
JS::Symbol* toSymbol() const { return value().toSymbol(); }
JS::BigInt* toBigInt() const { return value().toBigInt(); }
JSObject& toObject() const { return value().toObject(); }
JSObject* toObjectOrNull() const { return value().toObjectOrNull(); }
gc::Cell* toGCThing() const { return value().toGCThing(); }
@ -1421,6 +1459,7 @@ class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperati
void setNumber(double d) { set(JS::NumberValue(d)); }
void setString(JSString* str) { set(JS::StringValue(str)); }
void setSymbol(JS::Symbol* sym) { set(JS::SymbolValue(sym)); }
void setBigInt(JS::BigInt* bi) { set(JS::BigIntValue(bi)); }
void setObject(JSObject& obj) { set(JS::ObjectValue(obj)); }
void setObjectOrNull(JSObject* arg) { set(JS::ObjectOrNullValue(arg)); }
void setPrivate(void* ptr) { set(JS::PrivateValue(ptr)); }
@ -1469,6 +1508,8 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args)
return f(&val.toObject(), mozilla::Forward<Args>(args)...);
if (val.isSymbol())
return f(val.toSymbol(), mozilla::Forward<Args>(args)...);
if (val.isBigInt())
return f(val.toBigInt(), mozilla::Forward<Args>(args)...);
if (MOZ_UNLIKELY(val.isPrivateGCThing()))
return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...);
MOZ_ASSERT(!val.isGCThing());

View file

@ -50,6 +50,7 @@ class PropertyResult;
class Symbol;
enum class SymbolCode: uint32_t;
class BigInt;
} // namespace JS
// Do the importing.
@ -122,6 +123,7 @@ using JS::RootedObject;
using JS::RootedScript;
using JS::RootedString;
using JS::RootedSymbol;
using JS::RootedBigInt;
using JS::RootedValue;
using JS::PersistentRooted;
@ -131,6 +133,7 @@ using JS::PersistentRootedObject;
using JS::PersistentRootedScript;
using JS::PersistentRootedString;
using JS::PersistentRootedSymbol;
using JS::PersistentRootedBigInt;
using JS::PersistentRootedValue;
using JS::Handle;
@ -140,6 +143,7 @@ using JS::HandleObject;
using JS::HandleScript;
using JS::HandleString;
using JS::HandleSymbol;
using JS::HandleBigInt;
using JS::HandleValue;
using JS::MutableHandle;
@ -149,6 +153,7 @@ using JS::MutableHandleObject;
using JS::MutableHandleScript;
using JS::MutableHandleString;
using JS::MutableHandleSymbol;
using JS::MutableHandleBigInt;
using JS::MutableHandleValue;
using JS::NullHandleValue;
@ -166,6 +171,7 @@ using JS::Zone;
using JS::Symbol;
using JS::SymbolCode;
using JS::BigInt;
} /* namespace js */
#endif /* NamespaceImports_h */

258
js/src/builtin/BigInt.cpp Normal file
View file

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "builtin/BigInt.h"
#include "jsapi.h"
#include "builtin/TypedObject.h"
#include "gc/Tracer.h"
#include "js/TracingAPI.h"
#include "vm/ArrayBufferObject.h"
#include "vm/BigIntType.h"
#include "vm/SelfHosting.h"
#include "vm/TaggedProto.h"
#include "vm/NativeObject-inl.h"
using namespace js;
static MOZ_ALWAYS_INLINE bool
IsBigInt(HandleValue v)
{
return v.isBigInt() || (v.isObject() && v.toObject().is<BigIntObject>());
}
static JSObject*
CreateBigIntPrototype(JSContext* cx, JSProtoKey key)
{
return GlobalObject::createBlankPrototype<PlainObject>(cx, cx->global());
}
// BigInt proposal section 5.1.3
static bool
BigIntConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (args.isConstructing()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_CONSTRUCTOR, "BigInt");
return false;
}
// Step 2.
RootedValue v(cx, args.get(0));
if (!ToPrimitive(cx, JSTYPE_NUMBER, &v))
return false;
// Steps 3-4.
BigInt* bi = v.isNumber()
? NumberToBigInt(cx, v.toNumber())
: ToBigInt(cx, v);
if (!bi)
return false;
args.rval().setBigInt(bi);
return true;
}
JSObject*
BigIntObject::create(JSContext* cx, HandleBigInt bigInt)
{
RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
if (!obj)
return nullptr;
BigIntObject& bn = obj->as<BigIntObject>();
bn.setFixedSlot(PRIMITIVE_VALUE_SLOT, BigIntValue(bigInt));
return &bn;
}
BigInt*
BigIntObject::unbox() const
{
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toBigInt();
}
// BigInt proposal section 5.3.4
bool
BigIntObject::valueOf_impl(JSContext* cx, const CallArgs& args)
{
// Step 1.
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
args.rval().setBigInt(bi);
return true;
}
bool
BigIntObject::valueOf(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, valueOf_impl>(cx, args);
}
// BigInt proposal section 5.3.3
bool
BigIntObject::toString_impl(JSContext* cx, const CallArgs& args)
{
// Step 1.
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
// Steps 2-3.
uint8_t radix = 10;
// Steps 4-5.
if (args.hasDefined(0)) {
double d;
if (!ToInteger(cx, args.get(0), &d))
return false;
if (d < 2 || d > 36) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_RADIX);
return false;
}
radix = d;
}
// Steps 6-7.
JSLinearString* str = BigInt::toString(cx, bi, radix);
if (!str)
return false;
args.rval().setString(str);
return true;
}
bool
BigIntObject::toString(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, toString_impl>(cx, args);
}
// BigInt proposal section 5.3.2. "This function is
// implementation-dependent, and it is permissible, but not encouraged,
// for it to return the same thing as toString."
bool
BigIntObject::toLocaleString_impl(JSContext* cx, const CallArgs& args)
{
HandleValue thisv = args.thisv();
MOZ_ASSERT(IsBigInt(thisv));
RootedBigInt bi(cx, thisv.isBigInt()
? thisv.toBigInt()
: thisv.toObject().as<BigIntObject>().unbox());
RootedString str(cx, BigInt::toString(cx, bi, 10));
if (!str)
return false;
args.rval().setString(str);
return true;
}
bool
BigIntObject::toLocaleString(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsBigInt, toLocaleString_impl>(cx, args);
}
// BigInt proposal section 5.2.1. BigInt.asUintN ( bits, bigint )
bool
BigIntObject::asUintN(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
uint64_t bits;
if (!ToIndex(cx, args.get(0), &bits)) {
return false;
}
// Step 2.
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
if (!bi) {
return false;
}
// Step 3.
BigInt* res = BigInt::asUintN(cx, bi, bits);
if (!res) {
return false;
}
args.rval().setBigInt(res);
return true;
}
// BigInt proposal section 5.2.2. BigInt.asIntN ( bits, bigint )
bool
BigIntObject::asIntN(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
uint64_t bits;
if (!ToIndex(cx, args.get(0), &bits)) {
return false;
}
// Step 2.
RootedBigInt bi(cx, ToBigInt(cx, args.get(1)));
if (!bi) {
return false;
}
// Step 3.
BigInt* res = BigInt::asIntN(cx, bi, bits);
if (!res) {
return false;
}
args.rval().setBigInt(res);
return true;
}
const ClassSpec BigIntObject::classSpec_ = {
GenericCreateConstructor<BigIntConstructor, 1, gc::AllocKind::FUNCTION>,
CreateBigIntPrototype,
BigIntObject::staticMethods,
nullptr,
BigIntObject::methods,
BigIntObject::properties
};
const Class BigIntObject::class_ = {
"BigInt",
JSCLASS_HAS_CACHED_PROTO(JSProto_BigInt) |
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS),
JS_NULL_CLASS_OPS,
&BigIntObject::classSpec_
};
const JSPropertySpec BigIntObject::properties[] = {
// BigInt proposal section 5.3.5
JS_STRING_SYM_PS(toStringTag, "BigInt", JSPROP_READONLY),
JS_PS_END
};
const JSFunctionSpec BigIntObject::methods[] = {
JS_FN("valueOf", valueOf, 0, 0),
JS_FN("toString", toString, 0, 0),
JS_FN("toLocaleString", toLocaleString, 0, 0),
JS_FS_END
};
const JSFunctionSpec BigIntObject::staticMethods[] = {
JS_FN("asUintN", asUintN, 2, 0),
JS_FN("asIntN", asIntN, 2, 0),
JS_FS_END
};

52
js/src/builtin/BigInt.h Normal file
View file

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 builtin_BigInt_h
#define builtin_BigInt_h
#include "js/Class.h"
#include "js/RootingAPI.h"
#include "vm/BigIntType.h"
#include "vm/NativeObject.h"
namespace js {
class GlobalObject;
class BigIntObject : public NativeObject
{
static const unsigned PRIMITIVE_VALUE_SLOT = 0;
static const unsigned RESERVED_SLOTS = 1;
public:
static const ClassSpec classSpec_;
static const Class class_;
static JSObject* create(JSContext* cx, JS::Handle<JS::BigInt*> bi);
// Methods defined on BigInt.prototype.
static bool valueOf_impl(JSContext* cx, const CallArgs& args);
static bool valueOf(JSContext* cx, unsigned argc, JS::Value* vp);
static bool toString_impl(JSContext* cx, const CallArgs& args);
static bool toString(JSContext* cx, unsigned argc, JS::Value* vp);
static bool toLocaleString_impl(JSContext* cx, const CallArgs& args);
static bool toLocaleString(JSContext* cx, unsigned argc, JS::Value* vp);
static bool asUintN(JSContext* cx, unsigned argc, JS::Value* vp);
static bool asIntN(JSContext* cx, unsigned argc, JS::Value* vp);
JS::BigInt* unbox() const;
private:
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSFunctionSpec staticMethods[];
};
extern JSObject*
InitBigIntClass(JSContext* cx, Handle<GlobalObject*> global);
} // namespace js
#endif

View file

@ -61,7 +61,7 @@ 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() || value.isBigInt());
return true;
}
@ -81,6 +81,8 @@ HashValue(const Value& v, const mozilla::HashCodeScrambler& hcs)
return v.toString()->asAtom().hash();
if (v.isSymbol())
return v.toSymbol()->hash();
if (v.isBigInt())
return MaybeForwarded(v.toBigInt())->hash();
if (v.isObject())
return hcs.scramble(v.asRawBits());
@ -100,6 +102,12 @@ HashableValue::operator==(const HashableValue& other) const
// Two HashableValues are equal if they have equal bits.
bool b = (value.asRawBits() == other.value.asRawBits());
// BigInt values are considered equal if they represent the same
// mathematical value.
if (!b && (value.isBigInt() && other.value.isBigInt())) {
b = BigInt::equal(value.toBigInt(), other.value.toBigInt());
}
#ifdef DEBUG
bool same;
JS::RootingContext* rcx = GetJSContextFromMainThread();
@ -378,8 +386,9 @@ MarkKey(Range& r, const HashableValue& key, JSTracer* trc)
HashableValue newKey = key.mark(trc);
if (newKey.get() != key.get()) {
// The hash function only uses the bits of the Value, so it is safe to
// rekey even when the object or string has been modified by the GC.
// The hash function must take account of the fact that the thing being
// hashed may have been moved by GC. This is only an issue for BigInt as for
// other types the hash function only uses the bits of the Value.
r.rekeyFront(newKey);
}
}

View file

@ -7,6 +7,8 @@
#include "mozilla/ArrayUtils.h"
#include "builtin/BigInt.h"
#include "jscntxt.h"
#include "jsstr.h"
@ -471,6 +473,9 @@ js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
case ESClass::RegExp:
builtinTag = cx->names().objectRegExp;
break;
case ESClass::BigInt:
builtinTag = cx->names().objectBigInt;
break;
default:
if (obj->isCallable()) {
// Non-standard: Prevent <object> from showing up as Function.

View file

@ -21,6 +21,7 @@
#include "frontend/TokenStream.h"
#include "js/CharacterEncoding.h"
#include "vm/RegExpObject.h"
#include "vm/BigIntType.h"
#include "jsobjinlines.h"
@ -3434,6 +3435,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_STRING:
case PNK_REGEXP:
case PNK_NUMBER:
case PNK_BIGINT:
case PNK_TRUE:
case PNK_FALSE:
case PNK_NULL:
@ -3604,7 +3606,7 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
case PNK_REGEXP:
{
RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object);
RootedObject re1(cx, pn->as<RegExpLiteral>().objbox()->object());
LOCAL_ASSERT(re1 && re1->is<RegExpObject>());
RootedObject re2(cx, CloneRegExpObject(cx, re1));
@ -3619,6 +3621,13 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
val.setNumber(pn->as<NumericLiteral>().value());
break;
case PNK_BIGINT:
{
BigInt* x = pn->as<BigIntLiteral>().box()->value();
val.setBigInt(x);
break;
}
case PNK_NULL:
val.setNull();
break;

View file

@ -1093,6 +1093,11 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
*answer = false;
return true;
case PNK_BIGINT:
MOZ_ASSERT(pn->is<BigIntLiteral>());
*answer = false;
return true;
// |this| can throw in derived class constructors, including nested arrow
// functions or eval.
case PNK_THIS:
@ -4225,6 +4230,9 @@ ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObje
case PNK_NUMBER:
vp.setNumber(as<NumericLiteral>().value());
return true;
case PNK_BIGINT:
vp.setBigInt(as<BigIntLiteral>().box()->value());
return true;
case PNK_TEMPLATE_STRING:
case PNK_STRING:
vp.setString(as<NameNode>().atom());
@ -4834,6 +4842,15 @@ BytecodeEmitter::emitCopyDataProperties(CopyOption option)
return true;
}
bool
BytecodeEmitter::emitBigIntOp(BigInt* bigint)
{
if (!constList.append(BigIntValue(bigint))) {
return false;
}
return emitIndex32(JSOP_BIGINT, constList.length() - 1);
}
bool
BytecodeEmitter::emitIterator()
{
@ -9579,6 +9596,12 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false;
break;
case PNK_BIGINT:
if (!emitBigIntOp(pn->as<BigIntLiteral>().box()->value())) {
return false;
}
break;
case PNK_REGEXP:
if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox())))
return false;
@ -10317,7 +10340,7 @@ CGConstList::finish(ConstArray* array)
MOZ_ASSERT(length() == array->length);
for (unsigned i = 0; i < length(); i++)
array->vector[i] = list[i];
array->vector[i] = vector[i];
}
/*
@ -10331,6 +10354,7 @@ CGConstList::finish(ConstArray* array)
unsigned
CGObjectList::add(ObjectBox* objbox)
{
MOZ_ASSERT(objbox->isObjectBox());
MOZ_ASSERT(!objbox->emitLink);
objbox->emitLink = lastbox;
lastbox = objbox;
@ -10342,7 +10366,7 @@ CGObjectList::indexOf(JSObject* obj)
{
MOZ_ASSERT(length > 0);
unsigned index = length - 1;
for (ObjectBox* box = lastbox; box->object != obj; box = box->emitLink)
for (ObjectBox* box = lastbox; box->object() != obj; box = box->emitLink)
index--;
return index;
}
@ -10358,8 +10382,8 @@ CGObjectList::finish(ObjectArray* array)
do {
--cursor;
MOZ_ASSERT(!*cursor);
MOZ_ASSERT(objbox->object->isTenured());
*cursor = objbox->object;
MOZ_ASSERT(objbox->object()->isTenured());
*cursor = objbox->object();
} while ((objbox = objbox->emitLink) != nullptr);
MOZ_ASSERT(cursor == array->vector);
}

View file

@ -35,20 +35,21 @@ class SharedContext;
class TokenStream;
class CGConstList {
Vector<Value> list;
Rooted<ValueVector> vector;
public:
explicit CGConstList(ExclusiveContext* cx) : list(cx) {}
explicit CGConstList(ExclusiveContext* cx)
: vector(cx, ValueVector(cx))
{ }
MOZ_MUST_USE bool append(const Value& v) {
MOZ_ASSERT_IF(v.isString(), v.toString()->isAtom());
return list.append(v);
return vector.append(v);
}
size_t length() const { return list.length(); }
size_t length() const { return vector.length(); }
void finish(ConstArray* array);
};
struct CGObjectList {
uint32_t length; /* number of emitted so far objects */
ObjectBox* lastbox; /* last emitted object */
ObjectBox* lastbox; /* last emitted object */
CGObjectList() : length(0), lastbox(nullptr) {}
@ -198,7 +199,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
return innermostEmitterScope_;
}
CGConstList constList; /* constants to be included with the script */
CGConstList constList; /* double and bigint values used by script */
CGObjectList objectList; /* list of emitted objects */
CGScopeList scopeList; /* list of emitted scopes */
CGTryNoteList tryNoteList; /* list of emitted try notes */
@ -478,6 +479,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitNumberOp(double dval);
MOZ_MUST_USE bool emitBigIntOp(BigInt* bigint);
MOZ_MUST_USE bool emitThisLiteral(ThisLiteral* pn);
MOZ_MUST_USE bool emitGetFunctionThis(ParseNode* pn);
MOZ_MUST_USE bool emitGetFunctionThis(const mozilla::Maybe<uint32_t>& offset);

View file

@ -395,6 +395,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_THIS:
case PNK_ELISION:
case PNK_NUMBER:
case PNK_BIGINT:
case PNK_NEW:
case PNK_GENERATOR:
case PNK_GENEXP:
@ -485,6 +486,7 @@ IsEffectless(ParseNode* node)
node->isKind(PNK_FALSE) ||
node->isKind(PNK_STRING) ||
node->isKind(PNK_TEMPLATE_STRING) ||
node->isKind(PNK_BIGINT) ||
node->isKind(PNK_NUMBER) ||
node->isKind(PNK_NULL) ||
node->isKind(PNK_RAW_UNDEFINED) ||
@ -503,6 +505,9 @@ Boolish(ParseNode* pn, bool isNullish = false)
return (isNullish || isNonZeroNumber) ? Truthy : Falsy;
}
case PNK_BIGINT:
return (pn->as<BigIntLiteral>().box()->value()->isZero()) ? Falsy : Truthy;
case PNK_STRING:
case PNK_TEMPLATE_STRING: {
bool isNonZeroLengthString = (pn->as<NameNode>().atom()->length() > 0);
@ -591,6 +596,8 @@ FoldTypeOfExpr(ExclusiveContext* cx, UnaryNode* node, Parser<FullParseHandler>&
result = cx->names().string;
else if (expr->isKind(PNK_NUMBER))
result = cx->names().number;
else if (expr->isKind(PNK_BIGINT))
result = cx->names().bigint;
else if (expr->isKind(PNK_NULL))
result = cx->names().object;
else if (expr->isKind(PNK_TRUE) || expr->isKind(PNK_FALSE))
@ -1699,6 +1706,10 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
MOZ_ASSERT(pn->is<NumericLiteral>());
return true;
case PNK_BIGINT:
MOZ_ASSERT(pn->is<BigIntLiteral>());
return true;
case PNK_SUPERBASE:
case PNK_TYPEOFNAME: {
#ifdef DEBUG

View file

@ -151,6 +151,18 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return new_<NumericLiteral>(value, decimalPoint, pos);
}
// The Boxer object here is any object that can allocate BigIntBoxes.
// Specifically, a Boxer has a .newBigIntBox(T) method that accepts a
// BigInt* argument and returns a BigIntBox*.
template <class Boxer>
BigIntLiteralType newBigInt(BigInt* bi, const TokenPos& pos, Boxer& boxer) {
BigIntBox* box = boxer.newBigIntBox(bi);
if (!box) {
return null();
}
return new_<BigIntLiteral>(box, pos);
}
BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) {
return new_<BooleanLiteral>(cond, pos);
}

View file

@ -420,6 +420,9 @@ class NameResolver
MOZ_ASSERT(cur->is<NumericLiteral>());
break;
case PNK_BIGINT:
MOZ_ASSERT(cur->is<BigIntLiteral>());
break;
case PNK_TYPEOFNAME:
case PNK_SUPERBASE:

View file

@ -218,6 +218,10 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
MOZ_ASSERT(pn->is<NumericLiteral>());
return PushResult::Recyclable;
case PNK_BIGINT:
MOZ_ASSERT(pn->is<BigIntLiteral>());
return PushResult::Recyclable;
// Nodes with a single non-null child.
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
@ -716,6 +720,9 @@ ParseNode::dump(int indent)
case PN_NUMBER:
as<NumericLiteral>().dump(indent);
return;
case PN_BIGINT:
as<BigIntLiteral>().dump(indent);
return;
case PN_REGEXP:
as<RegExpLiteral>().dump(indent);
return;
@ -759,6 +766,12 @@ NumericLiteral::dump(int indent)
}
}
void
BigIntLiteral::dump(int indent)
{
fprintf(stderr, "(%s)", parseNodeNames[size_t(getKind())]);
}
void
RegExpLiteral::dump(int indent)
{
@ -962,23 +975,45 @@ LexicalScopeNode::dump(int indent)
}
#endif
ObjectBox::ObjectBox(JSObject* object, ObjectBox* traceLink)
: object(object),
traceLink(traceLink),
emitLink(nullptr)
TraceListNode::TraceListNode(js::gc::Cell* gcThing, TraceListNode* traceLink)
: gcThing(gcThing),
traceLink(traceLink)
{
MOZ_ASSERT(!object->is<JSFunction>());
MOZ_ASSERT(object->isTenured());
MOZ_ASSERT(gcThing->isTenured());
}
ObjectBox::ObjectBox(JSFunction* function, ObjectBox* traceLink)
: object(function),
traceLink(traceLink),
BigIntBox*
TraceListNode::asBigIntBox()
{
MOZ_ASSERT(isBigIntBox());
return static_cast<BigIntBox*>(this);
}
ObjectBox*
TraceListNode::asObjectBox()
{
MOZ_ASSERT(isObjectBox());
return static_cast<ObjectBox*>(this);
}
BigIntBox::BigIntBox(BigInt* bi, TraceListNode* traceLink)
: TraceListNode(bi, traceLink)
{
}
ObjectBox::ObjectBox(JSObject* obj, TraceListNode* traceLink)
: TraceListNode(obj, traceLink),
emitLink(nullptr)
{
MOZ_ASSERT(object->is<JSFunction>());
MOZ_ASSERT(!object()->is<JSFunction>());
}
ObjectBox::ObjectBox(JSFunction* function, TraceListNode* traceLink)
: TraceListNode(function, traceLink),
emitLink(nullptr)
{
MOZ_ASSERT(object()->is<JSFunction>());
MOZ_ASSERT(asFunctionBox()->function() == function);
MOZ_ASSERT(object->isTenured());
}
FunctionBox*
@ -989,16 +1024,17 @@ ObjectBox::asFunctionBox()
}
/* static */ void
ObjectBox::TraceList(JSTracer* trc, ObjectBox* listHead)
TraceListNode::TraceList(JSTracer* trc, TraceListNode* listHead)
{
for (ObjectBox* box = listHead; box; box = box->traceLink)
box->trace(trc);
for (TraceListNode* node = listHead; node; node = node->traceLink) {
node->trace(trc);
}
}
void
ObjectBox::trace(JSTracer* trc)
TraceListNode::trace(JSTracer* trc)
{
TraceRoot(trc, &object, "parser.object");
TraceGenericPointerRoot(trc, &gcThing, "parser.traceListNode");
}
void

View file

@ -12,6 +12,7 @@
#include "builtin/ModuleObject.h"
#include "frontend/TokenStream.h"
#include "vm/BigIntType.h"
namespace js {
namespace frontend {
@ -20,6 +21,7 @@ class ParseContext;
class FullParseHandler;
class FunctionBox;
class ObjectBox;
class BigIntBox;
#define FOR_EACH_PARSE_NODE_KIND(F) \
F(NOP) \
@ -53,6 +55,7 @@ class ObjectBox;
F(OBJECT_PROPERTY_NAME) \
F(COMPUTED_NAME) \
F(NUMBER) \
F(BIGINT) \
F(STRING) \
F(TEMPLATE_STRING_LIST) \
F(TEMPLATE_STRING) \
@ -524,6 +527,8 @@ IsTypeofKind(ParseNodeKind kind)
* regexp: RegExp model object
* PNK_NUMBER (NumericLiteral)
* value: double value of numeric literal
* PNK_BIGINT (BigIntLiteral)
* box: BigIntBox holding BigInt* value
* PNK_TRUE, PNK_FALSE (BooleanLiteral)
* pn_op: JSOp bytecode
* PNK_NULL (NullLiteral)
@ -571,6 +576,7 @@ enum ParseNodeArity
PN_LIST, /* generic singly linked list */
PN_NAME, /* name, label, string */
PN_NUMBER, /* numeric literal */
PN_BIGINT, /* BigInt literal */
PN_REGEXP, /* regexp literal */
PN_LOOP, /* loop control (break/continue) */
PN_SCOPE /* lexical scope */
@ -613,6 +619,7 @@ enum ParseNodeArity
macro(RawUndefinedLiteral, RawUndefinedLiteralType, asRawUndefinedLiteral) \
\
macro(NumericLiteral, NumericLiteralType, asNumericLiteral) \
macro(BigIntLiteral, BigIntLiteralType, asBigIntLiteral) \
\
macro(RegExpLiteral, RegExpLiteralType, asRegExpLiteral) \
\
@ -828,6 +835,11 @@ class ParseNode
double value; /* aligned numeric literal value */
DecimalPoint decimalPoint; /* Whether the number has a decimal point */
} number;
struct {
private:
friend class BigIntLiteral;
BigIntBox* box;
} bigint;
class {
private:
friend class LoopControlStatement;
@ -849,6 +861,7 @@ class ParseNode
/* True if pn is a parsenode representing a literal constant. */
bool isLiteral() const {
return isKind(PNK_NUMBER) ||
isKind(PNK_BIGINT) ||
isKind(PNK_STRING) ||
isKind(PNK_TRUE) ||
isKind(PNK_FALSE) ||
@ -1631,6 +1644,30 @@ class NumericLiteral : public ParseNode
}
};
class BigIntLiteral : public ParseNode
{
public:
BigIntLiteral(BigIntBox* bibox, const TokenPos& pos)
: ParseNode(PNK_BIGINT, JSOP_NOP, PN_BIGINT, pos)
{
pn_u.bigint.box = bibox;
}
static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_BIGINT);
MOZ_ASSERT_IF(match, node.isArity(PN_BIGINT));
return match;
}
#ifdef DEBUG
void dump(int indent);
#endif
BigIntBox* box() const {
return pn_u.bigint.box;
}
};
class LexicalScopeNode : public ParseNode
{
public:
@ -2350,25 +2387,48 @@ ParseNode::isConstant()
}
}
class ObjectBox
class TraceListNode
{
public:
JSObject* object;
protected:
js::gc::Cell* gcThing;
TraceListNode* traceLink;
TraceListNode(js::gc::Cell* gcThing, TraceListNode* traceLink);
bool isBigIntBox() const { return gcThing->is<BigInt>(); }
bool isObjectBox() const { return gcThing->is<JSObject>(); }
BigIntBox* asBigIntBox();
ObjectBox* asObjectBox();
ObjectBox(JSObject* object, ObjectBox* traceLink);
bool isFunctionBox() { return object->is<JSFunction>(); }
FunctionBox* asFunctionBox();
virtual void trace(JSTracer* trc);
static void TraceList(JSTracer* trc, ObjectBox* listHead);
public:
static void TraceList(JSTracer* trc, TraceListNode* listHead);
};
class BigIntBox : public TraceListNode
{
public:
BigIntBox(BigInt* bi, TraceListNode* link);
BigInt* value() const { return gcThing->as<BigInt>(); }
};
class ObjectBox : public TraceListNode
{
protected:
friend struct CGObjectList;
ObjectBox* traceLink;
ObjectBox* emitLink;
ObjectBox(JSFunction* function, TraceListNode* link);
ObjectBox(JSFunction* function, ObjectBox* traceLink);
public:
ObjectBox(JSObject* obj, TraceListNode* link);
JSObject* object() const { return gcThing->as<JSObject>(); }
bool isFunctionBox() const { return object()->is<JSFunction>(); }
FunctionBox* asFunctionBox();
};
enum ParseReportKind

View file

@ -438,7 +438,7 @@ UsedNameTracker::rewind(RewindToken token)
r.front().value().resetToScope(token.scriptId, token.scopeId);
}
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead,
FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, TraceListNode* traceListHead,
JSFunction* fun, uint32_t toStringStart,
Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
@ -882,11 +882,11 @@ Parser<FullParseHandler>::setAwaitHandling(AwaitHandling awaitHandling)
parser->setAwaitHandling(awaitHandling);
}
template <typename ParseHandler>
ObjectBox*
Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename BoxT, typename ArgT>
BoxT*
ParserBase::newTraceListNode(ArgT* arg)
{
MOZ_ASSERT(obj);
MOZ_ASSERT(arg);
/*
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them
@ -896,15 +896,27 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
* function.
*/
ObjectBox* objbox = alloc.new_<ObjectBox>(obj, traceListHead);
if (!objbox) {
BoxT* box = alloc.template new_<BoxT>(arg, traceListHead);
if (!box) {
ReportOutOfMemory(context);
return nullptr;
}
traceListHead = objbox;
traceListHead = box;
return objbox;
return box;
}
ObjectBox*
ParserBase::newObjectBox(JSObject* obj)
{
return newTraceListNode<ObjectBox, JSObject>(obj);
}
BigIntBox*
ParserBase::newBigIntBox(BigInt* val)
{
return newTraceListNode<BigIntBox, BigInt>(val);
}
template <typename ParseHandler>
@ -10581,6 +10593,37 @@ Parser<ParseHandler>::newRegExp()
return handler.newRegExp(reobj, pos(), *this);
}
template <>
BigIntLiteral*
Parser<FullParseHandler>::newBigInt()
{
// The token's charBuffer contains the DecimalIntegerLiteral or
// NumericLiteralBase production, and as such does not include the
// BigIntLiteralSuffix (the trailing "n"). Note that NumericLiteralBase
// productions may start with 0[bBoOxX], indicating binary/octal/hex.
const auto& chars = tokenStream.getTokenbuf();
mozilla::Range<const char16_t> source(chars.begin(), chars.length());
BigInt* b = js::ParseBigIntLiteral(context, source);
if (!b) {
return null();
}
// newBigInt immediately puts "b" in a BigIntBox, which is allocated using
// tempLifoAlloc, avoiding any potential GC. Therefore it's OK to pass a
// raw pointer.
return handler.newBigInt(b, pos(), *this);
}
template <>
SyntaxParseHandler::BigIntLiteralType
Parser<SyntaxParseHandler>::newBigInt()
{
// The tokenizer has already checked the syntax of the bigint.
return handler.newBigInt();
}
template <typename ParseHandler>
void
Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
@ -11476,6 +11519,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
case TOK_NUMBER:
return newNumber(tokenStream.currentToken());
case TOK_BIGINT:
return newBigInt();
case TOK_TRUE:
return handler.newBooleanLiteral(true, pos());
case TOK_FALSE:

View file

@ -779,8 +779,8 @@ class ParserBase : public StrictModeGetter
TokenStream tokenStream;
LifoAlloc::Mark tempPoolMark;
/* list of parsed objects for GC tracing */
ObjectBox* traceListHead;
/* list of parsed objects and BigInts for GC tracing */
TraceListNode* traceListHead;
/* innermost parse context (stack-allocated) */
ParseContext* pc;
@ -915,6 +915,13 @@ class ParserBase : public StrictModeGetter
bool warnOnceAboutExprClosure();
bool warnOnceAboutForEach();
ObjectBox* newObjectBox(JSObject* obj);
BigIntBox* newBigIntBox(BigInt* val);
private:
template <typename BoxT, typename ArgT>
BoxT* newTraceListNode(ArgT* arg);
protected:
enum InvokedPrediction { PredictUninvoked = false, PredictInvoked = true };
enum ForInitLocation { InForInit, NotInForInit };
@ -1085,7 +1092,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
{
friend class Parser;
LifoAlloc::Mark mark;
ObjectBox* traceListHead;
TraceListNode* traceListHead;
};
Mark mark() const {
Mark m;
@ -1174,7 +1181,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
* Allocate a new parsed object or function container from
* cx->tempLifoAlloc.
*/
ObjectBox* newObjectBox(JSObject* obj);
public:
FunctionBox* newFunctionBox(FunctionNodeType funNode, JSFunction* fun, uint32_t toStringStart,
Directives directives,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
@ -1660,6 +1667,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
const mozilla::Maybe<DeclarationKind>& maybeDecl, ListNodeType literal);
ListNodeType arrayInitializer(YieldHandling yieldHandling, PossibleError* possibleError);
RegExpLiteralType newRegExp();
BigIntLiteralType newBigInt();
ListNodeType objectLiteral(YieldHandling yieldHandling, PossibleError* possibleError);

View file

@ -443,7 +443,7 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags;
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* traceListHead, JSFunction* fun,
FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, TraceListNode* traceListHead, JSFunction* fun,
uint32_t toStringStart, Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
@ -467,7 +467,8 @@ class FunctionBox : public ObjectBox, public SharedContext
void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
ObjectBox* toObjectBox() override { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
JSFunction* function() const { return &object()->as<JSFunction>(); }
void clobberFunction(JSFunction* function) { gcThing = function; }
Scope* compilationEnclosingScope() const override {
// This method is used to distinguish the outermost SharedContext. If

View file

@ -224,6 +224,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
}
NumericLiteralType newNumber(double value, DecimalPoint decimalPoint, const TokenPos& pos) { return NodeGeneric; }
BigIntLiteralType newBigInt() { return NodeGeneric; }
BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) { return NodeGeneric; }
NameNodeType newStringLiteral(JSAtom* atom, const TokenPos& pos) {

View file

@ -74,6 +74,7 @@
macro(PRIVATE_NAME, "private identifier") \
macro(NUMBER, "numeric literal") \
macro(STRING, "string literal") \
macro(BIGINT, "bigint literal") \
\
/* start of template literal with substitutions */ \
macro(TEMPLATE_HEAD, "'${'") \

View file

@ -1382,6 +1382,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
const char16_t* identStart;
NameVisibility identVisibility;
bool hadUnicodeEscape;
bool isBigInt = false;
// Check if in the middle of a template string. Have to get this out of
// the way first.
@ -1619,6 +1620,10 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
} while (true);
}
if (c == 'n') {
isBigInt = true;
c = getCharIgnoreEOL();
}
ungetCharIgnoreEOL(c);
if (c != EOF) {
@ -1638,6 +1643,19 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
}
if (isBigInt) {
size_t length = userbuf.addressOfNextRawChar() - numStart - 1;
tokenbuf.clear();
if(!tokenbuf.reserve(length > 0 ? length : 1))
goto error;
if(length > 0)
tokenbuf.infallibleAppend(numStart, length);
else
tokenbuf.infallibleAppend("0", 1);
tp->type = TOK_BIGINT;
goto out;
}
// Unlike identifiers and strings, numbers cannot contain escaped
// chars, so we don't need to use tokenbuf. Instead we can just
// convert the char16_t characters in userbuf to the numeric value.
@ -1677,7 +1695,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
//
if (c1kind == BasePrefix) {
tp = newToken(-1);
int radix;
int radix = 10;
c = getCharIgnoreEOL();
if (c == 'x' || c == 'X') {
radix = 16;
@ -1777,6 +1795,10 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
hasExp = false;
goto decimal_rest;
}
if (c == 'n') {
isBigInt = true;
c = getCharIgnoreEOL();
}
ungetCharIgnoreEOL(c);
if (c != EOF) {
@ -1796,6 +1818,28 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
}
}
if (isBigInt) {
size_t length = userbuf.addressOfNextRawChar() - numStart - 1;
tokenbuf.clear();
if(!tokenbuf.reserve(radix == 10 ? length : (length + 2)))
goto error;
switch(radix)
{
case 2:
tokenbuf.infallibleAppend("0b", 2);
break;
case 8:
tokenbuf.infallibleAppend("0o", 2);
break;
case 16:
tokenbuf.infallibleAppend("0x", 2);
break;
}
tokenbuf.infallibleAppend(numStart, length);
tp->type = TOK_BIGINT;
goto out;
}
double dval;
const char16_t* dummy;
if (!GetPrefixInteger(cx, numStart, userbuf.addressOfNextRawChar(), radix,

View file

@ -14,6 +14,7 @@
#include "gc/Zone.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
#include "vm/BigIntType.h"
namespace js {
namespace gc {
@ -71,6 +72,7 @@ struct MovingTracer : JS::CallbackTracer
void onObjectEdge(JSObject** objp) override;
void onShapeEdge(Shape** shapep) override;
void onStringEdge(JSString** stringp) override;
void onBigIntEdge(JS::BigInt** bip) override;
void onScriptEdge(JSScript** scriptp) override;
void onLazyScriptEdge(LazyScript** lazyp) override;
void onBaseShapeEdge(BaseShape** basep) override;

View file

@ -113,6 +113,7 @@ enum class AllocKind {
FAT_INLINE_ATOM,
ATOM,
SYMBOL,
BIGINT,
JITCODE,
SCOPE,
REGEXP_SHARED,
@ -153,6 +154,7 @@ enum class AllocKind {
D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom) \
D(ATOM, String, js::NormalAtom, js::NormalAtom) \
D(SYMBOL, Symbol, JS::Symbol, JS::Symbol) \
D(BIGINT, BigInt, JS::BigInt, JS::BigInt) \
D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode) \
D(SCOPE, Scope, js::Scope, js::Scope) \
D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared)

View file

@ -21,6 +21,7 @@
#include "js/SliceBudget.h"
#include "vm/ArgumentsObject.h"
#include "vm/ArrayObject.h"
#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/Scope.h"
@ -875,6 +876,7 @@ js::GCMarker::markAndTraceChildren(T* thing)
namespace js {
template <> void GCMarker::traverse(BaseShape* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(JS::Symbol* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(JS::BigInt* thing) { markAndTraceChildren(thing); }
template <> void GCMarker::traverse(RegExpShared* thing) { markAndTraceChildren(thing); }
} // namespace js
@ -1458,6 +1460,12 @@ js::GCMarker::lazilyMarkChildren(ObjectGroup* group)
traverseEdge(group, static_cast<JSObject*>(fun));
}
void
JS::BigInt::traceChildren(JSTracer* trc)
{
return;
}
struct TraverseObjectFunctor
{
template <typename T>
@ -1704,6 +1712,8 @@ GCMarker::processMarkStackTop(SliceBudget& budget)
}
} else if (v.isSymbol()) {
traverseEdge(obj, v.toSymbol());
} else if (v.isBigInt()) {
traverseEdge(obj, v.toBigInt());
} else if (v.isPrivateGCThing()) {
traverseEdge(obj, v.toGCCellPtr());
}

View file

@ -425,6 +425,7 @@ struct RewrapTaggedPointer{};
DECLARE_REWRAP(JS::Value, JSObject, JS::ObjectOrNullValue, );
DECLARE_REWRAP(JS::Value, JSString, JS::StringValue, );
DECLARE_REWRAP(JS::Value, JS::Symbol, JS::SymbolValue, );
DECLARE_REWRAP(JS::Value, JS::BigInt, JS::BigIntValue, );
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, );
@ -435,7 +436,8 @@ 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 &&
!mozilla::IsBaseOf<JS::BigInt, T>::value, T>
{
static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
"T must not be Cell or TenuredCell");

View file

@ -20,6 +20,7 @@
#include "gc/Marking.h"
#include "gc/Zone.h"
#include "vm/BigIntType.h"
#include "vm/Shape.h"
#include "vm/Symbol.h"
@ -319,6 +320,10 @@ JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing,
name = "symbol";
break;
case JS::TraceKind::BigInt:
name = "BigInt";
break;
case JS::TraceKind::BaseShape:
name = "base_shape";
break;

View file

@ -165,6 +165,15 @@ class jsvalTypeCache(object):
self.NULL = d['JSVAL_TYPE_NULL']
self.OBJECT = d['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'))
@ -206,6 +215,8 @@ class jsval_layout(object):
value = self.box.as_address().cast(self.cache.JSString_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()'
elif tag == self.jtc.NULL:
return 'JSVAL_NULL'
elif tag == self.jtc.OBJECT:

View file

@ -1,6 +1,8 @@
#include "gdb-tests.h"
#include "jsapi.h"
#include "vm/BigIntType.h"
FRAGMENT(jsval, simple) {
using namespace JS;
@ -17,6 +19,7 @@ FRAGMENT(jsval, simple) {
RootedString hello(cx, JS_NewStringCopyZ(cx, "Hello!"));
RootedValue friendly_string(cx, StringValue(hello));
RootedValue symbol(cx, SymbolValue(GetSymbolFor(cx, hello)));
RootedValue bi(cx, BigIntValue(BigInt::zero(cx)));
RootedValue global(cx);
global.setObject(*CurrentGlobalOrNull(cx));
@ -36,5 +39,6 @@ FRAGMENT(jsval, simple) {
(void) empty_string;
(void) friendly_string;
(void) symbol;
(void) bi;
(void) global;
}

View file

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

View file

@ -1958,6 +1958,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
case Bailout_NonObjectInput:
case Bailout_NonStringInput:
case Bailout_NonSymbolInput:
case Bailout_NonBigIntInput:
case Bailout_UnexpectedSimdInput:
case Bailout_NonSharedTypedArrayInput:
case Bailout_Debugger:

View file

@ -710,6 +710,9 @@ BaselineCacheIRCompiler::emitGuardType()
case JSVAL_TYPE_SYMBOL:
masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
break;
case JSVAL_TYPE_BIGINT:
masm.branchTestBigInt(Assembler::NotEqual, input, failure->label());
break;
case JSVAL_TYPE_DOUBLE:
masm.branchTestNumber(Assembler::NotEqual, input, failure->label());
break;

View file

@ -1620,6 +1620,13 @@ BaselineCompiler::emit_JSOP_DOUBLE()
return true;
}
bool
BaselineCompiler::emit_JSOP_BIGINT()
{
frame.push(script->getConst(GET_UINT32_INDEX(pc)));
return true;
}
bool
BaselineCompiler::emit_JSOP_STRING()
{

View file

@ -65,6 +65,7 @@ namespace jit {
_(JSOP_UINT16) \
_(JSOP_UINT24) \
_(JSOP_DOUBLE) \
_(JSOP_BIGINT) \
_(JSOP_STRING) \
_(JSOP_SYMBOL) \
_(JSOP_OBJECT) \

View file

@ -8093,6 +8093,10 @@ ICTypeOf_Typed::Compiler::generateStubCode(MacroAssembler& masm)
masm.branchTestSymbol(Assembler::NotEqual, R0, &failure);
break;
case JSTYPE_BIGINT:
masm.branchTestBigInt(Assembler::NotEqual, R0, &failure);
break;
default:
MOZ_CRASH("Unexpected type");
}

View file

@ -446,6 +446,9 @@ GetPropIRGenerator::tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId
} else if (val_.isSymbol()) {
primitiveType = JSVAL_TYPE_SYMBOL;
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Symbol));
} else if (val_.isBigInt()) {
primitiveType = JSVAL_TYPE_BIGINT;
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_BigInt));
} else {
MOZ_ASSERT(val_.isNullOrUndefined() || val_.isMagic());
return true;

View file

@ -526,9 +526,11 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand& value,
bool mightBeString = valueMIR->mightBeType(MIRType::String);
bool mightBeSymbol = valueMIR->mightBeType(MIRType::Symbol);
bool mightBeDouble = valueMIR->mightBeType(MIRType::Double);
bool mightBeBigInt = valueMIR->mightBeType(MIRType::BigInt);
int tagCount = int(mightBeUndefined) + int(mightBeNull) +
int(mightBeBoolean) + int(mightBeInt32) + int(mightBeObject) +
int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble);
int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble) +
int(mightBeBigInt);;
MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0);
@ -618,6 +620,20 @@ CodeGenerator::testValueTruthyKernel(const ValueOperand& value,
--tagCount;
}
if (mightBeBigInt) {
MOZ_ASSERT(tagCount != 0);
Label notBigInt;
if (tagCount != 1) {
masm.branchTestBigInt(Assembler::NotEqual, tag, &notBigInt);
}
masm.branchTestBigIntTruthy(false, value, ifFalsy);
if (tagCount != 1) {
masm.jump(ifTruthy);
}
masm.bind(&notBigInt);
--tagCount;
}
if (mightBeSymbol) {
// All symbols are truthy.
MOZ_ASSERT(tagCount != 0);
@ -954,8 +970,15 @@ CodeGenerator::visitValueToString(LValueToString* lir)
}
// Symbol
if (lir->mir()->input()->mightBeType(MIRType::Symbol))
if (lir->mir()->input()->mightBeType(MIRType::Symbol)) {
masm.branchTestSymbol(Assembler::Equal, tag, ool->entry());
}
// BigInt
if (lir->mir()->input()->mightBeType(MIRType::BigInt)) {
// No fastpath currently implemented.
masm.branchTestBigInt(Assembler::Equal, tag, ool->entry());
}
#ifdef DEBUG
masm.assumeUnreachable("Unexpected type for MValueToString.");
@ -4902,10 +4925,11 @@ CodeGenerator::branchIfInvalidated(Register temp, Label* invalidated)
}
void
CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset)
CodeGenerator::emitAssertGCThingResult(Register input, MIRType type, const TemporaryTypeSet* typeset)
{
MOZ_ASSERT(type == MIRType::Object || type == MIRType::ObjectOrNull ||
type == MIRType::String || type == MIRType::Symbol);
type == MIRType::String || type == MIRType::Symbol ||
type == MIRType::BigInt);
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
regs.take(input);
@ -4960,6 +4984,9 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, cons
case MIRType::Symbol:
callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidSymbolPtr);
break;
case MIRType::BigInt:
callee = JS_FUNC_TO_DATA_PTR(void*, AssertValidBigIntPtr);
break;
default:
MOZ_CRASH();
}
@ -5029,7 +5056,7 @@ CodeGenerator::emitAssertResultV(const ValueOperand input, const TemporaryTypeSe
#ifdef DEBUG
void
CodeGenerator::emitObjectOrStringResultChecks(LInstruction* lir, MDefinition* mir)
CodeGenerator::emitGCThingResultChecks(LInstruction* lir, MDefinition* mir)
{
if (lir->numDefs() == 0)
return;
@ -5037,7 +5064,7 @@ CodeGenerator::emitObjectOrStringResultChecks(LInstruction* lir, MDefinition* mi
MOZ_ASSERT(lir->numDefs() == 1);
Register output = ToRegister(lir->getDef(0));
emitAssertObjectOrStringResult(output, mir->type(), mir->resultTypeSet());
emitAssertGCThingResult(output, mir->type(), mir->resultTypeSet());
}
void
@ -5069,7 +5096,8 @@ CodeGenerator::emitDebugResultChecks(LInstruction* ins)
case MIRType::ObjectOrNull:
case MIRType::String:
case MIRType::Symbol:
emitObjectOrStringResultChecks(ins, mir);
case MIRType::BigInt:
emitGCThingResultChecks(ins, mir);
break;
case MIRType::Value:
emitValueResultChecks(ins, mir);
@ -10306,7 +10334,7 @@ CodeGenerator::visitThrow(LThrow* lir)
callVM(ThrowInfoCodeGen, lir);
}
typedef bool (*BitNotFn)(JSContext*, HandleValue, int* p);
typedef bool (*BitNotFn)(JSContext*, MutableHandleValue, MutableHandleValue);
static const VMFunction BitNotInfo = FunctionInfo<BitNotFn>(BitNot, "BitNot");
void
@ -10316,7 +10344,7 @@ CodeGenerator::visitBitNotV(LBitNotV* lir)
callVM(BitNotInfo, lir);
}
typedef bool (*BitopFn)(JSContext*, HandleValue, HandleValue, int* p);
typedef bool (*BitopFn)(JSContext*, MutableHandleValue, MutableHandleValue, MutableHandleValue);
static const VMFunction BitAndInfo = FunctionInfo<BitopFn>(BitAnd, "BitAnd");
static const VMFunction BitOrInfo = FunctionInfo<BitopFn>(BitOr, "BitOr");
static const VMFunction BitXorInfo = FunctionInfo<BitopFn>(BitXor, "BitXor");
@ -10386,9 +10414,11 @@ CodeGenerator::visitTypeOfV(LTypeOfV* lir)
bool testNull = input->mightBeType(MIRType::Null);
bool testString = input->mightBeType(MIRType::String);
bool testSymbol = input->mightBeType(MIRType::Symbol);
bool testBigInt = input->mightBeType(MIRType::BigInt);
unsigned numTests = unsigned(testObject) + unsigned(testNumber) + unsigned(testBoolean) +
unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol);
unsigned(testUndefined) + unsigned(testNull) + unsigned(testString) + unsigned(testSymbol) +
unsigned(testBigInt);
MOZ_ASSERT_IF(!input->emptyResultTypeSet(), numTests > 0);
@ -10484,6 +10514,19 @@ CodeGenerator::visitTypeOfV(LTypeOfV* lir)
numTests--;
}
if (testBigInt) {
Label notBigInt;
if (numTests > 1) {
masm.branchTestBigInt(Assembler::NotEqual, tag, &notBigInt);
}
masm.movePtr(ImmGCPtr(names.bigint), output);
if (numTests > 1) {
masm.jump(&done);
}
masm.bind(&notBigInt);
numTests--;
}
MOZ_ASSERT(numTests == 0);
masm.bind(&done);
@ -11794,7 +11837,7 @@ CodeGenerator::visitAssertResultT(LAssertResultT* ins)
Register input = ToRegister(ins->input());
MDefinition* mir = ins->mirRaw();
emitAssertObjectOrStringResult(input, mir->type(), mir->resultTypeSet());
emitAssertGCThingResult(input, mir->type(), mir->resultTypeSet());
}
void

View file

@ -431,7 +431,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitAssertResultV(LAssertResultV* ins);
void visitAssertResultT(LAssertResultT* ins);
void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
void emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
void emitAssertGCThingResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
void visitInterruptCheck(LInterruptCheck* lir);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
@ -571,7 +571,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
#ifdef DEBUG
void emitDebugResultChecks(LInstruction* ins);
void emitObjectOrStringResultChecks(LInstruction* lir, MDefinition* mir);
void emitGCThingResultChecks(LInstruction* lir, MDefinition* mir);
void emitValueResultChecks(LInstruction* lir, MDefinition* mir);
#endif

View file

@ -2611,6 +2611,7 @@ IsResumableMIRType(MIRType type)
case MIRType::Float32:
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::Object:
case MIRType::MagicOptimizedArguments:
case MIRType::MagicOptimizedOut:

View file

@ -721,6 +721,9 @@ IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry, jsbytecode* start, jsbytecod
case JSOP_NEG:
type = inspector->expectedResultType(last);
break;
case JSOP_BIGINT:
type = MIRType::BigInt;
break;
default:
break;
}
@ -1347,6 +1350,7 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_,
case MIRType::Double:
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::Object:
if (type != def->type()) {
MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible);
@ -1765,6 +1769,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_compare(op);
case JSOP_DOUBLE:
case JSOP_BIGINT:
pushConstant(info().getConst(pc));
return true;
@ -4760,8 +4765,10 @@ IonBuilder::bitnotTrySpecialized(bool* emitted, MDefinition* input)
// Try to emit a specialized bitnot instruction based on the input type
// of the operand.
if (input->mightBeType(MIRType::Object) || input->mightBeType(MIRType::Symbol))
if (input->mightBeType(MIRType::Object) || input->mightBeType(MIRType::Symbol) ||
input->mightBeType(MIRType::BigInt)) {
return true;
}
MBitNot* ins = MBitNot::New(alloc(), input);
ins->setSpecialization(MIRType::Int32);
@ -7209,6 +7216,7 @@ ObjectOrSimplePrimitive(MDefinition* op)
// Return true if op is either undefined/null/boolean/int32 or an object.
return !op->mightBeType(MIRType::String)
&& !op->mightBeType(MIRType::Symbol)
&& !op->mightBeType(MIRType::BigInt)
&& !op->mightBeType(MIRType::Double)
&& !op->mightBeType(MIRType::Float32)
&& !op->mightBeType(MIRType::MagicOptimizedArguments)
@ -8348,6 +8356,10 @@ IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id)
key = JSProto_Symbol;
break;
case MIRType::BigInt:
key = JSProto_BigInt;
break;
case MIRType::Int32:
case MIRType::Double:
key = JSProto_Number;

View file

@ -103,6 +103,7 @@ enum BailoutKind
Bailout_NonObjectInput,
Bailout_NonStringInput,
Bailout_NonSymbolInput,
Bailout_NonBigIntInput,
// SIMD Unbox expects a given type, bails out if it doesn't match.
Bailout_UnexpectedSimdInput,
@ -212,6 +213,8 @@ BailoutKindString(BailoutKind kind)
return "Bailout_NonStringInput";
case Bailout_NonSymbolInput:
return "Bailout_NonSymbolInput";
case Bailout_NonBigIntInput:
return "Bailout_NonBigIntInput";
case Bailout_UnexpectedSimdInput:
return "Bailout_UnexpectedSimdInput";
case Bailout_NonSharedTypedArrayInput:
@ -412,6 +415,7 @@ enum class MIRType
// Types above have trivial conversion to a number.
String,
Symbol,
BigInt,
// Types above are primitive (including undefined and null).
Object,
MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value.
@ -496,6 +500,8 @@ MIRTypeFromValueType(JSValueType type)
return MIRType::String;
case JSVAL_TYPE_SYMBOL:
return MIRType::Symbol;
case JSVAL_TYPE_BIGINT:
return MIRType::BigInt;
case JSVAL_TYPE_BOOLEAN:
return MIRType::Boolean;
case JSVAL_TYPE_NULL:
@ -528,6 +534,8 @@ ValueTypeFromMIRType(MIRType type)
return JSVAL_TYPE_STRING;
case MIRType::Symbol:
return JSVAL_TYPE_SYMBOL;
case MIRType::BigInt:
return JSVAL_TYPE_BIGINT;
case MIRType::MagicOptimizedArguments:
case MIRType::MagicOptimizedOut:
case MIRType::MagicHole:
@ -568,6 +576,8 @@ StringFromMIRType(MIRType type)
return "String";
case MIRType::Symbol:
return "Symbol";
case MIRType::BigInt:
return "BigInt";
case MIRType::Object:
return "Object";
case MIRType::MagicOptimizedArguments:

View file

@ -599,6 +599,7 @@ class LDefinition
return LDefinition::INT32;
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::Object:
case MIRType::ObjectOrNull:
return LDefinition::OBJECT;

View file

@ -717,6 +717,10 @@ LIRGenerator::visitTest(MTest* test)
// TestPolicy).
MOZ_ASSERT(opd->type() != MIRType::String);
// BigInt is boxed in type analysis.
MOZ_ASSERT(opd->type() != MIRType::BigInt,
"BigInt should be boxed by TestPolicy");
// Testing a constant.
if (MConstant* constant = opd->maybeConstantValue()) {
bool b;
@ -2149,9 +2153,11 @@ LIRGenerator::visitToInt32(MToInt32* convert)
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::Object:
case MIRType::Undefined:
// Objects might be effectful. Symbols throw. Undefined coerces to NaN, not int32.
// Objects might be effectful. Symbols and BigInts throw. Undefined
// coerces to NaN, not int32.
MOZ_CRASH("ToInt32 invalid input type");
default:
@ -2939,6 +2945,8 @@ LIRGenerator::visitNot(MNot* ins)
// String is converted to length of string in the type analysis phase (see
// TestPolicy).
MOZ_ASSERT(op->type() != MIRType::String);
MOZ_ASSERT(op->type() != MIRType::BigInt,
"BigInt should be boxed by TestPolicy");
// - boolean: x xor 1
// - int32: LCompare(x, 0)

View file

@ -2894,6 +2894,7 @@ IonBuilder::inlineToInteger(CallInfo& callInfo)
if (input->mightBeType(MIRType::Object) ||
input->mightBeType(MIRType::String) ||
input->mightBeType(MIRType::Symbol) ||
input->mightBeType(MIRType::BigInt) ||
input->mightBeType(MIRType::Undefined) ||
input->mightBeMagicType())
{
@ -3021,12 +3022,16 @@ IonBuilder::inlineAtomicsCompareExchange(CallInfo& callInfo)
// These guards are desirable here and in subsequent atomics to
// avoid bad bailouts with MTruncateToInt32, see https://bugzilla.mozilla.org/show_bug.cgi?id=1141986#c20.
MDefinition* oldval = callInfo.getArg(2);
if (oldval->mightBeType(MIRType::Object) || oldval->mightBeType(MIRType::Symbol))
if (oldval->mightBeType(MIRType::Object) || oldval->mightBeType(MIRType::Symbol) ||
oldval->mightBeType(MIRType::BigInt)) {
return InliningStatus_NotInlined;
}
MDefinition* newval = callInfo.getArg(3);
if (newval->mightBeType(MIRType::Object) || newval->mightBeType(MIRType::Symbol))
if (newval->mightBeType(MIRType::Object) || newval->mightBeType(MIRType::Symbol) ||
newval->mightBeType(MIRType::BigInt)) {
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
bool requiresCheck = false;
@ -3063,8 +3068,10 @@ IonBuilder::inlineAtomicsExchange(CallInfo& callInfo)
}
MDefinition* value = callInfo.getArg(2);
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol) ||
value->mightBeType(MIRType::BigInt)) {
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
bool requiresCheck = false;
@ -3151,8 +3158,10 @@ IonBuilder::inlineAtomicsStore(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol) ||
value->mightBeType(MIRType::BigInt)) {
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
bool requiresCheck = false;
@ -3194,8 +3203,10 @@ IonBuilder::inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target)
}
MDefinition* value = callInfo.getArg(2);
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol))
if (value->mightBeType(MIRType::Object) || value->mightBeType(MIRType::Symbol) ||
value->mightBeType(MIRType::BigInt)) {
return InliningStatus_NotInlined;
}
Scalar::Type arrayType;
bool requiresCheck = false;

View file

@ -935,6 +935,9 @@ MConstant::MConstant(const js::Value& vp, CompilerConstraintList* constraints)
case MIRType::Symbol:
payload_.sym = vp.toSymbol();
break;
case MIRType::BigInt:
payload_.bi = vp.toBigInt();
break;
case MIRType::Object:
payload_.obj = &vp.toObject();
// Create a singleton type set for the object. This isn't necessary for
@ -1014,7 +1017,12 @@ MConstant::assertInitializedPayload() const
case MIRType::String:
case MIRType::Object:
case MIRType::Symbol:
case MIRType::BigInt:
#if MOZ_LITTLE_ENDIAN
MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0);
#else
MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits << 32) == 0);
#endif
break;
default:
MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()));
@ -1103,6 +1111,9 @@ MConstant::printOpcode(GenericPrinter& out) const
case MIRType::Symbol:
out.printf("symbol at %p", (void*)toSymbol());
break;
case MIRType::BigInt:
out.printf("BigInt at %p", (void*)toBigInt());
break;
case MIRType::String:
out.printf("string %p", (void*)toString());
break;
@ -1164,6 +1175,8 @@ MConstant::toJSValue() const
return StringValue(toString());
case MIRType::Symbol:
return SymbolValue(toSymbol());
case MIRType::BigInt:
return BigIntValue(toBigInt());
case MIRType::Object:
return ObjectValue(toObject());
case MIRType::MagicOptimizedArguments:
@ -1207,6 +1220,9 @@ MConstant::valueToBoolean(bool* res) const
case MIRType::Symbol:
*res = true;
return true;
case MIRType::BigInt:
*res = !toBigInt()->isZero();
return true;
case MIRType::String:
*res = toString()->length() != 0;
return true;
@ -2199,6 +2215,7 @@ MUnbox::printOpcode(GenericPrinter& out) const
case MIRType::Boolean: out.printf("to Boolean"); break;
case MIRType::String: out.printf("to String"); break;
case MIRType::Symbol: out.printf("to Symbol"); break;
case MIRType::BigInt: out.printf("to BigInt"); break;
case MIRType::Object: out.printf("to Object"); break;
default: break;
}
@ -2591,6 +2608,7 @@ jit::TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes)
case MIRType::Float32:
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::MagicOptimizedArguments:
return types->hasType(TypeSet::PrimitiveType(ValueTypeFromMIRType(input)));
@ -2846,9 +2864,11 @@ void
MBinaryBitwiseInstruction::infer(BaselineInspector*, jsbytecode*)
{
if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(0)->mightBeType(MIRType::Symbol) ||
getOperand(1)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Symbol))
getOperand(1)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Symbol) ||
getOperand(1)->mightBeType(MIRType::BigInt))
{
specialization_ = MIRType::None;
setResultType(MIRType::Value);
} else {
specializeAs(MIRType::Int32);
}
@ -2858,9 +2878,10 @@ void
MBinaryBitwiseInstruction::specializeAs(MIRType type)
{
MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
MOZ_ASSERT(this->type() == type);
MOZ_ASSERT(this->type() == MIRType::Value || this->type() == type);
specialization_ = type;
setResultType(type);
if (isBitOr() || isBitAnd() || isBitXor())
setCommutative();
@ -2870,17 +2891,23 @@ void
MShiftInstruction::infer(BaselineInspector*, jsbytecode*)
{
if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) ||
getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol))
getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol) ||
getOperand(0)->mightBeType(MIRType::BigInt) || getOperand(1)->mightBeType(MIRType::BigInt))
{
specialization_ = MIRType::None;
else
setResultType(MIRType::Value);
} else {
specialization_ = MIRType::Int32;
setResultType(MIRType::Int32);
}
}
void
MUrsh::infer(BaselineInspector* inspector, jsbytecode* pc)
{
if (getOperand(0)->mightBeType(MIRType::Object) || getOperand(1)->mightBeType(MIRType::Object) ||
getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol))
getOperand(0)->mightBeType(MIRType::Symbol) || getOperand(1)->mightBeType(MIRType::Symbol) ||
getOperand(0)->mightBeType(MIRType::BigInt) || getOperand(1)->mightBeType(MIRType::BigInt))
{
specialization_ = MIRType::None;
setResultType(MIRType::Value);
@ -3828,7 +3855,7 @@ MBitNot::NewInt32(TempAllocator& alloc, MDefinition* input)
{
MBitNot* ins = new(alloc) MBitNot(input);
ins->specialization_ = MIRType::Int32;
MOZ_ASSERT(ins->type() == MIRType::Int32);
ins->setResultType(MIRType::Int32);
return ins;
}
@ -3874,6 +3901,9 @@ MTypeOf::foldsTo(TempAllocator& alloc)
case MIRType::Symbol:
type = JSTYPE_SYMBOL;
break;
case MIRType::BigInt:
type = JSTYPE_BIGINT;
break;
case MIRType::Null:
type = JSTYPE_OBJECT;
break;
@ -4453,6 +4483,12 @@ MCompare::tryFoldTypeOf(bool* result)
*result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
return true;
}
}
else if (constant->toString() == TypeName(JSTYPE_BIGINT, names)) {
if (!typeOf->input()->mightBeType(MIRType::BigInt)) {
*result = (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE);
return true;
}
} else if (constant->toString() == TypeName(JSTYPE_OBJECT, names)) {
if (!typeOf->input()->mightBeType(MIRType::Object) &&
!typeOf->input()->mightBeType(MIRType::Null))
@ -5606,6 +5642,8 @@ MConstant::appendRoots(MRootList& roots) const
return roots.append(toString());
case MIRType::Symbol:
return roots.append(toSymbol());
case MIRType::BigInt:
return roots.append(toBigInt());
case MIRType::Object:
return roots.append(&toObject());
case MIRType::Undefined:

View file

@ -1548,6 +1548,7 @@ class MConstant : public MNullaryInstruction
double d;
JSString* str;
JS::Symbol* sym;
BigInt* bi;
JSObject* obj;
uint64_t asBits;
};
@ -1672,6 +1673,10 @@ class MConstant : public MNullaryInstruction
MOZ_ASSERT(type() == MIRType::Symbol);
return payload_.sym;
}
BigInt* toBigInt() const {
MOZ_ASSERT(type() == MIRType::BigInt);
return payload_.bi;
}
JSObject& toObject() const {
MOZ_ASSERT(type() == MIRType::Object);
return *payload_.obj;
@ -4743,6 +4748,7 @@ class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
type == MIRType::Double ||
type == MIRType::String ||
type == MIRType::Symbol ||
type == MIRType::BigInt ||
type == MIRType::Object);
TemporaryTypeSet* resultSet = ins->resultTypeSet();
@ -4781,6 +4787,9 @@ class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data
case MIRType::Symbol:
kind = Bailout_NonSymbolInput;
break;
case MIRType::BigInt:
kind = Bailout_NonBigIntInput;
break;
case MIRType::Object:
kind = Bailout_NonObjectInput;
break;
@ -5189,9 +5198,11 @@ class MToDouble
setMovable();
// An object might have "valueOf", which means it is effectful.
// ToNumber(symbol) throws.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
// ToNumber(symbol) and ToNumber(bigint) throw.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol) ||
def->mightBeType(MIRType::BigInt)) {
setGuard();
}
}
public:
@ -5226,11 +5237,15 @@ class MToDouble
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
if (input()->type() == MIRType::Value)
if (input()->type() == MIRType::Value) {
return false;
if (input()->type() == MIRType::Symbol)
}
if (input()->type() == MIRType::Symbol) {
return false;
}
if (input()->type() == MIRType::BigInt) {
return false;
}
return true;
}
@ -5253,9 +5268,11 @@ class MToFloat32
setMovable();
// An object might have "valueOf", which means it is effectful.
// ToNumber(symbol) throws.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
// ToNumber(symbol) and ToNumber(BigInt) throw.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol) ||
def->mightBeType(MIRType::BigInt)) {
setGuard();
}
}
explicit MToFloat32(MDefinition* def, bool mustPreserveNaN)
@ -5537,9 +5554,11 @@ class MToInt32
setMovable();
// An object might have "valueOf", which means it is effectful.
// ToNumber(symbol) throws.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
// ToInt32(symbol) and ToInt32(BigInt) throw.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol) ||
def->mightBeType(MIRType::BigInt)) {
setGuard();
}
}
public:
@ -5594,9 +5613,11 @@ class MTruncateToInt32
setMovable();
// An object might have "valueOf", which means it is effectful.
// ToInt32(symbol) throws.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
// ToInt32(symbol) and ToInt32(BigInt) throw.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol) ||
def->mightBeType(MIRType::BigInt)) {
setGuard();
}
}
public:
@ -5639,9 +5660,12 @@ class MToString :
setResultType(MIRType::String);
setMovable();
// Objects might override toString and Symbols throw.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol))
// Objects might override toString; Symbol and BigInts throw. We bailout in
// those cases and run side-effects in baseline instead.
if (def->mightBeType(MIRType::Object) || def->mightBeType(MIRType::Symbol) ||
def->mightBeType(MIRType::BigInt)) {
setGuard();
}
}
public:
@ -5701,7 +5725,7 @@ class MBitNot
: MUnaryInstruction(input)
{
specialization_ = MIRType::None;
setResultType(MIRType::Int32);
setResultType(MIRType::Value);
setMovable();
}
@ -5861,7 +5885,7 @@ class MBinaryBitwiseInstruction
maskMatchesRightRange(false)
{
MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64);
setResultType(type);
setResultType(MIRType::Value);
setMovable();
}

View file

@ -545,6 +545,7 @@ MacroAssembler::branchTestMIRType(Condition cond, const Value& val, MIRType type
case MIRType::Int32: return branchTestInt32(cond, val, label);
case MIRType::String: return branchTestString(cond, val, label);
case MIRType::Symbol: return branchTestSymbol(cond, val, label);
case MIRType::BigInt: return branchTestBigInt(cond, val, label);
case MIRType::Object: return branchTestObject(cond, val, label);
case MIRType::Double: return branchTestDouble(cond, val, label);
case MIRType::MagicOptimizedArguments: // Fall through.

View file

@ -45,12 +45,13 @@ MacroAssembler::guardTypeSet(const Source& address, const TypeSet* types, Barrie
MOZ_ASSERT(!types->unknown());
Label matched;
TypeSet::Type tests[8] = {
TypeSet::Type tests[9] = {
TypeSet::Int32Type(),
TypeSet::UndefinedType(),
TypeSet::BooleanType(),
TypeSet::StringType(),
TypeSet::SymbolType(),
TypeSet::BigIntType(),
TypeSet::NullType(),
TypeSet::MagicArgType(),
TypeSet::AnyObjectType()
@ -2736,6 +2737,9 @@ MacroAssembler::maybeBranchTestType(MIRType type, MDefinition* maybeDef, Registe
case MIRType::Symbol:
branchTestSymbol(Equal, tag, label);
break;
case MIRType::BigInt:
branchTestBigInt(Equal, tag, label);
break;
case MIRType::Object:
branchTestObject(Equal, tag, label);
break;

View file

@ -1137,6 +1137,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestBoolean(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestString(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestSymbol(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestBigInt(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestNull(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestObject(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestPrimitive(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
@ -1177,6 +1178,10 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestSymbol(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
inline void branchTestBigInt(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestBigInt(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
inline void branchTestNull(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestNull(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestNull(Condition cond, const ValueOperand& value, Label* label)
@ -1216,6 +1221,8 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH;
inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
inline void branchTestBigIntTruthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
private:
@ -1256,6 +1263,9 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestSymbolImpl(Condition cond, const T& t, Label* label)
DEFINED_ON(arm, arm64, x86_shared);
template <typename T>
inline void branchTestBigIntImpl(Condition cond, const T& t, Label* label)
DEFINED_ON(arm, arm64, x86_shared);
template <typename T>
inline void branchTestNullImpl(Condition cond, const T& t, Label* label)
DEFINED_ON(arm, arm64, x86_shared);
template <typename T>

View file

@ -164,13 +164,13 @@ bool
RBitNot::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue operand(cx, iter.read());
RootedValue result(cx);
int32_t result;
if (!js::BitNot(cx, operand, &result))
if (!js::BitNot(cx, &operand, &result)) {
return false;
}
RootedValue rootedResult(cx, js::Int32Value(result));
iter.storeInstructionResult(rootedResult);
iter.storeInstructionResult(result);
return true;
}
@ -190,14 +190,14 @@ RBitAnd::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
int32_t result;
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitAnd(cx, lhs, rhs, &result))
if (!js::BitAnd(cx, &lhs, &rhs, &result)) {
return false;
}
RootedValue rootedResult(cx, js::Int32Value(result));
iter.storeInstructionResult(rootedResult);
iter.storeInstructionResult(result);
return true;
}
@ -217,14 +217,14 @@ RBitOr::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
int32_t result;
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitOr(cx, lhs, rhs, &result))
if (!js::BitOr(cx, &lhs, &rhs, &result)) {
return false;
}
RootedValue asValue(cx, js::Int32Value(result));
iter.storeInstructionResult(asValue);
iter.storeInstructionResult(result);;
return true;
}
@ -244,13 +244,13 @@ RBitXor::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
int32_t result;
if (!js::BitXor(cx, lhs, rhs, &result))
if (!js::BitXor(cx, &lhs, &rhs, &result)) {
return false;
}
RootedValue rootedResult(cx, js::Int32Value(result));
iter.storeInstructionResult(rootedResult);
iter.storeInstructionResult(result);
return true;
}
@ -270,14 +270,14 @@ RLsh::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
int32_t result;
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
if (!js::BitLsh(cx, lhs, rhs, &result))
if (!js::BitLsh(cx, &lhs, &rhs, &result)) {
return false;
}
RootedValue asValue(cx, js::Int32Value(result));
iter.storeInstructionResult(asValue);
iter.storeInstructionResult(result);
return true;
}
@ -297,14 +297,14 @@ RRsh::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedValue lhs(cx, iter.read());
RootedValue rhs(cx, iter.read());
RootedValue result(cx);
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
int32_t result;
if (!js::BitRsh(cx, lhs, rhs, &result))
if (!js::BitRsh(cx, &lhs, &rhs, &result)) {
return false;
}
RootedValue rootedResult(cx, js::Int32Value(result));
iter.storeInstructionResult(rootedResult);
iter.storeInstructionResult(result);
return true;
}
@ -327,8 +327,9 @@ RUrsh::recover(JSContext* cx, SnapshotIterator& iter) const
MOZ_ASSERT(!lhs.isObject() && !rhs.isObject());
RootedValue result(cx);
if (!js::UrshOperation(cx, lhs, rhs, &result))
if (!js::UrshOperation(cx, &lhs, &rhs, &result)) {
return false;
}
iter.storeInstructionResult(result);
return true;
@ -778,7 +779,7 @@ RPow::recover(JSContext* cx, SnapshotIterator& iter) const
RootedValue result(cx);
MOZ_ASSERT(base.isNumber() && power.isNumber());
if (!js::math_pow_handle(cx, base, power, &result))
if (!js::PowValues(cx, &base, &power, &result))
return false;
iter.storeInstructionResult(result);
@ -805,7 +806,7 @@ RPowHalf::recover(JSContext* cx, SnapshotIterator& iter) const
power.setNumber(0.5);
MOZ_ASSERT(base.isNumber());
if (!js::math_pow_handle(cx, base, power, &result))
if (!js::PowValues(cx, &base, &power, &result))
return false;
iter.storeInstructionResult(result);

View file

@ -942,47 +942,43 @@ DoBinaryArithFallback(JSContext* cx, void* payload, ICBinaryArith_Fallback* stub
return false;
break;
case JSOP_POW:
if (!math_pow_handle(cx, lhsCopy, rhsCopy, ret))
if (!PowValues(cx, &lhsCopy, &rhsCopy, ret))
return false;
break;
case JSOP_BITOR: {
int32_t result;
if (!BitOr(cx, lhs, rhs, &result))
if (!BitOr(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
ret.setInt32(result);
}
break;
}
case JSOP_BITXOR: {
int32_t result;
if (!BitXor(cx, lhs, rhs, &result))
if (!BitXor(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
ret.setInt32(result);
}
break;
}
case JSOP_BITAND: {
int32_t result;
if (!BitAnd(cx, lhs, rhs, &result))
if (!BitAnd(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
ret.setInt32(result);
}
break;
}
case JSOP_LSH: {
int32_t result;
if (!BitLsh(cx, lhs, rhs, &result))
if (!BitLsh(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
ret.setInt32(result);
}
break;
}
case JSOP_RSH: {
int32_t result;
if (!BitRsh(cx, lhs, rhs, &result))
if (!BitRsh(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
ret.setInt32(result);
}
break;
}
case JSOP_URSH: {
if (!UrshOperation(cx, lhs, rhs, ret))
if (!UrshOperation(cx, &lhsCopy, &rhsCopy, ret)) {
return false;
}
break;
}
default:
@ -1475,16 +1471,19 @@ DoUnaryArithFallback(JSContext* cx, void* payload, ICUnaryArith_Fallback* stub_,
switch (op) {
case JSOP_BITNOT: {
int32_t result;
if (!BitNot(cx, val, &result))
RootedValue valCopy(cx, val);
if (!BitNot(cx, &valCopy, res)) {
return false;
res.setInt32(result);
}
break;
}
case JSOP_NEG:
if (!NegOperation(cx, script, pc, val, res))
case JSOP_NEG: {
// We copy val here because the original value is needed below.
RootedValue valCopy(cx, val);
if (!NegOperation(cx, script, pc, &valCopy, res))
return false;
break;
}
default:
MOZ_CRASH("Unexpected op");
}

View file

@ -409,6 +409,8 @@ ValTypeToString(JSValueType type)
return "string";
case JSVAL_TYPE_SYMBOL:
return "symbol";
case JSVAL_TYPE_BIGINT:
return "BigInt";
case JSVAL_TYPE_BOOLEAN:
return "boolean";
case JSVAL_TYPE_OBJECT:

View file

@ -700,7 +700,8 @@ ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
case MIRType::Object:
case MIRType::String:
case MIRType::Symbol:
// Objects might be effectful. Symbols give TypeError.
case MIRType::BigInt:
// Objects might be effectful. Symbols and BigInts give TypeError.
break;
default:
break;
@ -748,7 +749,8 @@ ToInt32Policy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
case MIRType::Object:
case MIRType::String:
case MIRType::Symbol:
// Objects might be effectful. Symbols give TypeError.
case MIRType::BigInt:
// Objects might be effectful. Symbols and BigInts give TypeError.
break;
default:
break;
@ -765,7 +767,8 @@ ToStringPolicy::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
MOZ_ASSERT(ins->isToString());
MIRType type = ins->getOperand(0)->type();
if (type == MIRType::Object || type == MIRType::Symbol) {
if (type == MIRType::Object || type == MIRType::Symbol ||
type == MIRType::BigInt) {
ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
return true;
}
@ -955,6 +958,7 @@ StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc, MInstruction* i
case MIRType::Object:
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
value = BoxAt(alloc, ins, value);
break;
default:

View file

@ -1236,15 +1236,27 @@ AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym)
MOZ_ASSERT(sym->getAllocKind() == gc::AllocKind::SYMBOL);
}
void
AssertValidBigIntPtr(JSContext* cx, JS::BigInt* bi) {
// FIXME: check runtime?
MOZ_ASSERT(cx->zone() == bi->zone());
MOZ_ASSERT(bi->isAligned());
MOZ_ASSERT(bi->isTenured());
MOZ_ASSERT(bi->getAllocKind() == gc::AllocKind::BIGINT);
}
void
AssertValidValue(JSContext* cx, Value* v)
{
if (v->isObject())
if (v->isObject()) {
AssertValidObjectPtr(cx, &v->toObject());
else if (v->isString())
} else if (v->isString()) {
AssertValidStringPtr(cx, v->toString());
else if (v->isSymbol())
} else if (v->isSymbol()) {
AssertValidSymbolPtr(cx, v->toSymbol());
} else if (v->isBigInt()) {
AssertValidBigIntPtr(cx, v->toBigInt());
}
}
bool

View file

@ -751,6 +751,7 @@ void AssertValidObjectPtr(JSContext* cx, JSObject* obj);
void AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj);
void AssertValidStringPtr(JSContext* cx, JSString* str);
void AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym);
void AssertValidBigIntPtr(JSContext* cx, JS::BigInt* bi);
void AssertValidValue(JSContext* cx, Value* v);
void MarkValueFromIon(JSRuntime* rt, Value* vp);

View file

@ -1880,6 +1880,29 @@ MacroAssembler::branchTestSymbolImpl(Condition cond, const T& t, Label* label)
ma_b(label, c);
}
void MacroAssembler::branchTestBigInt(Condition cond, Register tag, Label* label) {
branchTestBigIntImpl(cond, tag, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const BaseIndex& address, Label* label) {
branchTestBigIntImpl(cond, address, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value, Label* label) {
branchTestBigIntImpl(cond, value, label);
}
template <typename T>
void MacroAssembler::branchTestBigIntImpl(Condition cond, const T& t, Label* label) {
Condition c = testBigInt(cond, t);
ma_b(label, c);
}
void MacroAssembler::branchTestBigIntTruthy(bool truthy, const ValueOperand& value, Label* label) {
Condition c = testBigIntTruthy(truthy, value);
ma_b(label, c);
}
void
MacroAssembler::branchTestNull(Condition cond, Register tag, Label* label)
{

View file

@ -2717,6 +2717,11 @@ MacroAssemblerARMCompat::testSymbol(Assembler::Condition cond, const ValueOperan
return testSymbol(cond, value.typeReg());
}
Assembler::Condition MacroAssemblerARMCompat::testBigInt(Assembler::Condition cond, const ValueOperand& value)
{
return testBigInt(cond, value.typeReg());
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Assembler::Condition cond, const ValueOperand& value)
{
@ -2790,6 +2795,13 @@ MacroAssemblerARMCompat::testSymbol(Assembler::Condition cond, Register tag)
return cond;
}
Assembler::Condition MacroAssemblerARMCompat::testBigInt(Assembler::Condition cond, Register tag)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ma_cmp(tag, ImmTag(JSVAL_TAG_BIGINT));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Assembler::Condition cond, Register tag)
{
@ -2907,6 +2919,14 @@ MacroAssemblerARMCompat::testObject(Condition cond, const Address& address)
return testObject(cond, scratch);
}
Assembler::Condition MacroAssemblerARMCompat::testBigInt(Condition cond, const Address& address)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ScratchRegisterScope scratch(asMasm());
Register tag = extractTag(address, scratch);
return testBigInt(cond, tag);
}
Assembler::Condition
MacroAssemblerARMCompat::testNumber(Condition cond, const Address& address)
{
@ -2993,6 +3013,16 @@ MacroAssemblerARMCompat::testInt32(Condition cond, const BaseIndex& src)
return cond;
}
+Assembler::Condition
MacroAssemblerARMCompat::testBigInt(Condition cond,const BaseIndex& src)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ScratchRegisterScope scratch(asMasm());
Register tag = extractTag(src, scratch);
ma_cmp(tag, ImmTag(JSVAL_TAG_BIGINT));
return cond;
}
Assembler::Condition
MacroAssemblerARMCompat::testObject(Condition cond, const BaseIndex& src)
{
@ -3736,6 +3766,19 @@ MacroAssemblerARMCompat::testStringTruthy(bool truthy, const ValueOperand& value
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
+Assembler::Condition
MacroAssemblerARMCompat::testBigIntTruthy(bool truthy, const ValueOperand& value)
{
Register bi = value.payloadReg();
ScratchRegisterScope scratch(asMasm());
SecondScratchRegisterScope scratch2(asMasm());
ma_dtr(IsLoad, bi, Imm32(BigInt::offsetOfLengthSignAndReservedBits()),
scratch, scratch2);
as_cmp(scratch, Imm8(0));
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
void
MacroAssemblerARMCompat::floor(FloatRegister input, Register output, Label* bail)
{

View file

@ -695,6 +695,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testUndefined(Condition cond, const ValueOperand& value);
Condition testString(Condition cond, const ValueOperand& value);
Condition testSymbol(Condition cond, const ValueOperand& value);
Condition testBigInt(Condition cond, const ValueOperand& value);
Condition testObject(Condition cond, const ValueOperand& value);
Condition testNumber(Condition cond, const ValueOperand& value);
Condition testMagic(Condition cond, const ValueOperand& value);
@ -708,6 +709,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testUndefined(Condition cond, Register tag);
Condition testString(Condition cond, Register tag);
Condition testSymbol(Condition cond, Register tag);
Condition testBigInt(Condition cond, Register tag);
Condition testObject(Condition cond, Register tag);
Condition testDouble(Condition cond, Register tag);
Condition testNumber(Condition cond, Register tag);
@ -723,6 +725,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testUndefined(Condition cond, const Address& address);
Condition testString(Condition cond, const Address& address);
Condition testSymbol(Condition cond, const Address& address);
Condition testBigInt(Condition cond, const Address& address);
Condition testObject(Condition cond, const Address& address);
Condition testNumber(Condition cond, const Address& address);
@ -731,6 +734,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testBoolean(Condition cond, const BaseIndex& src);
Condition testString(Condition cond, const BaseIndex& src);
Condition testSymbol(Condition cond, const BaseIndex& src);
Condition testBigInt(Condition cond, const BaseIndex& src);
Condition testInt32(Condition cond, const BaseIndex& src);
Condition testObject(Condition cond, const BaseIndex& src);
Condition testDouble(Condition cond, const BaseIndex& src);
@ -749,6 +753,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
@ -797,6 +803,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
Condition testBooleanTruthy(bool truthy, const ValueOperand& operand);
Condition testDoubleTruthy(bool truthy, FloatRegister reg);
Condition testStringTruthy(bool truthy, const ValueOperand& value);
Condition testBigIntTruthy(bool truthy, const ValueOperand& value);
void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest);
void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);

View file

@ -963,6 +963,19 @@ MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value, Labe
branchTestSymbol(cond, value.typeReg(), label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value, Label* label)
{
branchTestBigInt(cond, value.typeReg(), label);
}
void MacroAssembler::branchTestBigIntTruthy(bool b, const ValueOperand& value, Label* label)
{
Register bi = value.payloadReg();
SecondScratchRegisterScope scratch2(*this);
ma_lw(scratch2, Address(bi, BigInt::offsetOfLengthSignAndReservedBits()));
ma_b(scratch2, Imm32(0), label, b ? NotEqual : Equal);
}
void
MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value, Label* label)
{

View file

@ -196,6 +196,9 @@ CodeGeneratorMIPS64::visitUnbox(LUnbox* unbox)
case MIRType::Symbol:
masm.unboxSymbol(inputReg, result);
break;
case MIRType::BigInt:
masm.unboxBigInt(inputReg, result);
break;
default:
MOZ_CRASH("Given MIRType cannot be unboxed.");
}
@ -219,6 +222,9 @@ CodeGeneratorMIPS64::visitUnbox(LUnbox* unbox)
case MIRType::Symbol:
masm.unboxSymbol(inputAddr, result);
break;
case MIRType::BigInt:
masm.unboxBigInt(inputAddr, result);
break;
default:
MOZ_CRASH("Given MIRType cannot be unboxed.");
}

View file

@ -622,6 +622,21 @@ MacroAssembler::branchTestSymbol(Condition cond, const ValueOperand& value, Labe
branchTestSymbol(cond, scratch2, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value, Label* label)
{
SecondScratchRegisterScope scratch2(*this);
splitTag(value, scratch2);
branchTestBigInt(cond, scratch2, label);
}
void MacroAssembler::branchTestBigIntTruthy(bool b, const ValueOperand& value, Label* label)
{
SecondScratchRegisterScope scratch2(*this);
unboxBigInt(value, scratch2);
loadPtr(Address(scratch2, BigInt::offsetOfLengthSignAndReservedBits()), scratch2);
ma_b(scratch2, ImmWord(0), label, b ? NotEqual : Equal);
}
void
MacroAssembler::branchTestNull(Condition cond, const ValueOperand& value, Label* label)
{

View file

@ -1495,6 +1495,21 @@ MacroAssemblerMIPS64Compat::unboxSymbol(Register src, Register dest)
ma_dext(dest, src, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void MacroAssemblerMIPS64Compat::unboxBigInt(const ValueOperand& operand, Register dest)
{
unboxNonDouble(operand, dest, JSVAL_TYPE_BIGINT);
}
void MacroAssemblerMIPS64Compat::unboxBigInt(Register src, Register dest)
{
unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
}
void MacroAssemblerMIPS64Compat::unboxBigInt(const Address& src, Register dest)
{
unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
}
void
MacroAssemblerMIPS64Compat::unboxSymbol(const Address& src, Register dest)
{

View file

@ -361,6 +361,9 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64
void unboxSymbol(const ValueOperand& src, Register dest);
void unboxSymbol(Register src, Register dest);
void unboxSymbol(const Address& src, Register dest);
void unboxBigInt(const ValueOperand& operand, Register dest);
void unboxBigInt(Register src, Register dest);
void unboxBigInt(const Address& src, Register dest);
void unboxObject(const ValueOperand& src, Register dest);
void unboxObject(Register src, Register dest);
void unboxObject(const Address& src, Register dest);

View file

@ -359,6 +359,7 @@ class MacroAssemblerNone : public Assembler
template <typename T> void unboxBoolean(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxString(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxSymbol(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxBigInt(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxObject(T, Register) { MOZ_CRASH(); }
template <typename T> void unboxDouble(T, FloatRegister) { MOZ_CRASH(); }
void unboxValue(const ValueOperand&, AnyRegister) { MOZ_CRASH(); }
@ -393,6 +394,7 @@ class MacroAssemblerNone : public Assembler
void loadConstantFloat32(wasm::RawF32, FloatRegister) { MOZ_CRASH(); }
Condition testInt32Truthy(bool, ValueOperand) { MOZ_CRASH(); }
Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); }
Condition testBigIntTruthy(bool, ValueOperand) { MOZ_CRASH(); }
template <typename T> void loadUnboxedValue(T, MIRType, AnyRegister) { MOZ_CRASH(); }
template <typename T> void storeUnboxedValue(const ConstantOrRegister&, MIRType, T, MIRType) { MOZ_CRASH(); }

View file

@ -431,6 +431,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir,
case MIRType::Int32:
case MIRType::String:
case MIRType::Symbol:
case MIRType::BigInt:
case MIRType::Object:
case MIRType::ObjectOrNull:
case MIRType::Boolean:

View file

@ -3211,7 +3211,7 @@ class LBitNotI : public LInstructionHelper<1, 1, 0>
};
// Call a VM function to perform a BITNOT operation.
class LBitNotV : public LCallInstructionHelper<1, BOX_PIECES, 0>
class LBitNotV : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
{
public:
LIR_HEADER(BitNotV)
@ -3271,7 +3271,7 @@ class LBitOpI64 : public LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>
};
// Call a VM function to perform a bitwise operation.
class LBitOpV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0>
class LBitOpV : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
{
JSOp jsop_;

View file

@ -402,7 +402,8 @@ LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as)
case MIRType::Object:
case MIRType::ObjectOrNull:
case MIRType::String:
case MIRType::Symbol: {
case MIRType::Symbol:
case MIRType::BigInt: {
LAssertResultT* check = new(alloc()) LAssertResultT(useRegister(def));
add(check, def->toInstruction());
break;

View file

@ -100,6 +100,9 @@ LIRGeneratorShared::visitConstant(MConstant* ins)
case MIRType::Symbol:
define(new(alloc()) LPointer(ins->toSymbol()), ins);
break;
case MIRType::BigInt:
define(new (alloc()) LPointer(ins->toBigInt()), ins);
break;
case MIRType::Object:
define(new(alloc()) LPointer(&ins->toObject()), ins);
break;

View file

@ -121,6 +121,9 @@ CodeGeneratorX64::visitUnbox(LUnbox* unbox)
case MIRType::Symbol:
cond = masm.testSymbol(Assembler::NotEqual, value);
break;
case MIRType::BigInt:
cond = masm.testBigInt(Assembler::NotEqual, value);
break;
default:
MOZ_CRASH("Given MIRType cannot be unboxed.");
}
@ -145,6 +148,9 @@ CodeGeneratorX64::visitUnbox(LUnbox* unbox)
case MIRType::Symbol:
masm.unboxSymbol(input, result);
break;
case MIRType::BigInt:
masm.unboxBigInt(input, result);
break;
default:
MOZ_CRASH("Given MIRType cannot be unboxed.");
}

View file

@ -231,6 +231,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testBigInt(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, ImmTag(JSVAL_TAG_BIGINT));
return cond;
}
Condition testObject(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
@ -306,6 +311,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const ValueOperand& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testBigInt(cond, scratch);
}
Condition testObject(Condition cond, const ValueOperand& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
@ -359,6 +369,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const Address& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testBigInt(cond, scratch);
}
Condition testObject(Condition cond, const Address& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
@ -406,6 +421,11 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
splitTag(src, scratch);
return testSymbol(cond, scratch);
}
Condition testBigInt(Condition cond, const BaseIndex& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
return testBigInt(cond, scratch);
}
Condition testInt32(Condition cond, const BaseIndex& src) {
ScratchRegisterScope scratch(asMasm());
splitTag(src, scratch);
@ -794,6 +814,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(Operand(src), dest); }
@ -894,6 +917,13 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
cmp32(Operand(scratch, JSString::offsetOfLength()), Imm32(0));
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
ScratchRegisterScope scratch(asMasm());
unboxBigInt(value, scratch);
cmpPtr(Operand(scratch, BigInt::offsetOfLengthSignAndReservedBits()),
ImmWord(0));
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
template <typename T>
inline void loadInt32OrDouble(const T& src, FloatRegister dest);

View file

@ -944,6 +944,30 @@ MacroAssembler::branchTestSymbolImpl(Condition cond, const T& t, Label* label)
j(cond, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, Register tag, Label* label) {
branchTestBigIntImpl(cond, tag, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const BaseIndex& address, Label* label) {
branchTestBigIntImpl(cond, address, label);
}
void MacroAssembler::branchTestBigInt(Condition cond, const ValueOperand& value, Label* label) {
branchTestBigIntImpl(cond, value, label);
}
template <typename T>
void MacroAssembler::branchTestBigIntImpl(Condition cond, const T& t, Label* label) {
cond = testBigInt(cond, t);
j(cond, label);
}
void MacroAssembler::branchTestBigIntTruthy(bool truthy, const ValueOperand& value, Label* label)
{
Condition cond = testBigIntTruthy(truthy, value);
j(cond, label);
}
void
MacroAssembler::branchTestNull(Condition cond, Register tag, Label* label)
{

View file

@ -294,6 +294,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testBigInt(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, ImmTag(JSVAL_TAG_BIGINT));
return cond;
}
Condition testObject(Condition cond, Register tag) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
@ -410,6 +415,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
Condition testSymbol(Condition cond, const ValueOperand& value) {
return testSymbol(cond, value.typeReg());
}
Condition testBigInt(Condition cond, const ValueOperand& value) {
return testBigInt(cond, value.typeReg());
}
Condition testObject(Condition cond, const ValueOperand& value) {
return testObject(cond, value.typeReg());
}
@ -455,6 +463,11 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cmp32(tagOf(address), ImmTag(JSVAL_TAG_SYMBOL));
return cond;
}
Condition testBigInt(Condition cond, const BaseIndex& address) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tagOf(address), ImmTag(JSVAL_TAG_BIGINT));
return cond;
}
Condition testInt32(Condition cond, const BaseIndex& address) {
MOZ_ASSERT(cond == Equal || cond == NotEqual);
cmp32(tagOf(address), ImmTag(JSVAL_TAG_INT32));
@ -696,6 +709,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
void unboxString(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxSymbol(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxBigInt(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const Address& src, Register dest) { unboxNonDouble(src, dest); }
void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(src, dest); }
@ -793,6 +808,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
cmp32(Operand(string, JSString::offsetOfLength()), Imm32(0));
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
Condition testBigIntTruthy(bool truthy, const ValueOperand& value) {
Register bi = value.payloadReg();
cmpPtr(Operand(bi, BigInt::offsetOfLengthSignAndReservedBits()),
ImmWord(0));
return truthy ? Assembler::NotEqual : Assembler::Equal;
}
template <typename T>
inline void loadInt32OrDouble(const T& src, FloatRegister dest);

View file

@ -619,3 +619,13 @@ MSG_DEF(JSMSG_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop shoul
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
// 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_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate")
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

@ -1099,6 +1099,12 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_
* with those as well.
*/
break;
} else if (elem.isBigInt()) {
// 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

@ -28,6 +28,8 @@
#include "vm/String-inl.h"
#include "vm/BigIntType.h"
using namespace js;
using namespace js::gc;
@ -484,6 +486,13 @@ ToAtomSlow(ExclusiveContext* cx, typename MaybeRooted<Value, allowGC>::HandleTyp
}
return nullptr;
}
if (v.isBigInt()) {
RootedBigInt i(cx, v.toBigInt());
JSAtom* atom = BigIntToAtom(cx, i);
if (!allowGC && !atom)
cx->recoverFromOutOfMemory();
return atom;
}
MOZ_ASSERT(v.isUndefined());
return cx->names().undefined;
}

View file

@ -18,6 +18,7 @@
#include "vm/GlobalObject.h"
#include "vm/ProxyObject.h"
#include "vm/StringBuffer.h"
#include "vm/BigIntType.h"
#include "vm/BooleanObject-inl.h"
@ -170,6 +171,8 @@ js::ToBooleanSlow(HandleValue v)
{
if (v.isString())
return v.toString()->length() != 0;
if (v.isBigInt())
return !v.toBigInt()->isZero();
MOZ_ASSERT(v.isObject());
return !EmulatesUndefined(&v.toObject());

View file

@ -339,6 +339,21 @@ JSCompartment::wrap(JSContext* cx, MutableHandleString strp)
return true;
}
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;
}
bool
JSCompartment::getNonWrapperObjectForCurrentCompartment(JSContext* cx, MutableHandleObject obj)
{

View file

@ -583,6 +583,7 @@ struct JSCompartment
MOZ_MUST_USE inline bool wrap(JSContext* cx, JS::MutableHandleValue vp);
MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandleString strp);
MOZ_MUST_USE bool wrap(JSContext* cx, js::MutableHandle<JS::BigInt*> bi);
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

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

View file

@ -9,6 +9,8 @@
#include <stdint.h>
#include "builtin/BigInt.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "jsgc.h"
@ -299,6 +301,8 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls)
*cls = ESClass::Arguments;
else if (obj->is<ErrorObject>())
*cls = ESClass::Error;
else if (obj->is<BigIntObject>())
*cls = ESClass::BigInt;
else
*cls = ESClass::Other;

View file

@ -222,6 +222,7 @@
#include "jit/JitcodeMap.h"
#include "js/SliceBudget.h"
#include "proxy/DeadObjectProxy.h"
#include "vm/BigIntType.h"
#include "vm/Debugger.h"
#include "vm/ProxyObject.h"
#include "vm/Shape.h"
@ -371,7 +372,8 @@ static const FinalizePhase BackgroundFinalizePhases[] = {
AllocKind::STRING,
AllocKind::FAT_INLINE_ATOM,
AllocKind::ATOM,
AllocKind::SYMBOL
AllocKind::SYMBOL,
AllocKind::BIGINT
}
},
{
@ -1986,6 +1988,7 @@ MovingTracer::updateEdge(T** thingp)
void MovingTracer::onObjectEdge(JSObject** objp) { updateEdge(objp); }
void MovingTracer::onShapeEdge(Shape** shapep) { updateEdge(shapep); }
void MovingTracer::onStringEdge(JSString** stringp) { updateEdge(stringp); }
void MovingTracer::onBigIntEdge(JS::BigInt** bip) { updateEdge(bip); }
void MovingTracer::onScriptEdge(JSScript** scriptp) { updateEdge(scriptp); }
void MovingTracer::onLazyScriptEdge(LazyScript** lazyp) { updateEdge(lazyp); }
void MovingTracer::onBaseShapeEdge(BaseShape** basep) { updateEdge(basep); }
@ -6557,6 +6560,8 @@ JS::GCCellPtr::GCCellPtr(const Value& v)
ptr = checkedCast(&v.toObject(), JS::TraceKind::Object);
else if (v.isSymbol())
ptr = checkedCast(v.toSymbol(), JS::TraceKind::Symbol);
else if (v.isBigInt())
ptr = checkedCast(v.toBigInt(), JS::TraceKind::BigInt);
else if (v.isPrivateGCThing())
ptr = checkedCast(v.toGCThing(), v.toGCThing()->getTraceKind());
else

View file

@ -20,6 +20,7 @@
#include "threading/ConditionVariable.h"
#include "threading/Thread.h"
#include "vm/NativeObject.h"
#include "vm/BigIntType.h"
namespace js {
@ -119,6 +120,7 @@ IsNurseryAllocable(AllocKind kind)
false, /* AllocKind::FAT_INLINE_ATOM */
false, /* AllocKind::ATOM */
false, /* AllocKind::SYMBOL */
false, /* AllocKind::BIGINT */
false, /* AllocKind::JITCODE */
false, /* AllocKind::SCOPE */
false, /* AllocKind::REGEXP_SHARED */
@ -158,6 +160,7 @@ IsBackgroundFinalized(AllocKind kind)
true, /* AllocKind::FAT_INLINE_ATOM */
true, /* AllocKind::ATOM */
true, /* AllocKind::SYMBOL */
true, /* AllocKind::BIGINT */
false, /* AllocKind::JITCODE */
true, /* AllocKind::SCOPE */
true, /* AllocKind::REGEXP_SHARED */

View file

@ -13,6 +13,7 @@
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Unused.h"
#include "mozilla/WrappingOperations.h"
#include <algorithm> // for std::max
#include <fcntl.h>
@ -103,6 +104,7 @@ using mozilla::IsNegative;
using mozilla::IsNegativeZero;
using mozilla::PositiveInfinity;
using mozilla::NegativeInfinity;
using mozilla::WrappingMultiply;
using JS::ToNumber;
using JS::GenericNaN;
@ -458,16 +460,13 @@ js::math_floor(JSContext* cx, unsigned argc, Value* vp)
bool
js::math_imul_handle(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res)
{
uint32_t a = 0, b = 0;
if (!lhs.isUndefined() && !ToUint32(cx, lhs, &a))
int32_t a = 0, b = 0;
if (!lhs.isUndefined() && !ToInt32(cx, lhs, &a))
return false;
if (!rhs.isUndefined() && !ToUint32(cx, rhs, &b))
if (!rhs.isUndefined() && !ToInt32(cx, rhs, &b))
return false;
uint32_t product = a * b;
res.setInt32(product > INT32_MAX
? int32_t(INT32_MIN + (product - INT32_MAX - 1))
: int32_t(product));
res.setInt32(WrappingMultiply(a, b));
return true;
}
@ -685,28 +684,22 @@ js::ecmaPow(double x, double y)
return pow(x, y);
}
bool
js::math_pow_handle(JSContext* cx, HandleValue base, HandleValue power, MutableHandleValue result)
{
double x;
if (!ToNumber(cx, base, &x))
return false;
double y;
if (!ToNumber(cx, power, &y))
return false;
double z = ecmaPow(x, y);
result.setNumber(z);
return true;
}
bool
js::math_pow(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return math_pow_handle(cx, args.get(0), args.get(1), args.rval());
double x;
if (!ToNumber(cx, args.get(0), &x))
return false;
double y;
if (!ToNumber(cx, args.get(1), &y))
return false;
double z = ecmaPow(x, y);
args.rval().setNumber(z);
return true;
}
uint64_t

View file

@ -123,10 +123,6 @@ math_min(JSContext* cx, unsigned argc, js::Value* vp);
extern bool
math_sqrt(JSContext* cx, unsigned argc, js::Value* vp);
extern bool
math_pow_handle(JSContext* cx, js::HandleValue base, js::HandleValue power,
js::MutableHandleValue result);
extern bool
math_pow(JSContext* cx, unsigned argc, js::Value* vp);

View file

@ -524,15 +524,22 @@ Number(JSContext* cx, unsigned argc, Value* vp)
bool isConstructing = args.isConstructing();
if (args.length() > 0) {
if (!ToNumber(cx, args[0]))
// BigInt proposal section 6.2, steps 2a-c.
if (!ToNumeric(cx, args[0]))
return false;
args.rval().set(args[0]);
} else {
args.rval().setInt32(0);
if (args[0].isBigInt())
args[0].setNumber(BigInt::numberValue(args[0].toBigInt()));
MOZ_ASSERT(args[0].isNumber());
}
if (!isConstructing)
if (!isConstructing) {
if (args.length() > 0) {
args.rval().set(args[0]);
} else {
args.rval().setInt32(0);
}
return true;
}
RootedObject newTarget(cx, &args.newTarget().toObject());
RootedObject proto(cx);
@ -1452,9 +1459,19 @@ js::ToNumberSlow(ExclusiveContext* 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() || v.isBigInt());
if (cx->isJSContext()) {
unsigned errnum = JSMSG_SYMBOL_TO_NUMBER;
if (v.isBigInt())
errnum = JSMSG_BIGINT_TO_NUMBER;
JS_ReportErrorNumberASCII(cx->asJSContext(), GetErrorMessage, nullptr, errnum);
}
return false;
}
JS_PUBLIC_API(bool)
@ -1482,6 +1499,30 @@ js::ToInt8Slow(JSContext *cx, const HandleValue v, int8_t *out)
return true;
}
// BigInt proposal section 3.1.6
bool
js::ToNumericSlow(ExclusiveContext* cx, MutableHandleValue vp)
{
MOZ_ASSERT(!vp.isNumber());
MOZ_ASSERT(!vp.isBigInt());
// Step 1.
if (!vp.isPrimitive()) {
if (!cx->isJSContext())
return false;
if (!ToPrimitive(cx->asJSContext(), JSTYPE_NUMBER, vp))
return false;
}
// Step 2.
if (vp.isBigInt()) {
return true;
}
// Step 3.
return ToNumber(cx->asJSContext(), vp);
}
/*
* Convert a value to an uint8_t, according to the ToUInt8() function in ES6
* ECMA-262, 7.1.10. Return converted value in *out on success, false on failure.
@ -1573,6 +1614,27 @@ js::ToInt32Slow(JSContext* cx, const HandleValue v, int32_t* out)
return true;
}
bool
js::ToInt32OrBigIntSlow(JSContext* cx, MutableHandleValue vp)
{
MOZ_ASSERT(!vp.isInt32());
if (vp.isDouble()) {
vp.setInt32(ToInt32(vp.toDouble()));
return true;
}
if (!ToNumeric(cx, vp)) {
return false;
}
if (vp.isBigInt()) {
return true;
}
vp.setInt32(ToInt32(vp.toNumber()));
return true;
}
JS_PUBLIC_API(bool)
js::ToUint32Slow(JSContext* cx, const HandleValue v, uint32_t* out)
{
@ -1706,6 +1768,35 @@ js::ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
return true;
}
// ES2017 draft 7.1.17 ToIndex
bool
js::ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index)
{
// Step 1.
if (v.isUndefined()) {
*index = 0;
return true;
}
// Step 2.a.
double integerIndex;
if (!ToInteger(cx, v, &integerIndex))
return false;
// Inlined version of ToLength.
// 1. Already an integer.
// 2. Step eliminates < 0, +0 == -0 with SameValueZero.
// 3/4. Limit to <= 2^53-1, so everything above should fail.
if (integerIndex < 0 || integerIndex >= DOUBLE_INTEGRAL_PRECISION_LIMIT) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
return false;
}
// Step 3.
*index = uint64_t(integerIndex);
return true;
}
template <typename CharT>
bool
js_strtod(ExclusiveContext* cx, const CharT* begin, const CharT* end, const CharT** dEnd,

View file

@ -308,6 +308,15 @@ MOZ_MUST_USE bool ToLengthClamped(T* cx, HandleValue v, uint32_t* out, bool* ove
*/
MOZ_MUST_USE bool ToIntegerIndex(JSContext* cx, JS::HandleValue v, uint64_t* index);
/* ES2017 draft 7.1.17 ToIndex
*
* Return true and set |*index| to the integer value if |v| is a valid
* integer index value. Otherwise report a RangeError and return false.
*
* The returned index will always be in the range 0 <= *index <= 2^53-1.
*/
MOZ_MUST_USE bool ToIndex(JSContext* cx, JS::HandleValue v, uint64_t* index);
MOZ_MUST_USE inline bool
SafeAdd(int32_t one, int32_t two, int32_t* res)
{
@ -362,6 +371,32 @@ ToNumber(ExclusiveContext* cx, HandleValue v, double* out)
return ToNumberSlow(cx, v, out);
}
bool
ToNumericSlow(ExclusiveContext* cx, JS::MutableHandleValue vp);
// BigInt proposal section 3.1.6
MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
ToNumeric(ExclusiveContext* cx, JS::MutableHandleValue vp)
{
if (vp.isNumber())
return true;
if (vp.isBigInt())
return true;
return ToNumericSlow(cx, vp);
}
bool
ToInt32OrBigIntSlow(JSContext* cx, JS::MutableHandleValue vp);
MOZ_ALWAYS_INLINE MOZ_MUST_USE bool
ToInt32OrBigInt(JSContext* cx, JS::MutableHandleValue vp)
{
if (vp.isInt32()) {
return true;
}
return ToInt32OrBigIntSlow(cx, vp);
}
void FIX_FPU();
} /* namespace js */

View file

@ -35,6 +35,7 @@
#include "jswin.h"
#include "jswrapper.h"
#include "builtin/BigInt.h"
#include "builtin/Eval.h"
#include "builtin/Object.h"
#include "builtin/SymbolObject.h"
@ -3104,9 +3105,13 @@ js::PrimitiveToObject(JSContext* cx, const Value& v)
return NumberObject::create(cx, v.toNumber());
if (v.isBoolean())
return BooleanObject::create(cx, v.toBoolean());
MOZ_ASSERT(v.isSymbol());
RootedSymbol symbol(cx, v.toSymbol());
return SymbolObject::create(cx, symbol);
if (v.isSymbol()) {
RootedSymbol symbol(cx, v.toSymbol());
return SymbolObject::create(cx, symbol);
}
MOZ_ASSERT(v.isBigInt());
RootedBigInt bigInt(cx, v.toBigInt());
return BigIntObject::create(cx, bigInt);
}
/*

View file

@ -9,6 +9,8 @@
#include "mozilla/Range.h"
#include "mozilla/ScopeExit.h"
#include "builtin/BigInt.h"
#include "jsarray.h"
#include "jsatom.h"
#include "jscntxt.h"
@ -328,6 +330,8 @@ PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleVa
} else if (cls == ESClass::Boolean) {
if (!Unbox(cx, obj, vp))
return false;
} else if (cls == ESClass::BigInt) {
vp.setBigInt(obj->as<BigIntObject>().unbox());
}
}
@ -626,6 +630,12 @@ Str(JSContext* cx, const Value& v, StringifyContext* scx)
return NumberValueToStringBuffer(cx, v, scx->sb);
}
/* Step 10 in the BigInt proposal. */
if (v.isBigInt()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BIGINT_NOT_SERIALIZABLE);
return false;
}
/* Step 10. */
MOZ_ASSERT(v.isObject());
RootedObject obj(cx, &v.toObject());

View file

@ -1039,6 +1039,9 @@ js::Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
break;
}
case JOF_BIGINT:
// Fallthrough.
case JOF_DOUBLE: {
RootedValue v(cx, script->getConst(GET_UINT32_INDEX(pc)));
JSAutoByteString bytes;

View file

@ -56,6 +56,7 @@ enum {
JOF_ATOMOBJECT = 19, /* uint16_t constant index + object index */
JOF_SCOPE = 20, /* unsigned 32-bit scope index */
JOF_ENVCOORD = 21, /* embedded ScopeCoordinate immediate */
JOF_BIGINT = 22, /* uint32_t index for BigInt value */
JOF_TYPEMASK = 0x001f, /* mask for above immediate types */
JOF_NAME = 1 << 5, /* name operation */

View file

@ -91,6 +91,7 @@
real(Float32Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
real(Float64Array, InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
real(Uint8ClampedArray, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
real(BigInt, InitViaClassSpec, OCLASP(BigInt)) \
real(Proxy, InitProxyClass, js::ProxyClassPtr) \
real(WeakMap, InitWeakMapClass, OCLASP(WeakMap)) \
real(Map, InitMapClass, OCLASP(Map)) \

View file

@ -80,6 +80,7 @@ enum JSType {
JSTYPE_BOOLEAN, /* boolean */
JSTYPE_NULL, /* null */
JSTYPE_SYMBOL, /* symbol */
JSTYPE_BIGINT, /* BigInt */
JSTYPE_LIMIT
};

Some files were not shown because too many files have changed in this diff Show more