Issue #1240 - Part 4 - Implement parser support for BigInt literals. https://bugzilla.mozilla.org/show_bug.cgi?id=1505849 Partially based on https://bugzilla.mozilla.org/show_bug.cgi?id=1456568 Un-result-ified the BigInt XDR code, so we can enable it. https://bugzilla.mozilla.org/show_bug.cgi?id=1419094 Uninitialised memory read with BigInt right-shift https://bugzilla.mozilla.org/show_bug.cgi?id=1679003

This commit is contained in:
Brian Smith 2023-07-18 20:23:02 -05:00 • committed by roytam1
commit dc23241afb
27 changed files with 394 additions and 80 deletions

View file

@ -1047,7 +1047,6 @@ MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
if (rval.isBigInt()) { if (rval.isBigInt()) {
return JS_WrapValue(cx, rval); return JS_WrapValue(cx, rval);
} }
MOZ_ASSERT(rval.isSymbol());
return true; return true;
} }

View file

@ -667,7 +667,7 @@ class MOZ_NON_PARAM alignas(8) Value
#if defined(JS_NUNBOX32) #if defined(JS_NUNBOX32)
return data.s.payload.bi; return data.s.payload.bi;
#elif defined(JS_PUNBOX64) #elif defined(JS_PUNBOX64)
return reinterpret_cast<JS::BigInt*>(data.asBits & JSVAL_SHIFTED_TAG_BIGINT); return reinterpret_cast<JS::BigInt*>(data.asBits & JSVAL_PAYLOAD_MASK);
#endif #endif
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -151,6 +151,18 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return new_<NumericLiteral>(value, decimalPoint, pos); 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) { BooleanLiteralType newBooleanLiteral(bool cond, const TokenPos& pos) {
return new_<BooleanLiteral>(cond, pos); return new_<BooleanLiteral>(cond, pos);
} }

View file

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

View file

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

View file

@ -12,6 +12,7 @@
#include "builtin/ModuleObject.h" #include "builtin/ModuleObject.h"
#include "frontend/TokenStream.h" #include "frontend/TokenStream.h"
#include "vm/BigIntType.h"
namespace js { namespace js {
namespace frontend { namespace frontend {
@ -20,6 +21,7 @@ class ParseContext;
class FullParseHandler; class FullParseHandler;
class FunctionBox; class FunctionBox;
class ObjectBox; class ObjectBox;
class BigIntBox;
#define FOR_EACH_PARSE_NODE_KIND(F) \ #define FOR_EACH_PARSE_NODE_KIND(F) \
F(NOP) \ F(NOP) \
@ -53,6 +55,7 @@ class ObjectBox;
F(OBJECT_PROPERTY_NAME) \ F(OBJECT_PROPERTY_NAME) \
F(COMPUTED_NAME) \ F(COMPUTED_NAME) \
F(NUMBER) \ F(NUMBER) \
F(BIGINT) \
F(STRING) \ F(STRING) \
F(TEMPLATE_STRING_LIST) \ F(TEMPLATE_STRING_LIST) \
F(TEMPLATE_STRING) \ F(TEMPLATE_STRING) \
@ -524,6 +527,8 @@ IsTypeofKind(ParseNodeKind kind)
* regexp: RegExp model object * regexp: RegExp model object
* PNK_NUMBER (NumericLiteral) * PNK_NUMBER (NumericLiteral)
* value: double value of numeric literal * value: double value of numeric literal
* PNK_BIGINT (BigIntLiteral)
* box: BigIntBox holding BigInt* value
* PNK_TRUE, PNK_FALSE (BooleanLiteral) * PNK_TRUE, PNK_FALSE (BooleanLiteral)
* pn_op: JSOp bytecode * pn_op: JSOp bytecode
* PNK_NULL (NullLiteral) * PNK_NULL (NullLiteral)
@ -571,6 +576,7 @@ enum ParseNodeArity
PN_LIST, /* generic singly linked list */ PN_LIST, /* generic singly linked list */
PN_NAME, /* name, label, string */ PN_NAME, /* name, label, string */
PN_NUMBER, /* numeric literal */ PN_NUMBER, /* numeric literal */
PN_BIGINT, /* BigInt literal */
PN_REGEXP, /* regexp literal */ PN_REGEXP, /* regexp literal */
PN_LOOP, /* loop control (break/continue) */ PN_LOOP, /* loop control (break/continue) */
PN_SCOPE /* lexical scope */ PN_SCOPE /* lexical scope */
@ -613,6 +619,7 @@ enum ParseNodeArity
macro(RawUndefinedLiteral, RawUndefinedLiteralType, asRawUndefinedLiteral) \ macro(RawUndefinedLiteral, RawUndefinedLiteralType, asRawUndefinedLiteral) \
\ \
macro(NumericLiteral, NumericLiteralType, asNumericLiteral) \ macro(NumericLiteral, NumericLiteralType, asNumericLiteral) \
macro(BigIntLiteral, BigIntLiteralType, asBigIntLiteral) \
\ \
macro(RegExpLiteral, RegExpLiteralType, asRegExpLiteral) \ macro(RegExpLiteral, RegExpLiteralType, asRegExpLiteral) \
\ \
@ -828,6 +835,11 @@ class ParseNode
double value; /* aligned numeric literal value */ double value; /* aligned numeric literal value */
DecimalPoint decimalPoint; /* Whether the number has a decimal point */ DecimalPoint decimalPoint; /* Whether the number has a decimal point */
} number; } number;
struct {
private:
friend class BigIntLiteral;
BigIntBox* box;
} bigint;
class { class {
private: private:
friend class LoopControlStatement; friend class LoopControlStatement;
@ -849,6 +861,7 @@ class ParseNode
/* True if pn is a parsenode representing a literal constant. */ /* True if pn is a parsenode representing a literal constant. */
bool isLiteral() const { bool isLiteral() const {
return isKind(PNK_NUMBER) || return isKind(PNK_NUMBER) ||
isKind(PNK_BIGINT) ||
isKind(PNK_STRING) || isKind(PNK_STRING) ||
isKind(PNK_TRUE) || isKind(PNK_TRUE) ||
isKind(PNK_FALSE) || 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 class LexicalScopeNode : public ParseNode
{ {
public: public:
@ -2350,25 +2387,48 @@ ParseNode::isConstant()
} }
} }
class ObjectBox class TraceListNode
{ {
public: protected:
JSObject* object; 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); 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: protected:
friend struct CGObjectList; friend struct CGObjectList;
ObjectBox* traceLink;
ObjectBox* emitLink; 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 enum ParseReportKind

View file

@ -438,7 +438,7 @@ UsedNameTracker::rewind(RewindToken token)
r.front().value().resetToScope(token.scriptId, token.scopeId); 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, JSFunction* fun, uint32_t toStringStart,
Directives directives, bool extraWarnings, Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind) GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
@ -882,11 +882,11 @@ Parser<FullParseHandler>::setAwaitHandling(AwaitHandling awaitHandling)
parser->setAwaitHandling(awaitHandling); parser->setAwaitHandling(awaitHandling);
} }
template <typename ParseHandler> template <typename BoxT, typename ArgT>
ObjectBox* BoxT*
Parser<ParseHandler>::newObjectBox(JSObject* obj) ParserBase::newTraceListNode(ArgT* arg)
{ {
MOZ_ASSERT(obj); MOZ_ASSERT(arg);
/* /*
* We use JSContext.tempLifoAlloc to allocate parsed objects and place them * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
@ -896,15 +896,27 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
* function. * function.
*/ */
ObjectBox* objbox = alloc.new_<ObjectBox>(obj, traceListHead); BoxT* box = alloc.template new_<BoxT>(arg, traceListHead);
if (!objbox) { if (!box) {
ReportOutOfMemory(context); ReportOutOfMemory(context);
return nullptr; 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> template <typename ParseHandler>
@ -10579,6 +10591,37 @@ Parser<ParseHandler>::newRegExp()
return handler.newRegExp(reobj, pos(), *this); 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> template <typename ParseHandler>
void void
Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos, Parser<ParseHandler>::checkDestructuringAssignmentTarget(Node expr, TokenPos exprPos,
@ -11474,6 +11517,9 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TripledotHandling
case TOK_NUMBER: case TOK_NUMBER:
return newNumber(tokenStream.currentToken()); return newNumber(tokenStream.currentToken());
case TOK_BIGINT:
return newBigInt();
case TOK_TRUE: case TOK_TRUE:
return handler.newBooleanLiteral(true, pos()); return handler.newBooleanLiteral(true, pos());
case TOK_FALSE: case TOK_FALSE:

View file

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

View file

@ -443,7 +443,7 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags; 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, uint32_t toStringStart, Directives directives, bool extraWarnings,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind); GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
@ -467,7 +467,8 @@ class FunctionBox : public ObjectBox, public SharedContext
void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind); void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
ObjectBox* toObjectBox() override { return this; } 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 { Scope* compilationEnclosingScope() const override {
// This method is used to distinguish the outermost SharedContext. If // This method is used to distinguish the outermost SharedContext. If

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1765,6 +1765,7 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_compare(op); return jsop_compare(op);
case JSOP_DOUBLE: case JSOP_DOUBLE:
case JSOP_BIGINT:
pushConstant(info().getConst(pc)); pushConstant(info().getConst(pc));
return true; return true;

View file

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

View file

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

View file

@ -83,7 +83,8 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
SCRIPT_NULL, SCRIPT_NULL,
SCRIPT_OBJECT, SCRIPT_OBJECT,
SCRIPT_VOID, SCRIPT_VOID,
SCRIPT_HOLE SCRIPT_HOLE,
SCRIPT_BIGINT
}; };
ConstTag tag; ConstTag tag;
@ -104,6 +105,8 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
tag = SCRIPT_OBJECT; tag = SCRIPT_OBJECT;
} else if (vp.isMagic(JS_ELEMENTS_HOLE)) { } else if (vp.isMagic(JS_ELEMENTS_HOLE)) {
tag = SCRIPT_HOLE; tag = SCRIPT_HOLE;
} else if (vp.isBigInt()) {
tag = SCRIPT_BIGINT;
} else { } else {
MOZ_ASSERT(vp.isUndefined()); MOZ_ASSERT(vp.isUndefined());
tag = SCRIPT_VOID; tag = SCRIPT_VOID;
@ -176,6 +179,20 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
if (mode == XDR_DECODE) if (mode == XDR_DECODE)
vp.setMagic(JS_ELEMENTS_HOLE); vp.setMagic(JS_ELEMENTS_HOLE);
break; break;
case SCRIPT_BIGINT: {
RootedBigInt bi(cx);
if (mode == XDR_ENCODE) {
bi = vp.toBigInt();
}
if(!XDRBigInt(xdr, &bi))
return false;
if (mode == XDR_DECODE) {
vp.setBigInt(bi);
}
break;
}
default: default:
// Fail in debug, but only soft-fail in release // Fail in debug, but only soft-fail in release
MOZ_ASSERT(false, "Bad XDR value kind"); MOZ_ASSERT(false, "Bad XDR value kind");
@ -3418,6 +3435,38 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
} }
} }
/* Constants */
AutoValueVector consts(cx);
if (nconsts != 0) {
GCPtrValue* vector = src->consts()->vector;
RootedValue val(cx);
RootedValue clone(cx);
for (unsigned i = 0; i < nconsts; i++) {
val = vector[i];
if (val.isDouble()) {
clone = val;
} 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);
}
} else {
MOZ_ASSERT_UNREACHABLE("bad script consts() element");
}
if (!consts.append(clone)) {
return false;
}
}
}
/* Objects */ /* Objects */
AutoObjectVector objects(cx); AutoObjectVector objects(cx);
@ -3508,7 +3557,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector);
dst->consts()->vector = vector; dst->consts()->vector = vector;
for (unsigned i = 0; i < nconsts; ++i) for (unsigned i = 0; i < nconsts; ++i)
MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom()); vector[i].init(consts[i]);
} }
if (nobjects != 0) { if (nobjects != 0) {
GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector); GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector);

View file

@ -1987,6 +1987,8 @@ BigInt* BigInt::rshByAbsolute(ExclusiveContext* cx, HandleBigInt x, HandleBigInt
return nullptr; return nullptr;
} }
if (!bitsShift) { if (!bitsShift) {
// If roundingCanOverflow, manually initialize the overflow digit.
result->setDigit(resultLength - 1, 0);
for (int i = digitShift; i < length; i++) { for (int i = digitShift; i < length; i++) {
result->setDigit(i - digitShift, x->digit(i)); result->setDigit(i - digitShift, x->digit(i));
} }
@ -3144,16 +3146,14 @@ JS::ubi::Node::Size JS::ubi::Concrete<BigInt>::size(
return size; return size;
} }
#if 0 // Future XDR support
template <XDRMode mode> template <XDRMode mode>
XDRResult js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi) { bool js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi) {
JSContext* cx = xdr->cx(); ExclusiveContext* cx = xdr->cx();
uint8_t sign; uint8_t sign;
uint32_t length; uint32_t length;
if (mode == XDR_ENCODE) { if (mode == XDR_ENCODE) {
cx->check(bi);
sign = static_cast<uint8_t>(bi->isNegative()); sign = static_cast<uint8_t>(bi->isNegative());
uint64_t sz = bi->digitLength() * sizeof(BigInt::Digit); uint64_t sz = bi->digitLength() * sizeof(BigInt::Digit);
// As the maximum source code size is currently UINT32_MAX code units // As the maximum source code size is currently UINT32_MAX code units
@ -3165,8 +3165,10 @@ XDRResult js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi) {
length = static_cast<uint32_t>(sz); length = static_cast<uint32_t>(sz);
} }
MOZ_TRY(xdr->codeUint8(&sign)); if(!xdr->codeUint8(&sign))
MOZ_TRY(xdr->codeUint32(&length)); return false;
if(!xdr->codeUint32(&length))
return false;
MOZ_RELEASE_ASSERT(length % sizeof(BigInt::Digit) == 0); MOZ_RELEASE_ASSERT(length % sizeof(BigInt::Digit) == 0);
uint32_t digitLength = length / sizeof(BigInt::Digit); uint32_t digitLength = length / sizeof(BigInt::Digit);
@ -3179,7 +3181,8 @@ XDRResult js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi) {
std::uninitialized_copy_n(bi->digits().Elements(), digitLength, buf.get()); std::uninitialized_copy_n(bi->digits().Elements(), digitLength, buf.get());
} }
MOZ_TRY(xdr->codeBytes(buf.get(), length)); if(!xdr->codeBytes(buf.get(), length))
return false;
if (mode == XDR_DECODE) { if (mode == XDR_DECODE) {
BigInt* res = BigInt::createUninitialized(cx, digitLength, sign); BigInt* res = BigInt::createUninitialized(cx, digitLength, sign);
@ -3190,12 +3193,10 @@ XDRResult js::XDRBigInt(XDRState<mode>* xdr, MutableHandleBigInt bi) {
bi.set(res); bi.set(res);
} }
return Ok(); return true;
} }
template XDRResult js::XDRBigInt(XDRState<XDR_ENCODE>* xdr, template bool js::XDRBigInt(XDRState<XDR_ENCODE>* xdr, MutableHandleBigInt bi);
MutableHandleBigInt bi);
template bool js::XDRBigInt(XDRState<XDR_DECODE>* xdr, MutableHandleBigInt bi);
template XDRResult js::XDRBigInt(XDRState<XDR_DECODE>* xdr,
MutableHandleBigInt bi);
#endif

View file

@ -26,7 +26,6 @@
namespace JS { namespace JS {
#if 0 // Future XDR support
class BigInt; class BigInt;
} // namespace JS } // namespace JS
@ -34,12 +33,11 @@ class BigInt;
namespace js { namespace js {
template <XDRMode mode> template <XDRMode mode>
XDRResult XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi); bool XDRBigInt(XDRState<mode>* xdr, MutableHandle<JS::BigInt*> bi);
} // namespace js } // namespace js
namespace JS { namespace JS {
#endif
class BigInt final : public js::gc::TenuredCell { class BigInt final : public js::gc::TenuredCell {
public: public:
@ -332,11 +330,8 @@ class BigInt final : public js::gc::TenuredCell {
friend struct JSStructuredCloneReader; friend struct JSStructuredCloneReader;
friend struct JSStructuredCloneWriter; friend struct JSStructuredCloneWriter;
#if 0 // Future XDR support
template <js::XDRMode mode> template <js::XDRMode mode>
friend js::XDRResult js::XDRBigInt(js::XDRState<mode>* xdr, friend bool js::XDRBigInt(js::XDRState<mode>* xdr, MutableHandle<BigInt*> bi);
MutableHandle<BigInt*> bi);
#endif
BigInt() = delete; BigInt() = delete;
BigInt(const BigInt& other) = delete; BigInt(const BigInt& other) = delete;

View file

@ -4125,6 +4125,13 @@ CASE(JSOP_IS_CONSTRUCTING)
PUSH_MAGIC(JS_IS_CONSTRUCTING); PUSH_MAGIC(JS_IS_CONSTRUCTING);
END_CASE(JSOP_IS_CONSTRUCTING) END_CASE(JSOP_IS_CONSTRUCTING)
CASE(JSOP_BIGINT)
{
PUSH_COPY(script->getConst(GET_UINT32_INDEX(REGS.pc)));
MOZ_ASSERT(REGS.sp[-1].isBigInt());
}
END_CASE(JSOP_BIGINT)
DEFAULT() DEFAULT()
{ {
char numBuf[12]; char numBuf[12];

View file

@ -2357,14 +2357,20 @@
* Operands: * Operands:
* Stack: arg => rval * Stack: arg => rval
*/ \ */ \
macro(JSOP_DYNAMIC_IMPORT, 234, "call-import", NULL, 1, 1, 1, JOF_BYTE) macro(JSOP_DYNAMIC_IMPORT, 234, "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
*/ \
macro(JSOP_BIGINT, 235, "bigint", NULL, 5, 0, 1, JOF_BIGINT)
/* /*
* In certain circumstances it may be useful to "pad out" the opcode space to * In certain circumstances it may be useful to "pad out" the opcode space to
* a power of two. Use this macro to do so. * a power of two. Use this macro to do so.
*/ */
#define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \ #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
macro(235) \
macro(236) \ macro(236) \
macro(237) \ macro(237) \
macro(238) \ macro(238) \

View file

@ -8709,7 +8709,7 @@ js::CompileAsmJS(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList,
// generating bytecode for asm.js functions, allowing this asm.js module // generating bytecode for asm.js functions, allowing this asm.js module
// function to be the finished result. // function to be the finished result.
MOZ_ASSERT(funbox->function()->isInterpreted()); MOZ_ASSERT(funbox->function()->isInterpreted());
funbox->object = moduleFun; funbox->clobberFunction(moduleFun);
// Success! Write to the console with a "warning" message. // Success! Write to the console with a "warning" message.
*validated = true; *validated = true;