mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Bug 1505849 - Implement parser support for BigInt literals r=terpri,jandem
Differential Revision: https://phabricator.services.mozilla.com/D11353 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
7e8a95c1c9
commit
907dd759ae
@ -21,6 +21,9 @@
|
||||
#include "frontend/Parser.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/StableStringChars.h"
|
||||
#ifdef ENABLE_BIGINT
|
||||
#include "vm/BigIntType.h"
|
||||
#endif
|
||||
#include "vm/JSAtom.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
@ -3147,6 +3150,9 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
case ParseNodeKind::String:
|
||||
case ParseNodeKind::RegExp:
|
||||
case ParseNodeKind::Number:
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
#endif
|
||||
case ParseNodeKind::True:
|
||||
case ParseNodeKind::False:
|
||||
case ParseNodeKind::Null:
|
||||
@ -3312,7 +3318,7 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
|
||||
|
||||
case ParseNodeKind::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.as<RegExpObject>()));
|
||||
@ -3328,6 +3334,16 @@ ASTSerializer::literal(ParseNode* pn, MutableHandleValue dst)
|
||||
val.setNumber(pn->as<NumericLiteral>().value());
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
{
|
||||
BigInt* x = pn->as<BigIntLiteral>().box()->value();
|
||||
cx->check(x);
|
||||
val.setBigInt(x);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::Null:
|
||||
val.setNull();
|
||||
break;
|
||||
|
@ -51,7 +51,7 @@ class BinASTParserBase: private JS::AutoGCRooter
|
||||
virtual void doTrace(JSTracer* trc) {}
|
||||
|
||||
void trace(JSTracer* trc) {
|
||||
ObjectBox::TraceList(trc, traceListHead_);
|
||||
TraceListNode::TraceList(trc, traceListHead_);
|
||||
doTrace(trc);
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ class BinASTParserBase: private JS::AutoGCRooter
|
||||
// ---- Memory-related stuff
|
||||
protected:
|
||||
LifoAlloc& alloc_;
|
||||
ObjectBox* traceListHead_;
|
||||
TraceListNode* traceListHead_;
|
||||
UsedNameTracker& usedNames_;
|
||||
private:
|
||||
LifoAlloc::Mark tempPoolMark_;
|
||||
@ -256,10 +256,10 @@ class BinASTParser : public BinASTParserBase, public ErrorReporter, public BCEPa
|
||||
* function.
|
||||
*/
|
||||
|
||||
ObjectBox* objbox = alloc_.new_<ObjectBox>(obj, traceListHead_);
|
||||
if (!objbox) {
|
||||
ReportOutOfMemory(cx_);
|
||||
return nullptr;
|
||||
ObjectBox* objbox = alloc_.new_<ObjectBox>(obj, traceListHead_);
|
||||
if (!objbox) {
|
||||
ReportOutOfMemory(cx_);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
traceListHead_ = objbox;
|
||||
|
@ -1062,6 +1062,13 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
*answer = false;
|
||||
return true;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
MOZ_ASSERT(pn->is<BigIntLiteral>());
|
||||
*answer = false;
|
||||
return true;
|
||||
#endif
|
||||
|
||||
// |this| can throw in derived class constructors, including nested arrow
|
||||
// functions or eval.
|
||||
case ParseNodeKind::This:
|
||||
@ -2000,7 +2007,7 @@ BytecodeEmitter::emitNumberOp(double dval)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!numberList.append(dval)) {
|
||||
if (!numberList.append(DoubleValue(dval))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -4153,6 +4160,11 @@ ParseNode::getConstantValue(JSContext* cx, AllowConstantObjects allowObjects,
|
||||
case ParseNodeKind::Number:
|
||||
vp.setNumber(as<NumericLiteral>().value());
|
||||
return true;
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
vp.setBigInt(as<BigIntLiteral>().box()->value());
|
||||
return true;
|
||||
#endif
|
||||
case ParseNodeKind::TemplateString:
|
||||
case ParseNodeKind::String:
|
||||
vp.setString(as<NameNode>().atom());
|
||||
@ -4722,6 +4734,17 @@ BytecodeEmitter::emitCopyDataProperties(CopyOption option)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool
|
||||
BytecodeEmitter::emitBigIntOp(BigInt* bigint)
|
||||
{
|
||||
if (!numberList.append(BigIntValue(bigint))) {
|
||||
return false;
|
||||
}
|
||||
return emitIndex32(JSOP_BIGINT, numberList.length() - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitIterator()
|
||||
{
|
||||
@ -8915,6 +8938,14 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
if (!emitBigIntOp(pn->as<BigIntLiteral>().box()->value())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::RegExp:
|
||||
if (!emitRegExp(objectList.add(pn->as<RegExpLiteral>().objbox()))) {
|
||||
return false;
|
||||
@ -9224,7 +9255,7 @@ CGNumberList::finish(mozilla::Span<GCPtrValue> array)
|
||||
MOZ_ASSERT(length() == array.size());
|
||||
|
||||
for (unsigned i = 0; i < length(); i++) {
|
||||
array[i].init(DoubleValue(list[i]));
|
||||
array[i].init(vector[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9239,6 +9270,7 @@ CGNumberList::finish(mozilla::Span<GCPtrValue> array)
|
||||
unsigned
|
||||
CGObjectList::add(ObjectBox* objbox)
|
||||
{
|
||||
MOZ_ASSERT(objbox->isObjectBox());
|
||||
MOZ_ASSERT(!objbox->emitLink);
|
||||
objbox->emitLink = lastbox;
|
||||
lastbox = objbox;
|
||||
@ -9254,11 +9286,11 @@ CGObjectList::finish(mozilla::Span<GCPtrObject> array)
|
||||
ObjectBox* objbox = lastbox;
|
||||
for (GCPtrObject& obj : mozilla::Reversed(array)) {
|
||||
MOZ_ASSERT(obj == nullptr);
|
||||
MOZ_ASSERT(objbox->object->isTenured());
|
||||
MOZ_ASSERT(objbox->object()->isTenured());
|
||||
if (objbox->isFunctionBox()) {
|
||||
objbox->asFunctionBox()->finish();
|
||||
}
|
||||
obj.init(objbox->object);
|
||||
obj.init(objbox->object());
|
||||
objbox = objbox->emitLink;
|
||||
}
|
||||
}
|
||||
|
@ -29,20 +29,22 @@ namespace js {
|
||||
namespace frontend {
|
||||
|
||||
class CGNumberList {
|
||||
Vector<double> list;
|
||||
Rooted<ValueVector> vector;
|
||||
|
||||
public:
|
||||
explicit CGNumberList(JSContext* cx) : list(cx) {}
|
||||
MOZ_MUST_USE bool append(double v) {
|
||||
return list.append(v);
|
||||
explicit CGNumberList(JSContext* cx)
|
||||
: vector(cx, ValueVector(cx))
|
||||
{ }
|
||||
MOZ_MUST_USE bool append(const Value& v) {
|
||||
return vector.append(v);
|
||||
}
|
||||
size_t length() const { return list.length(); }
|
||||
size_t length() const { return vector.length(); }
|
||||
void finish(mozilla::Span<GCPtrValue> 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) {}
|
||||
|
||||
@ -194,7 +196,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||
return innermostEmitterScope_;
|
||||
}
|
||||
|
||||
CGNumberList numberList; /* number constants to be included with the script */
|
||||
CGNumberList numberList; /* 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 */
|
||||
@ -530,6 +532,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||
|
||||
MOZ_MUST_USE bool emitNumberOp(double dval);
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
MOZ_MUST_USE bool emitBigIntOp(BigInt* bigint);
|
||||
#endif
|
||||
|
||||
MOZ_MUST_USE bool emitThisLiteral(ThisLiteral* pn);
|
||||
MOZ_MUST_USE bool emitGetFunctionThis(NameNode* thisName);
|
||||
MOZ_MUST_USE bool emitGetFunctionThis(const mozilla::Maybe<uint32_t>& offset);
|
||||
|
@ -379,6 +379,9 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
|
||||
case ParseNodeKind::This:
|
||||
case ParseNodeKind::Elision:
|
||||
case ParseNodeKind::Number:
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
#endif
|
||||
case ParseNodeKind::New:
|
||||
case ParseNodeKind::Generator:
|
||||
case ParseNodeKind::ParamsBody:
|
||||
@ -472,6 +475,9 @@ IsEffectless(ParseNode* node)
|
||||
node->isKind(ParseNodeKind::String) ||
|
||||
node->isKind(ParseNodeKind::TemplateString) ||
|
||||
node->isKind(ParseNodeKind::Number) ||
|
||||
#ifdef ENABLE_BIGINT
|
||||
node->isKind(ParseNodeKind::BigInt) ||
|
||||
#endif
|
||||
node->isKind(ParseNodeKind::Null) ||
|
||||
node->isKind(ParseNodeKind::RawUndefined) ||
|
||||
node->isKind(ParseNodeKind::Function);
|
||||
@ -486,6 +492,11 @@ Boolish(ParseNode* pn)
|
||||
case ParseNodeKind::Number:
|
||||
return (pn->as<NumericLiteral>().value() != 0 && !IsNaN(pn->as<NumericLiteral>().value())) ? Truthy : Falsy;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
return (pn->as<BigIntLiteral>().box()->value()->toBoolean()) ? Truthy : Falsy;
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::String:
|
||||
case ParseNodeKind::TemplateString:
|
||||
return (pn->as<NameNode>().atom()->length() > 0) ? Truthy : Falsy;
|
||||
@ -567,7 +578,13 @@ FoldTypeOfExpr(JSContext* cx, UnaryNode* node, PerHandlerParser<FullParseHandler
|
||||
result = cx->names().string;
|
||||
} else if (expr->isKind(ParseNodeKind::Number)) {
|
||||
result = cx->names().number;
|
||||
} else if (expr->isKind(ParseNodeKind::Null)) {
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
else if (expr->isKind(ParseNodeKind::BigInt)) {
|
||||
result = cx->names().bigint;
|
||||
}
|
||||
#endif
|
||||
else if (expr->isKind(ParseNodeKind::Null)) {
|
||||
result = cx->names().object;
|
||||
} else if (expr->isKind(ParseNodeKind::True) || expr->isKind(ParseNodeKind::False)) {
|
||||
result = cx->names().boolean;
|
||||
@ -1634,6 +1651,12 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
||||
MOZ_ASSERT(pn->is<NumericLiteral>());
|
||||
return true;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
MOZ_ASSERT(pn->is<BigIntLiteral>());
|
||||
return true;
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::SuperBase:
|
||||
case ParseNodeKind::TypeOfName: {
|
||||
#ifdef DEBUG
|
||||
|
@ -131,6 +131,20 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
return new_<NumericLiteral>(value, decimalPoint, pos);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
// 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);
|
||||
}
|
||||
#endif
|
||||
|
||||
BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) {
|
||||
return new_<BooleanLiteral>(cond, pos);
|
||||
}
|
||||
|
@ -463,6 +463,12 @@ class NameResolver
|
||||
MOZ_ASSERT(cur->is<NumericLiteral>());
|
||||
break;
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case ParseNodeKind::BigInt:
|
||||
MOZ_ASSERT(cur->is<BigIntLiteral>());
|
||||
break;
|
||||
#endif
|
||||
|
||||
case ParseNodeKind::TypeOfName:
|
||||
case ParseNodeKind::SuperBase:
|
||||
MOZ_ASSERT(cur->as<UnaryNode>().kid()->isKind(ParseNodeKind::Name));
|
||||
|
@ -180,6 +180,11 @@ ParseNode::dump(GenericPrinter& out, int indent)
|
||||
case PN_NUMBER:
|
||||
as<NumericLiteral>().dump(out, indent);
|
||||
return;
|
||||
#ifdef ENABLE_BIGINT
|
||||
case PN_BIGINT:
|
||||
as<BigIntLiteral>().dump(out, indent);
|
||||
return;
|
||||
#endif
|
||||
case PN_REGEXP:
|
||||
as<RegExpLiteral>().dump(out, indent);
|
||||
return;
|
||||
@ -223,6 +228,14 @@ NumericLiteral::dump(GenericPrinter& out, int indent)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
void
|
||||
BigIntLiteral::dump(GenericPrinter& out, int indent)
|
||||
{
|
||||
out.printf("(%s)", parseNodeNames[size_t(getKind())]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
RegExpLiteral::dump(GenericPrinter& out, int indent)
|
||||
{
|
||||
@ -436,23 +449,49 @@ LexicalScopeNode::dump(GenericPrinter& out, 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),
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntBox*
|
||||
TraceListNode::asBigIntBox()
|
||||
{
|
||||
MOZ_ASSERT(isBigIntBox());
|
||||
return static_cast<BigIntBox*>(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
ObjectBox*
|
||||
TraceListNode::asObjectBox()
|
||||
{
|
||||
MOZ_ASSERT(isObjectBox());
|
||||
return static_cast<ObjectBox*>(this);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntBox::BigIntBox(BigInt* bi, TraceListNode* traceLink)
|
||||
: TraceListNode(bi, traceLink)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
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*
|
||||
@ -463,17 +502,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
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "frontend/TokenStream.h"
|
||||
#ifdef ENABLE_BIGINT
|
||||
#include "vm/BigIntType.h"
|
||||
#endif
|
||||
#include "vm/BytecodeUtil.h"
|
||||
#include "vm/Printer.h"
|
||||
#include "vm/Scope.h"
|
||||
@ -42,6 +45,9 @@ class ParseContext;
|
||||
class FullParseHandler;
|
||||
class FunctionBox;
|
||||
class ObjectBox;
|
||||
#ifdef ENABLE_BIGINT
|
||||
class BigIntBox;
|
||||
#endif
|
||||
|
||||
#define FOR_EACH_PARSE_NODE_KIND(F) \
|
||||
F(EmptyStatement, PN_NULLARY) \
|
||||
@ -71,6 +77,7 @@ class ObjectBox;
|
||||
F(PrivateName, PN_NAME) \
|
||||
F(ComputedName, PN_UNARY) \
|
||||
F(Number, PN_NUMBER) \
|
||||
IF_BIGINT(F(BigInt, PN_BIGINT),/**/) \
|
||||
F(String, PN_NAME) \
|
||||
F(TemplateStringList, PN_LIST) \
|
||||
F(TemplateString, PN_NAME) \
|
||||
@ -485,6 +492,8 @@ IsTypeofKind(ParseNodeKind kind)
|
||||
* regexp: RegExp model object
|
||||
* Number (NumericLiteral)
|
||||
* value: double value of numeric literal
|
||||
* BigInt (BigIntLiteral)
|
||||
* box: BigIntBox holding BigInt* value
|
||||
* True, False (BooleanLiteral)
|
||||
* pn_op: JSOp bytecode
|
||||
* Null (NullLiteral)
|
||||
@ -524,6 +533,9 @@ enum ParseNodeArity
|
||||
PN_NAME, /* name, label, string */
|
||||
PN_FIELD, /* field name, optional initializer */
|
||||
PN_NUMBER, /* numeric literal */
|
||||
#ifdef ENABLE_BIGINT
|
||||
PN_BIGINT, /* BigInt literal */
|
||||
#endif
|
||||
PN_REGEXP, /* regexp literal */
|
||||
PN_LOOP, /* loop control (break/continue) */
|
||||
PN_SCOPE /* lexical scope */
|
||||
@ -563,6 +575,7 @@ enum ParseNodeArity
|
||||
macro(RawUndefinedLiteral, RawUndefinedLiteralType, asRawUndefinedLiteral) \
|
||||
\
|
||||
macro(NumericLiteral, NumericLiteralType, asNumericLiteral) \
|
||||
IF_BIGINT(macro(BigIntLiteral, BigIntLiteralType, asBigIntLiteral),) \
|
||||
\
|
||||
macro(RegExpLiteral, RegExpLiteralType, asRegExpLiteral) \
|
||||
\
|
||||
@ -734,6 +747,13 @@ class ParseNode
|
||||
double value; /* aligned numeric literal value */
|
||||
DecimalPoint decimalPoint; /* Whether the number has a decimal point */
|
||||
} number;
|
||||
#ifdef ENABLE_BIGINT
|
||||
struct {
|
||||
private:
|
||||
friend class BigIntLiteral;
|
||||
BigIntBox* box;
|
||||
} bigint;
|
||||
#endif
|
||||
class {
|
||||
private:
|
||||
friend class LoopControlStatement;
|
||||
@ -753,6 +773,9 @@ class ParseNode
|
||||
/* True if pn is a parsenode representing a literal constant. */
|
||||
bool isLiteral() const {
|
||||
return isKind(ParseNodeKind::Number) ||
|
||||
#ifdef ENABLE_BIGINT
|
||||
isKind(ParseNodeKind::BigInt) ||
|
||||
#endif
|
||||
isKind(ParseNodeKind::String) ||
|
||||
isKind(ParseNodeKind::True) ||
|
||||
isKind(ParseNodeKind::False) ||
|
||||
@ -1526,6 +1549,32 @@ class NumericLiteral : public ParseNode
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
class BigIntLiteral : public ParseNode
|
||||
{
|
||||
public:
|
||||
BigIntLiteral(BigIntBox* bibox, const TokenPos& pos)
|
||||
: ParseNode(ParseNodeKind::BigInt, JSOP_NOP, pos)
|
||||
{
|
||||
pn_u.bigint.box = bibox;
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(ParseNodeKind::BigInt);
|
||||
MOZ_ASSERT_IF(match, node.isArity(PN_BIGINT));
|
||||
return match;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void dump(GenericPrinter& out, int indent);
|
||||
#endif
|
||||
|
||||
BigIntBox* box() const {
|
||||
return pn_u.bigint.box;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class LexicalScopeNode : public ParseNode
|
||||
{
|
||||
public:
|
||||
@ -2183,25 +2232,54 @@ ParseNode::isConstant()
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectBox
|
||||
class TraceListNode
|
||||
{
|
||||
public:
|
||||
JSObject* object;
|
||||
protected:
|
||||
js::gc::Cell* gcThing;
|
||||
TraceListNode* traceLink;
|
||||
|
||||
TraceListNode(js::gc::Cell* gcThing, TraceListNode* traceLink);
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool isBigIntBox() const { return gcThing->is<BigInt>(); }
|
||||
#endif
|
||||
bool isObjectBox() const { return gcThing->is<JSObject>(); }
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntBox* asBigIntBox();
|
||||
#endif
|
||||
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);
|
||||
};
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
class BigIntBox : public TraceListNode
|
||||
{
|
||||
public:
|
||||
BigIntBox(BigInt* bi, TraceListNode* link);
|
||||
BigInt* value() const { return gcThing->as<BigInt>(); }
|
||||
};
|
||||
#endif
|
||||
|
||||
class ObjectBox : public TraceListNode
|
||||
{
|
||||
protected:
|
||||
friend struct CGObjectList;
|
||||
|
||||
ObjectBox* traceLink;
|
||||
ObjectBox* emitLink;
|
||||
|
||||
ObjectBox(JSFunction* function, ObjectBox* traceLink);
|
||||
ObjectBox(JSFunction* function, TraceListNode* link);
|
||||
|
||||
public:
|
||||
ObjectBox(JSObject* obj, TraceListNode* link);
|
||||
|
||||
JSObject* object() const { return gcThing->as<JSObject>(); }
|
||||
|
||||
bool isFunctionBox() const { return object()->is<JSFunction>(); }
|
||||
FunctionBox* asFunctionBox();
|
||||
};
|
||||
|
||||
enum ParseReportKind
|
||||
|
@ -460,10 +460,11 @@ GeneralParser<ParseHandler, Unit>::setInParametersOfAsyncFunction(bool inParamet
|
||||
asFinalParser()->setInParametersOfAsyncFunction(inParameters);
|
||||
}
|
||||
|
||||
ObjectBox*
|
||||
ParserBase::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
|
||||
@ -473,17 +474,31 @@ ParserBase::newObjectBox(JSObject* obj)
|
||||
* function.
|
||||
*/
|
||||
|
||||
ObjectBox* objbox = alloc.template 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);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntBox*
|
||||
ParserBase::newBigIntBox(BigInt* val)
|
||||
{
|
||||
return newTraceListNode<BigIntBox, BigInt>(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class ParseHandler>
|
||||
FunctionBox*
|
||||
PerHandlerParser<ParseHandler>::newFunctionBox(CodeNodeType funNode, JSFunction* fun,
|
||||
@ -520,7 +535,7 @@ PerHandlerParser<ParseHandler>::newFunctionBox(CodeNodeType funNode, JSFunction*
|
||||
void
|
||||
ParserBase::trace(JSTracer* trc)
|
||||
{
|
||||
ObjectBox::TraceList(trc, traceListHead);
|
||||
TraceListNode::TraceList(trc, traceListHead);
|
||||
}
|
||||
|
||||
void
|
||||
@ -9345,6 +9360,46 @@ GeneralParser<ParseHandler, Unit>::newRegExp()
|
||||
return asFinalParser()->newRegExp();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
template <typename Unit>
|
||||
BigIntLiteral*
|
||||
Parser<FullParseHandler, Unit>::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.getCharBuffer();
|
||||
mozilla::Range<const char16_t> source(chars.begin(), chars.length());
|
||||
|
||||
BigInt* b = js::StringToBigInt(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 <typename Unit>
|
||||
SyntaxParseHandler::BigIntLiteralType
|
||||
Parser<SyntaxParseHandler, Unit>::newBigInt()
|
||||
{
|
||||
// The tokenizer has already checked the syntax of the bigint.
|
||||
|
||||
return handler.newBigInt();
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
typename ParseHandler::BigIntLiteralType
|
||||
GeneralParser<ParseHandler, Unit>::newBigInt()
|
||||
{
|
||||
return asFinalParser()->newBigInt();
|
||||
}
|
||||
#endif /* ENABLE_BIGINT */
|
||||
|
||||
// |exprPossibleError| is the PossibleError state within |expr|,
|
||||
// |possibleError| is the surrounding PossibleError state.
|
||||
template <class ParseHandler, typename Unit>
|
||||
@ -10369,6 +10424,11 @@ GeneralParser<ParseHandler, Unit>::primaryExpr(YieldHandling yieldHandling,
|
||||
case TokenKind::Number:
|
||||
return newNumber(anyChars.currentToken());
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case TokenKind::BigInt:
|
||||
return newBigInt();
|
||||
#endif
|
||||
|
||||
case TokenKind::True:
|
||||
return handler.newBooleanLiteral(true, pos());
|
||||
case TokenKind::False:
|
||||
|
@ -247,8 +247,8 @@ class MOZ_STACK_CLASS ParserBase
|
||||
TokenStreamAnyChars anyChars;
|
||||
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;
|
||||
@ -348,7 +348,7 @@ class MOZ_STACK_CLASS ParserBase
|
||||
{
|
||||
friend class ParserBase;
|
||||
LifoAlloc::Mark mark;
|
||||
ObjectBox* traceListHead;
|
||||
TraceListNode* traceListHead;
|
||||
};
|
||||
Mark mark() const {
|
||||
Mark m;
|
||||
@ -361,7 +361,15 @@ class MOZ_STACK_CLASS ParserBase
|
||||
traceListHead = m.traceListHead;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename BoxT, typename ArgT>
|
||||
BoxT* newTraceListNode(ArgT* arg);
|
||||
|
||||
public:
|
||||
ObjectBox* newObjectBox(JSObject* obj);
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntBox* newBigIntBox(BigInt* val);
|
||||
#endif
|
||||
|
||||
mozilla::Maybe<GlobalScope::Data*> newGlobalScopeData(ParseContext::Scope& scope);
|
||||
mozilla::Maybe<ModuleScope::Data*> newModuleScopeData(ParseContext::Scope& scope);
|
||||
@ -1295,6 +1303,10 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
||||
return handler.newNumber(tok.number(), tok.decimalPoint(), tok.pos);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
inline BigIntLiteralType newBigInt();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Match the current token against the BindingIdentifier production with
|
||||
// the given Yield parameter. If there is no match, report a syntax
|
||||
@ -1410,6 +1422,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
||||
inline void setInParametersOfAsyncFunction(bool inParameters);
|
||||
|
||||
RegExpLiteralType newRegExp();
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntLiteralType newBigInt();
|
||||
#endif
|
||||
|
||||
// Parse a module.
|
||||
CodeNodeType moduleBody(ModuleSharedContext* modulesc);
|
||||
@ -1537,6 +1552,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
||||
inline void setInParametersOfAsyncFunction(bool inParameters);
|
||||
|
||||
RegExpLiteralType newRegExp();
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntLiteralType newBigInt();
|
||||
#endif
|
||||
|
||||
// Parse a module.
|
||||
CodeNodeType moduleBody(ModuleSharedContext* modulesc);
|
||||
|
@ -121,7 +121,7 @@ FunctionBox::atomsAreKept()
|
||||
}
|
||||
#endif
|
||||
|
||||
FunctionBox::FunctionBox(JSContext* cx, ObjectBox* traceListHead,
|
||||
FunctionBox::FunctionBox(JSContext* cx, TraceListNode* traceListHead,
|
||||
JSFunction* fun, uint32_t toStringStart,
|
||||
Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
|
@ -292,7 +292,7 @@ SharedContext::asEvalContext()
|
||||
|
||||
class FunctionBox : public ObjectBox, public SharedContext
|
||||
{
|
||||
// The parser handles tracing the fields below via the ObjectBox linked
|
||||
// The parser handles tracing the fields below via the TraceListNode linked
|
||||
// list.
|
||||
|
||||
// This field is used for two purposes:
|
||||
@ -403,7 +403,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
// Whether this function has nested functions.
|
||||
bool hasInnerFunctions_:1;
|
||||
|
||||
FunctionBox(JSContext* cx, ObjectBox* traceListHead, JSFunction* fun,
|
||||
FunctionBox(JSContext* cx, TraceListNode* traceListHead, JSFunction* fun,
|
||||
uint32_t toStringStart, Directives directives, bool extraWarnings,
|
||||
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
|
||||
|
||||
@ -437,7 +437,8 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
void setEnclosingScopeForInnerLazyFunction(Scope* enclosingScope);
|
||||
void finish();
|
||||
|
||||
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
|
||||
|
@ -208,6 +208,12 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
return NodeGeneric;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
BigIntLiteralType newBigInt() {
|
||||
return NodeGeneric;
|
||||
}
|
||||
#endif
|
||||
|
||||
BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) { return NodeGeneric; }
|
||||
|
||||
NameNodeType newStringLiteral(JSAtom* atom, const TokenPos& pos) {
|
||||
|
@ -76,6 +76,7 @@
|
||||
macro(PrivateName, "private identifier") \
|
||||
macro(Number, "numeric literal") \
|
||||
macro(String, "string literal") \
|
||||
IF_BIGINT(macro(BigInt, "bigint literal"),) \
|
||||
\
|
||||
/* start of template literal with substitutions */ \
|
||||
macro(TemplateHead, "'${'") \
|
||||
|
@ -2272,8 +2272,11 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStar
|
||||
|
||||
// Numbers contain no escapes, so we can read directly from |sourceUnits|.
|
||||
double dval;
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool isBigInt = false;
|
||||
#endif
|
||||
DecimalPoint decimalPoint = NoDecimal;
|
||||
if (unit != '.' && unit != 'e' && unit != 'E') {
|
||||
if (unit != '.' && unit != 'e' && unit != 'E' && IF_BIGINT(unit != 'n', true)) {
|
||||
// NOTE: |unit| may be EOF here.
|
||||
ungetCodeUnit(unit);
|
||||
|
||||
@ -2284,7 +2287,14 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStar
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
else if (unit == 'n') {
|
||||
isBigInt = true;
|
||||
unit = peekCodeUnit();
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// Consume any decimal dot and fractional component.
|
||||
if (unit == '.') {
|
||||
decimalPoint = HasDecimal;
|
||||
@ -2346,6 +2356,13 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::decimalNumber(int32_t unit, TokenStar
|
||||
}
|
||||
|
||||
noteBadToken.release();
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (isBigInt) {
|
||||
return bigIntLiteral(start, modifier, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
newNumberToken(dval, decimalPoint, start, modifier, out);
|
||||
return true;
|
||||
}
|
||||
@ -2476,6 +2493,35 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::regexpLiteral(TokenStart start, Token
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
template<typename Unit, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<Unit, AnyCharsAccess>::bigIntLiteral(TokenStart start,
|
||||
Modifier modifier,
|
||||
TokenKind* out)
|
||||
{
|
||||
MOZ_ASSERT(this->sourceUnits.previousCodeUnit() == toUnit('n'));
|
||||
MOZ_ASSERT(this->sourceUnits.offset() > start.offset());
|
||||
uint32_t length = this->sourceUnits.offset() - start.offset();
|
||||
MOZ_ASSERT(length >= 2);
|
||||
this->charBuffer.clear();
|
||||
mozilla::Range<const Unit> chars(this->sourceUnits.codeUnitPtrAt(start.offset()),
|
||||
length);
|
||||
for (uint32_t idx = 0; idx < length - 1; idx++) {
|
||||
int32_t unit = CodeUnitValue(chars[idx]);
|
||||
// Char buffer may start with a 0[bBoOxX] prefix, then follows with
|
||||
// binary, octal, decimal, or hex digits. Already checked by caller, as
|
||||
// the "n" indicating bigint comes at the end.
|
||||
MOZ_ASSERT(isAsciiCodePoint(unit));
|
||||
if (!this->appendCodePointToCharBuffer(unit)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
newBigIntToken(start, modifier, out);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename Unit, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp,
|
||||
@ -2640,8 +2686,11 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
//
|
||||
if (c1kind == ZeroDigit) {
|
||||
TokenStart start(this->sourceUnits, -1);
|
||||
|
||||
int radix;
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool isLegacyOctalOrNoctal = false;
|
||||
bool isBigInt = false;
|
||||
#endif
|
||||
const Unit* numStart;
|
||||
unit = getCodeUnit();
|
||||
if (unit == 'x' || unit == 'X') {
|
||||
@ -2694,6 +2743,9 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
}
|
||||
} else if (IsAsciiDigit(unit)) {
|
||||
radix = 8;
|
||||
#ifdef ENABLE_BIGINT
|
||||
isLegacyOctalOrNoctal = true;
|
||||
#endif
|
||||
// one past the '0'
|
||||
numStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
|
||||
|
||||
@ -2728,7 +2780,20 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
return decimalNumber(unit, start, numStart, modifier, ttp);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (unit == 'n') {
|
||||
if (isLegacyOctalOrNoctal) {
|
||||
error(JSMSG_BIGINT_INVALID_SYNTAX);
|
||||
return badToken();
|
||||
}
|
||||
isBigInt = true;
|
||||
unit = peekCodeUnit();
|
||||
} else {
|
||||
ungetCodeUnit(unit);
|
||||
}
|
||||
#else
|
||||
ungetCodeUnit(unit);
|
||||
#endif
|
||||
|
||||
// Error if an identifier-start code point appears immediately
|
||||
// after the number. Somewhat surprisingly, if we don't check
|
||||
@ -2748,6 +2813,12 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
if (isBigInt) {
|
||||
return bigIntLiteral(start, modifier, ttp);
|
||||
}
|
||||
#endif
|
||||
|
||||
double dval;
|
||||
if (!GetFullInteger(anyCharsAccess().cx, numStart,
|
||||
this->sourceUnits.addressOfNextCodeUnit(), radix, &dval))
|
||||
|
@ -1911,6 +1911,13 @@ class GeneralTokenStreamChars
|
||||
token->setNumber(dval, decimalPoint);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
void newBigIntToken(TokenStart start, TokenStreamShared::Modifier modifier, TokenKind* out)
|
||||
{
|
||||
newToken(TokenKind::BigInt, start, modifier, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
void newAtomToken(TokenKind kind, JSAtom* atom, TokenStart start,
|
||||
TokenStreamShared::Modifier modifier, TokenKind* out)
|
||||
{
|
||||
@ -2349,6 +2356,9 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
||||
using GeneralCharsBase::newNameToken;
|
||||
using GeneralCharsBase::newPrivateNameToken;
|
||||
using GeneralCharsBase::newNumberToken;
|
||||
#ifdef ENABLE_BIGINT
|
||||
using GeneralCharsBase::newBigIntToken;
|
||||
#endif
|
||||
using GeneralCharsBase::newRegExpToken;
|
||||
using GeneralCharsBase::newSimpleToken;
|
||||
using CharsBase::peekCodeUnit;
|
||||
@ -2516,6 +2526,12 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
||||
/** Tokenize a regular expression literal beginning at |start|. */
|
||||
MOZ_MUST_USE bool regexpLiteral(TokenStart start, TokenKind* out);
|
||||
|
||||
/**
|
||||
* Slurp characters between |start| and sourceUnits.current() into
|
||||
* charBuffer, to later parse into a bigint.
|
||||
*/
|
||||
MOZ_MUST_USE bool bigIntLiteral(TokenStart start, Modifier modifier, TokenKind* out);
|
||||
|
||||
public:
|
||||
// Advance to the next token. If the token stream encountered an error,
|
||||
// return false. Otherwise return true and store the token kind in |*ttp|.
|
||||
|
10
js/src/jit-test/tests/xdr/bigint.js
Normal file
10
js/src/jit-test/tests/xdr/bigint.js
Normal file
@ -0,0 +1,10 @@
|
||||
// |jit-test| skip-if: !('BigInt' in this)
|
||||
load(libdir + 'bytecode-cache.js');
|
||||
|
||||
let test = `
|
||||
assertEq(2n**64n - 1n, BigInt("0xffffFFFFffffFFFF"));
|
||||
`;
|
||||
evalWithCache(test, {
|
||||
assertEqBytecode: true,
|
||||
assertEqResult : true
|
||||
});
|
@ -1871,6 +1871,15 @@ BaselineCompiler::emit_JSOP_DOUBLE()
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_BIGINT()
|
||||
{
|
||||
frame.push(script->getConst(GET_UINT32_INDEX(pc)));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_STRING()
|
||||
{
|
||||
|
@ -54,6 +54,7 @@ namespace jit {
|
||||
_(JSOP_UINT24) \
|
||||
_(JSOP_RESUMEINDEX) \
|
||||
_(JSOP_DOUBLE) \
|
||||
IF_BIGINT(_(JSOP_BIGINT),) \
|
||||
_(JSOP_STRING) \
|
||||
_(JSOP_SYMBOL) \
|
||||
_(JSOP_OBJECT) \
|
||||
|
@ -1990,6 +1990,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
return jsop_compare(op);
|
||||
|
||||
case JSOP_DOUBLE:
|
||||
#ifdef ENABLE_BIGINT
|
||||
case JSOP_BIGINT:
|
||||
#endif
|
||||
pushConstant(info().getConst(pc));
|
||||
return Ok();
|
||||
|
||||
|
@ -8,6 +8,9 @@ assertExpr("42", lit(42));
|
||||
assertExpr("(/asdf/)", lit(/asdf/));
|
||||
assertExpr("this", thisExpr);
|
||||
assertExpr("foo", ident("foo"));
|
||||
if ("BigInt" in this) {
|
||||
assertExpr("1234n", lit(BigInt(1234)));
|
||||
}
|
||||
|
||||
// member expressions
|
||||
assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar")));
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
|
||||
#include "vm/JSContext-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
using mozilla::Abs;
|
||||
@ -1064,6 +1066,22 @@ js::StringToBigInt(JSContext* cx, HandleString str, uint8_t radix)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BigInt*
|
||||
js::StringToBigInt(JSContext* cx, const Range<const char16_t>& chars)
|
||||
{
|
||||
RootedBigInt res(cx, BigInt::create(cx));
|
||||
if (!res) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t radix = 0;
|
||||
if (StringToBigIntImpl(chars, radix, res)) {
|
||||
return res.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t
|
||||
BigInt::byteLength(BigInt* x)
|
||||
{
|
||||
@ -1147,3 +1165,58 @@ JS::ubi::Concrete<BigInt>::size(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
size += bi.sizeOfExcludingThis(mallocSizeOf);
|
||||
return size;
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
XDRResult
|
||||
js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi)
|
||||
{
|
||||
JSContext* cx = xdr->cx();
|
||||
|
||||
uint8_t sign;
|
||||
uint32_t length;
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
cx->check(bi);
|
||||
sign = static_cast<uint8_t>(bi->sign());
|
||||
uint64_t sz = BigInt::byteLength(bi);
|
||||
// As the maximum source code size is currently UINT32_MAX code units
|
||||
// (see BytecodeCompiler::checkLength), any bigint literal's length in
|
||||
// word-sized digits will be less than UINT32_MAX as well. That could
|
||||
// change or FoldConstants could start creating these though, so leave
|
||||
// this as a release-enabled assert.
|
||||
MOZ_RELEASE_ASSERT(sz <= UINT32_MAX);
|
||||
length = static_cast<uint32_t>(sz);
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint8(&sign));
|
||||
MOZ_TRY(xdr->codeUint32(&length));
|
||||
|
||||
UniquePtr<uint8_t> buf(cx->pod_malloc<uint8_t>(length));
|
||||
if (!buf) {
|
||||
ReportOutOfMemory(cx);
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
BigInt::writeBytes(bi, RangedPtr<uint8_t>(buf.get(), length));
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeBytes(buf.get(), length));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
BigInt* res = BigInt::createFromBytes(cx, static_cast<int8_t>(sign),
|
||||
buf.get(), length);
|
||||
if (!res) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
bi.set(res);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult
|
||||
js::XDRBigInt(XDRState<XDR_ENCODE>* xdr, MutableHandleBigInt bi);
|
||||
|
||||
template XDRResult
|
||||
js::XDRBigInt(XDRState<XDR_DECODE>* xdr, MutableHandleBigInt bi);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "vm/StringType.h"
|
||||
#include "vm/Xdr.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
@ -28,6 +29,9 @@ template <typename CharT>
|
||||
static bool StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
|
||||
uint8_t radix, Handle<JS::BigInt*> res);
|
||||
|
||||
template<XDRMode mode>
|
||||
XDRResult XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi);
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
@ -38,6 +42,8 @@ class BigInt final : public js::gc::TenuredCell
|
||||
template <typename CharT>
|
||||
friend bool js::StringToBigIntImpl(const mozilla::Range<const CharT>& chars,
|
||||
uint8_t radix, Handle<BigInt*> res);
|
||||
template <js::XDRMode mode>
|
||||
friend js::XDRResult js::XDRBigInt(js::XDRState<mode>* xdr, MutableHandleBigInt bi);
|
||||
|
||||
protected:
|
||||
// Reserved word for Cell GC invariants. This also ensures minimum
|
||||
@ -161,6 +167,10 @@ NumberToBigInt(JSContext* cx, double d);
|
||||
extern JS::Result<JS::BigInt*, JS::OOM&>
|
||||
StringToBigInt(JSContext* cx, JS::Handle<JSString*> str, uint8_t radix);
|
||||
|
||||
// Same.
|
||||
extern JS::BigInt*
|
||||
StringToBigInt(JSContext* cx, const mozilla::Range<const char16_t>& chars);
|
||||
|
||||
extern JS::BigInt*
|
||||
ToBigInt(JSContext* cx, JS::Handle<JS::Value> v);
|
||||
|
||||
|
@ -1495,6 +1495,10 @@ Disassemble1(JSContext* cx, HandleScript script, jsbytecode* pc,
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
case JOF_BIGINT:
|
||||
// Fallthrough.
|
||||
#endif
|
||||
case JOF_DOUBLE: {
|
||||
RootedValue v(cx, script->getConst(GET_UINT32_INDEX(pc)));
|
||||
UniqueChars bytes = ToDisassemblySource(cx, v);
|
||||
|
@ -57,6 +57,9 @@ enum {
|
||||
JOF_REGEXP = 16, /* uint32_t regexp index */
|
||||
JOF_DOUBLE = 17, /* uint32_t index for double value */
|
||||
JOF_SCOPE = 18, /* uint32_t scope index */
|
||||
#ifdef ENABLE_BIGINT
|
||||
JOF_BIGINT = 19, /* uint32_t index for BigInt value */
|
||||
#endif
|
||||
JOF_TYPEMASK = 0x001f, /* mask for above immediate types */
|
||||
|
||||
JOF_NAME = 1 << 5, /* name operation */
|
||||
|
@ -4790,6 +4790,15 @@ CASE(JSOP_IS_CONSTRUCTING)
|
||||
PUSH_MAGIC(JS_IS_CONSTRUCTING);
|
||||
END_CASE(JSOP_IS_CONSTRUCTING)
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
CASE(JSOP_BIGINT)
|
||||
{
|
||||
PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc)));
|
||||
MOZ_ASSERT(REGS.sp[-1].isBigInt());
|
||||
}
|
||||
END_CASE(JSOP_BIGINT)
|
||||
#endif
|
||||
|
||||
DEFAULT()
|
||||
{
|
||||
char numBuf[12];
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "builtin/Object.h"
|
||||
#include "jit/JitFrames.h"
|
||||
#include "proxy/Proxy.h"
|
||||
#ifdef ENABLE_BIGINT
|
||||
#include "vm/BigIntType.h"
|
||||
#endif
|
||||
#include "vm/HelperThreads.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/Iteration.h"
|
||||
@ -114,6 +117,12 @@ class ContextChecks
|
||||
checkAtom(symbol, argIndex);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIGINT
|
||||
void check(JS::BigInt* bi, int argIndex) {
|
||||
check(bi->zone(), argIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
void check(const js::Value& v, int argIndex) {
|
||||
if (v.isObject()) {
|
||||
check(&v.toObject(), argIndex);
|
||||
@ -122,6 +131,11 @@ class ContextChecks
|
||||
} else if (v.isSymbol()) {
|
||||
check(v.toSymbol(), argIndex);
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
else if (v.isBigInt()) {
|
||||
check(v.toBigInt(), argIndex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check the contents of any container class that supports the C++
|
||||
|
@ -101,7 +101,10 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
|
||||
SCRIPT_NULL,
|
||||
SCRIPT_OBJECT,
|
||||
SCRIPT_VOID,
|
||||
SCRIPT_HOLE
|
||||
SCRIPT_HOLE,
|
||||
#ifdef ENABLE_BIGINT
|
||||
SCRIPT_BIGINT
|
||||
#endif
|
||||
};
|
||||
|
||||
ConstTag tag;
|
||||
@ -122,7 +125,13 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
|
||||
tag = SCRIPT_OBJECT;
|
||||
} else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
|
||||
tag = SCRIPT_HOLE;
|
||||
} else {
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
else if (vp.isBigInt()) {
|
||||
tag = SCRIPT_BIGINT;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
MOZ_ASSERT(vp.isUndefined());
|
||||
tag = SCRIPT_VOID;
|
||||
}
|
||||
@ -202,6 +211,21 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
|
||||
vp.setMagic(JS_ELEMENTS_HOLE);
|
||||
}
|
||||
break;
|
||||
#ifdef ENABLE_BIGINT
|
||||
case SCRIPT_BIGINT: {
|
||||
RootedBigInt bi(cx);
|
||||
if (mode == XDR_ENCODE) {
|
||||
bi = vp.toBigInt();
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRBigInt(xdr, &bi));
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
vp.setBigInt(bi);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
// Fail in debug, but only soft-fail in release
|
||||
MOZ_ASSERT(false, "Bad XDR value kind");
|
||||
@ -3911,9 +3935,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
||||
MOZ_ASSERT(!src->sourceObject()->isMarkedGray());
|
||||
|
||||
uint32_t nscopes = src->scopes().size();
|
||||
#ifdef DEBUG
|
||||
uint32_t nconsts = src->hasConsts() ? src->consts().size() : 0;
|
||||
#endif
|
||||
uint32_t nobjects = src->hasObjects() ? src->objects().size() : 0;
|
||||
|
||||
/* Script data */
|
||||
@ -3944,6 +3966,41 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
||||
}
|
||||
}
|
||||
|
||||
/* Constants */
|
||||
|
||||
AutoValueVector consts(cx);
|
||||
if (nconsts != 0) {
|
||||
RootedValue val(cx);
|
||||
RootedValue clone(cx);
|
||||
for (const GCPtrValue& elem : src->consts()) {
|
||||
val = elem.get();
|
||||
if (val.isDouble()) {
|
||||
clone = val;
|
||||
}
|
||||
#ifdef ENABLE_BIGINT
|
||||
else if (val.isBigInt()) {
|
||||
if (cx->zone() == val.toBigInt()->zone()) {
|
||||
clone.setBigInt(val.toBigInt());
|
||||
} else {
|
||||
RootedBigInt b(cx, val.toBigInt());
|
||||
BigInt* copy = BigInt::copy(cx, b);
|
||||
if (!copy) {
|
||||
return false;
|
||||
}
|
||||
clone.setBigInt(copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
MOZ_ASSERT_UNREACHABLE("bad script consts() element");
|
||||
}
|
||||
|
||||
if (!consts.append(clone)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Objects */
|
||||
|
||||
AutoObjectVector objects(cx);
|
||||
@ -4024,15 +4081,12 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
||||
array[i].init(scopes[i]);
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (nconsts) {
|
||||
auto array = dst->data_->consts();
|
||||
for (unsigned i = 0; i < nconsts; ++i) {
|
||||
// We don't support GCThings here and thus don't need to call |init|.
|
||||
MOZ_ASSERT(!array[i].isGCThing());
|
||||
array[i].init(consts[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (nobjects) {
|
||||
auto array = dst->data_->objects();
|
||||
for (unsigned i = 0; i < nobjects; ++i) {
|
||||
|
@ -2498,14 +2498,22 @@
|
||||
* Operands:
|
||||
* Stack: arg => rval
|
||||
*/ \
|
||||
macro(JSOP_DYNAMIC_IMPORT, 233, "call-import", NULL, 1, 1, 1, JOF_BYTE)
|
||||
macro(JSOP_DYNAMIC_IMPORT, 233, "call-import", NULL, 1, 1, 1, JOF_BYTE) \
|
||||
/*
|
||||
* Pushes a BigInt constant onto the stack.
|
||||
* Category: Literals
|
||||
* Type: Constants
|
||||
* Operands: uint32_t constIndex
|
||||
* Stack: => val
|
||||
*/ \
|
||||
IF_BIGINT(macro(JSOP_BIGINT, 234, "bigint", NULL, 5, 0, 1, JOF_BIGINT),)
|
||||
|
||||
/*
|
||||
* In certain circumstances it may be useful to "pad out" the opcode space to
|
||||
* a power of two. Use this macro to do so.
|
||||
*/
|
||||
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
|
||||
macro(234) \
|
||||
IF_BIGINT(,macro(234)) \
|
||||
macro(235) \
|
||||
macro(236) \
|
||||
macro(237) \
|
||||
|
@ -7474,7 +7474,7 @@ js::CompileAsmJS(JSContext* cx, AsmJSParser& parser, ParseNode* stmtList, bool*
|
||||
// generating bytecode for asm.js functions, allowing this asm.js module
|
||||
// function to be the finished result.
|
||||
MOZ_ASSERT(funbox->function()->isInterpreted());
|
||||
funbox->object = moduleFun;
|
||||
funbox->clobberFunction(moduleFun);
|
||||
|
||||
// Success! Write to the console with a "warning" message.
|
||||
*validated = true;
|
||||
|
Loading…
Reference in New Issue
Block a user