mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 721322 - Functions containing |expr.arguments| should be marked (conservatively) as using arguments. r=jorendorff
--HG-- extra : rebase_source : 3ef23e440de3244ffff8ceb30e75fe086ae3b577
This commit is contained in:
parent
d9e9735f31
commit
6cb3d45766
@ -434,18 +434,47 @@ struct TreeContext { /* tree context for semantic checks */
|
||||
return flags & TCF_FUN_MUTATES_PARAMETER;
|
||||
}
|
||||
|
||||
void noteArgumentsUse(ParseNode *pn) {
|
||||
/*
|
||||
* Accessing the implicit |arguments| local binding in a function must
|
||||
* trigger appropriate code generation such that the access works.
|
||||
*/
|
||||
void noteArgumentsNameUse(ParseNode *node) {
|
||||
JS_ASSERT(inFunction());
|
||||
countArgumentsUse(pn);
|
||||
JS_ASSERT(node->isKind(PNK_NAME));
|
||||
JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
|
||||
countArgumentsUse(node);
|
||||
flags |= TCF_FUN_USES_ARGUMENTS;
|
||||
if (funbox)
|
||||
funbox->node->pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
|
||||
void countArgumentsUse(ParseNode *pn) {
|
||||
JS_ASSERT(pn->pn_atom == parser->context->runtime->atomState.argumentsAtom);
|
||||
/*
|
||||
* Non-dynamic accesses to a property named "arguments" inside a function
|
||||
* have to deoptimize the function in case those accesses are to the
|
||||
* function's arguments. (However, this is unnecessary in strict mode
|
||||
* functions because of the f.arguments poison-pill. O frabjous day!)
|
||||
*/
|
||||
void noteArgumentsPropertyAccess(ParseNode *node) {
|
||||
JS_ASSERT(inFunction());
|
||||
JS_ASSERT(&node->asPropertyAccess().name() ==
|
||||
parser->context->runtime->atomState.argumentsAtom);
|
||||
if (!inStrictMode()) {
|
||||
flags |= TCF_FUN_USES_ARGUMENTS;
|
||||
if (funbox)
|
||||
funbox->node->pn_dflags |= PND_FUNARG;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Uses of |arguments| must be noted so that such uses can be forbidden if
|
||||
* they occur inside generator expressions (which desugar to functions and
|
||||
* yields, in which |arguments| would have an entirely different meaning).
|
||||
*/
|
||||
void countArgumentsUse(ParseNode *node) {
|
||||
JS_ASSERT(node->isKind(PNK_NAME));
|
||||
JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
|
||||
argumentsCount++;
|
||||
argumentsNode = pn;
|
||||
argumentsNode = node;
|
||||
}
|
||||
|
||||
bool needsEagerArguments() const {
|
||||
|
@ -484,6 +484,7 @@ class BreakStatement;
|
||||
class ContinueStatement;
|
||||
class XMLProcessingInstruction;
|
||||
class ConditionalExpression;
|
||||
class PropertyAccess;
|
||||
|
||||
struct ParseNode {
|
||||
private:
|
||||
@ -927,6 +928,7 @@ struct ParseNode {
|
||||
inline XMLProcessingInstruction &asXMLProcessingInstruction();
|
||||
#endif
|
||||
inline ConditionalExpression &asConditionalExpression();
|
||||
inline PropertyAccess &asPropertyAccess();
|
||||
};
|
||||
|
||||
struct NullaryNode : public ParseNode {
|
||||
@ -1230,6 +1232,14 @@ class PropertyAccess : public ParseNode {
|
||||
}
|
||||
};
|
||||
|
||||
inline PropertyAccess &
|
||||
ParseNode::asPropertyAccess()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_DOT));
|
||||
JS_ASSERT(pn_arity == PN_NAME);
|
||||
return *static_cast<PropertyAccess *>(this);
|
||||
}
|
||||
|
||||
class PropertyByValue : public ParseNode {
|
||||
public:
|
||||
PropertyByValue(ParseNode *lhs, ParseNode *propExpr,
|
||||
|
@ -4393,7 +4393,7 @@ Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext va
|
||||
pn2->pn_pos.end = init->pn_pos.end;
|
||||
|
||||
if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
|
||||
tc->noteArgumentsUse(pn2);
|
||||
tc->noteArgumentsNameUse(pn2);
|
||||
if (!blockObj)
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
}
|
||||
@ -5746,11 +5746,21 @@ Parser::memberExpr(JSBool allowCallSyntax)
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
nextMember = new_<PropertyAccess>(lhs, tokenStream.currentToken().name(),
|
||||
PropertyName *field = tokenStream.currentToken().name();
|
||||
nextMember = new_<PropertyAccess>(lhs, field,
|
||||
lhs->pn_pos.begin,
|
||||
tokenStream.currentToken().pos.end);
|
||||
if (!nextMember)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* A property access of the form |<expr>.arguments| might
|
||||
* access this function's arguments, so we need to flag a
|
||||
* potential arguments use to ensure an arguments object
|
||||
* will be created. See bug 721322.
|
||||
*/
|
||||
if (tc->inFunction() && field == context->runtime->atomState.argumentsAtom)
|
||||
tc->noteArgumentsPropertyAccess(nextMember);
|
||||
}
|
||||
}
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -6614,7 +6624,7 @@ Parser::propertyQualifiedIdentifier()
|
||||
#endif
|
||||
|
||||
ParseNode *
|
||||
Parser::identifierName(bool afterDot)
|
||||
Parser::identifierName(bool afterDoubleDot)
|
||||
{
|
||||
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
|
||||
|
||||
@ -6626,26 +6636,25 @@ Parser::identifierName(bool afterDot)
|
||||
node->setOp(JSOP_NAME);
|
||||
|
||||
if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
|
||||
name == context->runtime->atomState.argumentsAtom) {
|
||||
/*
|
||||
* Flag arguments usage so we can avoid unsafe optimizations such
|
||||
* as formal parameter assignment analysis (because of the hated
|
||||
* feature whereby arguments alias formals). We do this even for
|
||||
* a reference of the form foo.arguments, which ancient code may
|
||||
* still use instead of arguments (more hate).
|
||||
*/
|
||||
tc->noteArgumentsUse(node);
|
||||
|
||||
name == context->runtime->atomState.argumentsAtom)
|
||||
{
|
||||
/*
|
||||
* Bind early to JSOP_ARGUMENTS to relieve later code from having
|
||||
* to do this work (new rule for the emitter to count on).
|
||||
*/
|
||||
if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING)
|
||||
&& !tc->inStatement(STMT_WITH)) {
|
||||
node->setOp(JSOP_ARGUMENTS);
|
||||
node->pn_dflags |= PND_BOUND;
|
||||
if (!afterDoubleDot) {
|
||||
/*
|
||||
* Note use of |arguments| to ensure we can properly create the
|
||||
* |arguments| object for this function.
|
||||
*/
|
||||
tc->noteArgumentsNameUse(node);
|
||||
|
||||
if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
|
||||
node->setOp(JSOP_ARGUMENTS);
|
||||
node->pn_dflags |= PND_BOUND;
|
||||
}
|
||||
}
|
||||
} else if ((!afterDot
|
||||
} else if ((!afterDoubleDot
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|| (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
|
||||
#endif
|
||||
@ -6708,7 +6717,7 @@ Parser::identifierName(bool afterDot)
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
|
||||
if (afterDot) {
|
||||
if (afterDoubleDot) {
|
||||
if (!checkForFunctionNode(name, node))
|
||||
return NULL;
|
||||
}
|
||||
@ -6735,7 +6744,7 @@ Parser::starOrAtPropertyIdentifier(TokenKind tt)
|
||||
#endif
|
||||
|
||||
ParseNode *
|
||||
Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||
Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
|
||||
{
|
||||
JS_ASSERT(tokenStream.isCurrentTokenType(tt));
|
||||
|
||||
@ -7168,7 +7177,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||
#endif
|
||||
|
||||
case TOK_NAME:
|
||||
pn = identifierName(afterDot);
|
||||
pn = identifierName(afterDoubleDot);
|
||||
break;
|
||||
|
||||
case TOK_REGEXP:
|
||||
|
@ -234,7 +234,7 @@ struct Parser : private AutoGCRooter
|
||||
ParseNode *mulExpr1n();
|
||||
ParseNode *unaryExpr();
|
||||
ParseNode *memberExpr(JSBool allowCallSyntax);
|
||||
ParseNode *primaryExpr(TokenKind tt, JSBool afterDot);
|
||||
ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
|
||||
ParseNode *parenExpr(JSBool *genexp = NULL);
|
||||
|
||||
/*
|
||||
@ -259,7 +259,7 @@ struct Parser : private AutoGCRooter
|
||||
|
||||
bool checkForFunctionNode(PropertyName *name, ParseNode *node);
|
||||
|
||||
ParseNode *identifierName(bool afterDot);
|
||||
ParseNode *identifierName(bool afterDoubleDot);
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
ParseNode *endBracketedExpr();
|
||||
|
@ -0,0 +1,6 @@
|
||||
function f()
|
||||
{
|
||||
var x = <><arguments/><arguments/></>;
|
||||
x..arguments;
|
||||
}
|
||||
f();
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
* Contributor:
|
||||
* Jeff Walden <jwalden+code@mit.edu>
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 721322;
|
||||
var summary =
|
||||
'f.arguments must trigger an arguments object in non-strict mode functions';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var obj =
|
||||
{
|
||||
test: function()
|
||||
{
|
||||
var args = obj.test.arguments;
|
||||
assertEq(args !== null, true);
|
||||
assertEq(args[0], 5);
|
||||
assertEq(args[1], undefined);
|
||||
assertEq(args.length, 2);
|
||||
}
|
||||
};
|
||||
obj.test(5, undefined);
|
||||
|
||||
var sobj =
|
||||
{
|
||||
test: function()
|
||||
{
|
||||
"use strict";
|
||||
|
||||
try
|
||||
{
|
||||
var args = sobj.test.arguments;
|
||||
throw new Error("access to arguments property of strict mode " +
|
||||
"function didn't throw");
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
assertEq(e instanceof TypeError, true,
|
||||
"should have thrown TypeError, instead got: " + e);
|
||||
}
|
||||
}
|
||||
};
|
||||
sobj.test(5, undefined);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -1,4 +1,5 @@
|
||||
url-prefix ../../jsreftest.html?test=ecma_5/extensions/
|
||||
script arguments-property-access-in-function.js
|
||||
script 8.12.5-01.js
|
||||
script 15.4.4.11.js
|
||||
script 15.9.4.2.js
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
* Contributor:
|
||||
* Jeff Walden <jwalden+code@mit.edu>
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 721322;
|
||||
var summary = 'Allow f.arguments in generator expressions';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
eval("(function() { return (f.arguments for (x in [1])); })()");
|
||||
eval("(function() { var f = { arguments: 12 }; return [f.arguments for (x in [1])]; })()");
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
@ -1,4 +1,5 @@
|
||||
url-prefix ../../jsreftest.html?test=js1_8/genexps/
|
||||
script arguments-property-access-in-generator.js
|
||||
script regress-347739.js
|
||||
script regress-349012-01.js
|
||||
script regress-349326.js
|
||||
|
Loading…
Reference in New Issue
Block a user