mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 20:07:30 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
1977864a3a
131 changed files with 6239 additions and 442 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1100,6 +1100,7 @@ enum class ESClass {
|
|||
SetIterator,
|
||||
Arguments,
|
||||
Error,
|
||||
BigInt,
|
||||
|
||||
/** None of the above. */
|
||||
Other
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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*> {};
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
258
js/src/builtin/BigInt.cpp
Normal 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
52
js/src/builtin/BigInt.h
Normal 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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, "'${'") \
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)')
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ namespace jit {
|
|||
_(JSOP_UINT16) \
|
||||
_(JSOP_UINT24) \
|
||||
_(JSOP_DOUBLE) \
|
||||
_(JSOP_BIGINT) \
|
||||
_(JSOP_STRING) \
|
||||
_(JSOP_SYMBOL) \
|
||||
_(JSOP_OBJECT) \
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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, ¬BigInt);
|
||||
}
|
||||
masm.branchTestBigIntTruthy(false, value, ifFalsy);
|
||||
if (tagCount != 1) {
|
||||
masm.jump(ifTruthy);
|
||||
}
|
||||
masm.bind(¬BigInt);
|
||||
--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, ¬BigInt);
|
||||
}
|
||||
masm.movePtr(ImmGCPtr(names.bigint), output);
|
||||
if (numTests > 1) {
|
||||
masm.jump(&done);
|
||||
}
|
||||
masm.bind(¬BigInt);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
107
js/src/jsnum.cpp
107
js/src/jsnum.cpp
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)) \
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue