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:
Andy Wingo 2018-11-15 15:01:09 +00:00
parent 7e8a95c1c9
commit 907dd759ae
31 changed files with 662 additions and 74 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -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, "'${'") \

View File

@ -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))

View File

@ -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|.

View 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
});

View File

@ -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()
{

View File

@ -54,6 +54,7 @@ namespace jit {
_(JSOP_UINT24) \
_(JSOP_RESUMEINDEX) \
_(JSOP_DOUBLE) \
IF_BIGINT(_(JSOP_BIGINT),) \
_(JSOP_STRING) \
_(JSOP_SYMBOL) \
_(JSOP_OBJECT) \

View File

@ -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();

View File

@ -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")));

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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 */

View File

@ -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];

View File

@ -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++

View File

@ -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) {

View File

@ -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) \

View File

@ -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;