зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1825722 - Add an ArgumentsLength parse node r=arai
By adding a separate parse node for `arguments.length` we will be able to do bytecode generation differently in some circumstances. Differential Revision: https://phabricator.services.mozilla.com/D203143
This commit is contained in:
Родитель
eda5af5f2d
Коммит
11e59aece7
|
@ -2885,7 +2885,8 @@ bool ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) {
|
|||
}
|
||||
|
||||
case ParseNodeKind::DotExpr:
|
||||
case ParseNodeKind::OptionalDotExpr: {
|
||||
case ParseNodeKind::OptionalDotExpr:
|
||||
case ParseNodeKind::ArgumentsLength: {
|
||||
PropertyAccessBase* prop = &pn->as<PropertyAccessBase>();
|
||||
MOZ_ASSERT(prop->pn_pos.encloses(prop->expression().pn_pos));
|
||||
|
||||
|
|
|
@ -925,6 +925,7 @@ restart:
|
|||
// Watch out for getters!
|
||||
case ParseNodeKind::OptionalDotExpr:
|
||||
case ParseNodeKind::DotExpr:
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
MOZ_ASSERT(pn->is<BinaryNode>());
|
||||
*answer = true;
|
||||
return true;
|
||||
|
@ -4367,6 +4368,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
|
|||
: NameOpEmitter::Kind::SimpleAssignment);
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
bool isSuper = prop->isSuper();
|
||||
|
@ -4466,6 +4468,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
|
|||
if (isCompound) {
|
||||
MOZ_ASSERT(rhs);
|
||||
switch (lhs->getKind()) {
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
if (!poe->emitGet(prop->key().atom())) {
|
||||
|
@ -4512,6 +4515,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
|
|||
}
|
||||
offset += noe->emittedBindOp();
|
||||
break;
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr:
|
||||
if (!poe->prepareForRhs()) {
|
||||
// [stack] # if Simple Assignment with Super
|
||||
|
@ -4579,6 +4583,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
if (!poe->emitAssignment(prop->key().atom())) {
|
||||
|
@ -4666,7 +4671,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
|
|||
numPushed = noe->emittedBindOp();
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
bool isSuper = prop->isSuper();
|
||||
|
@ -4802,7 +4807,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
|
||||
|
@ -7326,6 +7331,7 @@ bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode* deleteNode) {
|
|||
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr:
|
||||
case ParseNodeKind::OptionalDotExpr: {
|
||||
auto* propExpr = &kid->as<PropertyAccessBase>();
|
||||
|
@ -7978,6 +7984,7 @@ bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
|
||||
PropertyAccess* prop = &callee->as<PropertyAccess>();
|
||||
|
@ -8076,6 +8083,7 @@ bool BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, CallNode* maybeCall,
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
|
||||
PropertyAccess* prop = &callee->as<PropertyAccess>();
|
||||
|
@ -8197,6 +8205,7 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode,
|
|||
coordNode = argsList;
|
||||
|
||||
switch (calleeNode->getKind()) {
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr:
|
||||
// Use the position of a property access identifier.
|
||||
//
|
||||
|
@ -8658,6 +8667,7 @@ bool BytecodeEmitter::emitOptionalTree(
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr: {
|
||||
PropertyAccess* prop = &pn->as<PropertyAccess>();
|
||||
bool isSuper = prop->isSuper();
|
||||
|
@ -9015,6 +9025,7 @@ bool BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage) {
|
|||
MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(UnaryNode* incDec,
|
||||
ValueUsage valueUsage) {
|
||||
switch (incDec->kid()->getKind()) {
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::DotExpr:
|
||||
return emitPropIncDec(incDec, valueUsage);
|
||||
case ParseNodeKind::ElemExpr:
|
||||
|
@ -12502,6 +12513,24 @@ bool BytecodeEmitter::emitTree(
|
|||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::ArgumentsLength: {
|
||||
PropOpEmitter poe(this, PropOpEmitter::Kind::Get,
|
||||
PropOpEmitter::ObjKind::Other);
|
||||
if (!poe.prepareForObj()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NameOpEmitter noe(this, TaggedParserAtomIndex::WellKnown::arguments(),
|
||||
NameOpEmitter::Kind::Get);
|
||||
if (!noe.emitGet()) {
|
||||
return false;
|
||||
}
|
||||
if (!poe.emitGet(TaggedParserAtomIndex::WellKnown::length())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::ElemExpr: {
|
||||
PropertyByValue* elem = &pn->as<PropertyByValue>();
|
||||
bool isSuper = elem->isSuper();
|
||||
|
|
|
@ -407,6 +407,7 @@ restart:
|
|||
case ParseNodeKind::ObjectExpr:
|
||||
case ParseNodeKind::PropertyNameExpr:
|
||||
case ParseNodeKind::DotExpr:
|
||||
case ParseNodeKind::ArgumentsLength:
|
||||
case ParseNodeKind::ElemExpr:
|
||||
case ParseNodeKind::Arguments:
|
||||
case ParseNodeKind::CallExpr:
|
||||
|
|
|
@ -103,7 +103,8 @@ class FullParseHandler {
|
|||
bool isPropertyOrPrivateMemberAccess(Node node) {
|
||||
return node->isKind(ParseNodeKind::DotExpr) ||
|
||||
node->isKind(ParseNodeKind::ElemExpr) ||
|
||||
node->isKind(ParseNodeKind::PrivateMemberExpr);
|
||||
node->isKind(ParseNodeKind::PrivateMemberExpr) ||
|
||||
node->isKind(ParseNodeKind::ArgumentsLength);
|
||||
}
|
||||
|
||||
bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
|
||||
|
@ -887,6 +888,11 @@ class FullParseHandler {
|
|||
key->pn_pos.end);
|
||||
}
|
||||
|
||||
ArgumentsLengthResult newArgumentsLength(Node expr, NameNodeType key) {
|
||||
return newResult<ArgumentsLength>(expr, key, expr->pn_pos.begin,
|
||||
key->pn_pos.end);
|
||||
}
|
||||
|
||||
PropertyByValueResult newPropertyByValue(Node lhs, Node index, uint32_t end) {
|
||||
return newResult<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
|
||||
}
|
||||
|
@ -1137,6 +1143,12 @@ class FullParseHandler {
|
|||
TaggedParserAtomIndex::WellKnown::arguments();
|
||||
}
|
||||
|
||||
bool isLengthName(Node node) {
|
||||
return node->isKind(ParseNodeKind::PropertyNameExpr) &&
|
||||
node->as<NameNode>().atom() ==
|
||||
TaggedParserAtomIndex::WellKnown::length();
|
||||
}
|
||||
|
||||
bool isEvalName(Node node) {
|
||||
return node->isKind(ParseNodeKind::Name) &&
|
||||
node->as<NameNode>().atom() ==
|
||||
|
|
|
@ -75,6 +75,7 @@ class FunctionBox;
|
|||
F(PostDecrementExpr, UnaryNode) \
|
||||
F(PropertyNameExpr, NameNode) \
|
||||
F(DotExpr, PropertyAccess) \
|
||||
F(ArgumentsLength, ArgumentsLength) \
|
||||
F(ElemExpr, PropertyByValue) \
|
||||
F(PrivateMemberExpr, PrivateMemberAccess) \
|
||||
F(OptionalDotExpr, OptionalPropertyAccess) \
|
||||
|
@ -616,6 +617,7 @@ inline bool IsTypeofKind(ParseNodeKind kind) {
|
|||
MACRO(ClassNames) \
|
||||
MACRO(ForNode) \
|
||||
MACRO(PropertyAccess) \
|
||||
MACRO(ArgumentsLength) \
|
||||
MACRO(OptionalPropertyAccess) \
|
||||
MACRO(PropertyByValue) \
|
||||
MACRO(OptionalPropertyByValue) \
|
||||
|
@ -2014,7 +2016,8 @@ class PropertyAccessBase : public BinaryNode {
|
|||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(ParseNodeKind::DotExpr) ||
|
||||
node.isKind(ParseNodeKind::OptionalDotExpr);
|
||||
node.isKind(ParseNodeKind::OptionalDotExpr) ||
|
||||
node.isKind(ParseNodeKind::ArgumentsLength);
|
||||
MOZ_ASSERT_IF(match, node.is<BinaryNode>());
|
||||
MOZ_ASSERT_IF(match, node.as<BinaryNode>().right()->isKind(
|
||||
ParseNodeKind::PropertyNameExpr));
|
||||
|
@ -2042,7 +2045,8 @@ class PropertyAccess : public PropertyAccessBase {
|
|||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(ParseNodeKind::DotExpr);
|
||||
bool match = node.isKind(ParseNodeKind::DotExpr) ||
|
||||
node.isKind(ParseNodeKind::ArgumentsLength);
|
||||
MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
|
||||
return match;
|
||||
}
|
||||
|
@ -2051,6 +2055,26 @@ class PropertyAccess : public PropertyAccessBase {
|
|||
// ParseNodeKind::SuperBase cannot result from any expression syntax.
|
||||
return expression().isKind(ParseNodeKind::SuperBase);
|
||||
}
|
||||
|
||||
protected:
|
||||
using PropertyAccessBase::PropertyAccessBase;
|
||||
};
|
||||
|
||||
class ArgumentsLength : public PropertyAccess {
|
||||
public:
|
||||
ArgumentsLength(ParseNode* lhs, NameNode* name, uint32_t begin, uint32_t end)
|
||||
: PropertyAccess(ParseNodeKind::ArgumentsLength, lhs, name, begin, end) {
|
||||
MOZ_ASSERT(lhs);
|
||||
MOZ_ASSERT(name);
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
bool match = node.isKind(ParseNodeKind::ArgumentsLength);
|
||||
MOZ_ASSERT_IF(match, node.is<PropertyAccessBase>());
|
||||
return match;
|
||||
}
|
||||
|
||||
bool isSuper() const { return false; }
|
||||
};
|
||||
|
||||
class OptionalPropertyAccess : public PropertyAccessBase {
|
||||
|
|
|
@ -10926,6 +10926,11 @@ GeneralParser<ParseHandler, Unit>::memberPropertyAccess(
|
|||
MOZ_ASSERT(!handler_.isSuperBase(lhs));
|
||||
return handler_.newOptionalPropertyAccess(lhs, name);
|
||||
}
|
||||
|
||||
if (handler_.isArgumentsName(lhs) && handler_.isLengthName(name)) {
|
||||
return handler_.newArgumentsLength(lhs, name);
|
||||
}
|
||||
|
||||
return handler_.newPropertyAccess(lhs, name);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,9 @@ enum SyntaxParseHandlerNode {
|
|||
// casing.
|
||||
NodeName,
|
||||
|
||||
// Nodes representing the names "arguments" and "eval".
|
||||
// Nodes representing the names "arguments", "length" and "eval".
|
||||
NodeArgumentsName,
|
||||
NodeLengthName,
|
||||
NodeEvalName,
|
||||
|
||||
// Node representing the "async" name, which may actually be a
|
||||
|
@ -77,6 +78,10 @@ enum SyntaxParseHandlerNode {
|
|||
NodePrivateMemberAccess,
|
||||
NodeOptionalPrivateMemberAccess,
|
||||
|
||||
// Node representing the compound Arguments.length expression;
|
||||
// Used only for property access, not assignment.
|
||||
NodeArgumentsLength,
|
||||
|
||||
// Destructuring target patterns can't be parenthesized: |([a]) = [3];|
|
||||
// must be a syntax error. (We can't use NodeGeneric instead of these
|
||||
// because that would trigger invalid-left-hand-side ReferenceError
|
||||
|
@ -164,7 +169,7 @@ class SyntaxParseHandler {
|
|||
|
||||
bool isPropertyOrPrivateMemberAccess(Node node) {
|
||||
return node == NodeDottedProperty || node == NodeElement ||
|
||||
node == NodePrivateMemberAccess;
|
||||
node == NodePrivateMemberAccess || node == NodeArgumentsLength;
|
||||
}
|
||||
|
||||
bool isOptionalPropertyOrPrivateMemberAccess(Node node) {
|
||||
|
@ -210,6 +215,9 @@ class SyntaxParseHandler {
|
|||
if (name == TaggedParserAtomIndex::WellKnown::arguments()) {
|
||||
return NodeArgumentsName;
|
||||
}
|
||||
if (name == TaggedParserAtomIndex::WellKnown::length()) {
|
||||
return NodeLengthName;
|
||||
}
|
||||
if (pos.begin + strlen("async") == pos.end &&
|
||||
name == TaggedParserAtomIndex::WellKnown::async()) {
|
||||
return NodePotentialAsyncKeyword;
|
||||
|
@ -579,6 +587,10 @@ class SyntaxParseHandler {
|
|||
return NodeDottedProperty;
|
||||
}
|
||||
|
||||
PropertyAccessResult newArgumentsLength(Node expr, NameNodeType key) {
|
||||
return NodeArgumentsLength;
|
||||
}
|
||||
|
||||
PropertyAccessResult newOptionalPropertyAccess(Node expr, NameNodeType key) {
|
||||
return NodeOptionalDottedProperty;
|
||||
}
|
||||
|
@ -777,10 +789,12 @@ class SyntaxParseHandler {
|
|||
|
||||
bool isName(Node node) {
|
||||
return node == NodeName || node == NodeArgumentsName ||
|
||||
node == NodeEvalName || node == NodePotentialAsyncKeyword;
|
||||
node == NodeLengthName || node == NodeEvalName ||
|
||||
node == NodePotentialAsyncKeyword;
|
||||
}
|
||||
|
||||
bool isArgumentsName(Node node) { return node == NodeArgumentsName; }
|
||||
bool isLengthName(Node node) { return node == NodeLengthName; }
|
||||
bool isEvalName(Node node) { return node == NodeEvalName; }
|
||||
bool isAsyncKeyword(Node node) { return node == NodePotentialAsyncKeyword; }
|
||||
|
||||
|
@ -795,7 +809,8 @@ class SyntaxParseHandler {
|
|||
// |this|. It's not really eligible for the funapply/funcall
|
||||
// optimizations as they're currently implemented (assuming a single
|
||||
// value is used for both retrieval and |this|).
|
||||
if (node != NodeDottedProperty && node != NodeOptionalDottedProperty) {
|
||||
if (node != NodeDottedProperty && node != NodeOptionalDottedProperty &&
|
||||
node != NodeArgumentsLength) {
|
||||
return TaggedParserAtomIndex::null();
|
||||
}
|
||||
return lastAtom;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// |reftest| skip-if(!xulRuntime.shell)
|
||||
|
||||
// Test reflect.parse on a function with arguments.length
|
||||
let ast = Reflect.parse(`function f10() {
|
||||
return arguments.length;
|
||||
}`);
|
||||
|
||||
assertEq(ast.body[0].body.body[0].argument.object.type, "Identifier");
|
||||
assertEq(ast.body[0].body.body[0].argument.object.name, "arguments");
|
||||
assertEq(ast.body[0].body.body[0].argument.property.type, "Identifier");
|
||||
assertEq(ast.body[0].body.body[0].argument.property.name, "length");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0, "ok");
|
Загрузка…
Ссылка в новой задаче