Commit 69335a5d authored by kocienda's avatar kocienda

Reviewed by Gramps and Ken.

	Checked in by Ken.

	- fixed 3134693 -- carsdirect.com crash on used car search, due to large JavaScript array

	The parser was using recursion to handle many types of lists.
	This meant that we crashed out of stack space when any of the lists were extra big.
	I applied the same sort of fix we had already applied a while back for argument lists for
	all the other types of lists, including the list of ElementNode that was the reason for
	the crash reported here.

        * kjs/grammar.y: Removed ElisionNode altogether and just use a count.
	Use specific node types for PropertyNameAndValueList and PropertyName.

        * kjs/grammar.cpp: Regenerated.
        * kjs/grammar.cpp.h: Regenerated.
        * kjs/grammar.h: Regenerated.

        * kjs/nodes.h: Elide "ElisionNode", changing objects to keep elision counts instead.
	Make the ObjectLiteralNode list field be PropertyValueNode, not just Node.
	Make PropertyValueNode fields have specific types. Add new reverse list functions, calls
	to those functions in the constructors, and friend declarations as needed so the class
	that holds the head of a list can reverse the list during parsing.
        * kjs/nodes.cpp:
        (ElementNode::ref): Use iteration instead of recursion. Also elide "elision".
        (ElementNode::deref): Ditto.
        (ElementNode::evaluate): Use iteration instead of recursion, taking advantage of
	the fact that the linked list is reversed. Also use the elision count rather than
	an elision list.
        (ArrayNode::reverseElementList): Reverse the list so we can iterate normally.
        (ArrayNode::ref): Elide "elision".
        (ArrayNode::deref): Ditto.
        (ArrayNode::evaluate): Use elision count instead of elision list.
        (ObjectLiteralNode::reverseList): Reverse the list so we can iterate normally.
        (PropertyValueNode::ref): Use iteration instead of recursion.
        (PropertyValueNode::deref): Use iteration instead of recursion.
        (PropertyValueNode::evaluate): Use iteration instead of recursion, taking advantage
	of the fact that the linked list is reversed.
        (ArgumentListNode::ref): Change code to match the other similar cases we had to revise.
        (ArgumentListNode::deref): Ditto.
        (ArgumentListNode::evaluateList): Ditto.
        (ArgumentsNode::reverseList): Ditto.
        (VarDeclListNode::ref): Use iteration instead of recursion.
        (VarDeclListNode::deref): Ditto.
        (VarDeclListNode::evaluate): Use iteration instead of recursion, taking advantage
	of the fact that the linked list is reversed.
        (VarDeclListNode::processVarDecls): Ditto.
        (VarStatementNode::reverseList): Reverse the list so we can iterate normally.
        (FunctionBodyNode::FunctionBodyNode): Use BlockNode as the base class, removing
	most of the FunctionBodyNode class.

        * kjs/nodes2string.cpp:
        (ElementNode::streamTo): Update for using a count for elision, and reverse linking.
        (ArrayNode::streamTo): Update for using a count for elision.
        (PropertyValueNode::streamTo): Update for reverse linking.
        (ArgumentListNode::streamTo): Update for reverse linking. This has been wrong for
	a while, since we added the reverse a long time ago.
        (VarDeclListNode::streamTo): Update for reverse linking.
        (ParameterNode::streamTo): Update for reverse linking.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@3192 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 7570c92e
2002-12-23 Darin Adler <darin@apple.com>
Reviewed by Gramps and Ken.
Checked in by Ken.
- fixed 3134693 -- carsdirect.com crash on used car search, due to large JavaScript array
The parser was using recursion to handle many types of lists.
This meant that we crashed out of stack space when any of the lists were extra big.
I applied the same sort of fix we had already applied a while back for argument lists for
all the other types of lists, including the list of ElementNode that was the reason for
the crash reported here.
* kjs/grammar.y: Removed ElisionNode altogether and just use a count.
Use specific node types for PropertyNameAndValueList and PropertyName.
* kjs/grammar.cpp: Regenerated.
* kjs/grammar.cpp.h: Regenerated.
* kjs/grammar.h: Regenerated.
* kjs/nodes.h: Elide "ElisionNode", changing objects to keep elision counts instead.
Make the ObjectLiteralNode list field be PropertyValueNode, not just Node.
Make PropertyValueNode fields have specific types. Add new reverse list functions, calls
to those functions in the constructors, and friend declarations as needed so the class
that holds the head of a list can reverse the list during parsing.
* kjs/nodes.cpp:
(ElementNode::ref): Use iteration instead of recursion. Also elide "elision".
(ElementNode::deref): Ditto.
(ElementNode::evaluate): Use iteration instead of recursion, taking advantage of
the fact that the linked list is reversed. Also use the elision count rather than
an elision list.
(ArrayNode::reverseElementList): Reverse the list so we can iterate normally.
(ArrayNode::ref): Elide "elision".
(ArrayNode::deref): Ditto.
(ArrayNode::evaluate): Use elision count instead of elision list.
(ObjectLiteralNode::reverseList): Reverse the list so we can iterate normally.
(PropertyValueNode::ref): Use iteration instead of recursion.
(PropertyValueNode::deref): Use iteration instead of recursion.
(PropertyValueNode::evaluate): Use iteration instead of recursion, taking advantage
of the fact that the linked list is reversed.
(ArgumentListNode::ref): Change code to match the other similar cases we had to revise.
(ArgumentListNode::deref): Ditto.
(ArgumentListNode::evaluateList): Ditto.
(ArgumentsNode::reverseList): Ditto.
(VarDeclListNode::ref): Use iteration instead of recursion.
(VarDeclListNode::deref): Ditto.
(VarDeclListNode::evaluate): Use iteration instead of recursion, taking advantage
of the fact that the linked list is reversed.
(VarDeclListNode::processVarDecls): Ditto.
(VarStatementNode::reverseList): Reverse the list so we can iterate normally.
(FunctionBodyNode::FunctionBodyNode): Use BlockNode as the base class, removing
most of the FunctionBodyNode class.
* kjs/nodes2string.cpp:
(ElementNode::streamTo): Update for using a count for elision, and reverse linking.
(ArrayNode::streamTo): Update for using a count for elision.
(PropertyValueNode::streamTo): Update for reverse linking.
(ArgumentListNode::streamTo): Update for reverse linking. This has been wrong for
a while, since we added the reverse a long time ago.
(VarDeclListNode::streamTo): Update for reverse linking.
(ParameterNode::streamTo): Update for reverse linking.
=== Alexander-45 ===
2002-12-22 Darin Adler <darin@apple.com>
......
2002-12-23 Darin Adler <darin@apple.com>
Reviewed by Gramps and Ken.
Checked in by Ken.
- fixed 3134693 -- carsdirect.com crash on used car search, due to large JavaScript array
The parser was using recursion to handle many types of lists.
This meant that we crashed out of stack space when any of the lists were extra big.
I applied the same sort of fix we had already applied a while back for argument lists for
all the other types of lists, including the list of ElementNode that was the reason for
the crash reported here.
* kjs/grammar.y: Removed ElisionNode altogether and just use a count.
Use specific node types for PropertyNameAndValueList and PropertyName.
* kjs/grammar.cpp: Regenerated.
* kjs/grammar.cpp.h: Regenerated.
* kjs/grammar.h: Regenerated.
* kjs/nodes.h: Elide "ElisionNode", changing objects to keep elision counts instead.
Make the ObjectLiteralNode list field be PropertyValueNode, not just Node.
Make PropertyValueNode fields have specific types. Add new reverse list functions, calls
to those functions in the constructors, and friend declarations as needed so the class
that holds the head of a list can reverse the list during parsing.
* kjs/nodes.cpp:
(ElementNode::ref): Use iteration instead of recursion. Also elide "elision".
(ElementNode::deref): Ditto.
(ElementNode::evaluate): Use iteration instead of recursion, taking advantage of
the fact that the linked list is reversed. Also use the elision count rather than
an elision list.
(ArrayNode::reverseElementList): Reverse the list so we can iterate normally.
(ArrayNode::ref): Elide "elision".
(ArrayNode::deref): Ditto.
(ArrayNode::evaluate): Use elision count instead of elision list.
(ObjectLiteralNode::reverseList): Reverse the list so we can iterate normally.
(PropertyValueNode::ref): Use iteration instead of recursion.
(PropertyValueNode::deref): Use iteration instead of recursion.
(PropertyValueNode::evaluate): Use iteration instead of recursion, taking advantage
of the fact that the linked list is reversed.
(ArgumentListNode::ref): Change code to match the other similar cases we had to revise.
(ArgumentListNode::deref): Ditto.
(ArgumentListNode::evaluateList): Ditto.
(ArgumentsNode::reverseList): Ditto.
(VarDeclListNode::ref): Use iteration instead of recursion.
(VarDeclListNode::deref): Ditto.
(VarDeclListNode::evaluate): Use iteration instead of recursion, taking advantage
of the fact that the linked list is reversed.
(VarDeclListNode::processVarDecls): Ditto.
(VarStatementNode::reverseList): Reverse the list so we can iterate normally.
(FunctionBodyNode::FunctionBodyNode): Use BlockNode as the base class, removing
most of the FunctionBodyNode class.
* kjs/nodes2string.cpp:
(ElementNode::streamTo): Update for using a count for elision, and reverse linking.
(ArrayNode::streamTo): Update for using a count for elision.
(PropertyValueNode::streamTo): Update for reverse linking.
(ArgumentListNode::streamTo): Update for reverse linking. This has been wrong for
a while, since we added the reverse a long time ago.
(VarDeclListNode::streamTo): Update for reverse linking.
(ParameterNode::streamTo): Update for reverse linking.
=== Alexander-45 ===
2002-12-22 Darin Adler <darin@apple.com>
......
This diff is collapsed.
......@@ -21,8 +21,9 @@ typedef union {
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
ElisionNode *eli;
Operator op;
PropertyValueNode *plist;
PropertyNode *pnode;
} YYSTYPE;
#ifndef YYLTYPE
......
......@@ -21,8 +21,9 @@ typedef union {
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
ElisionNode *eli;
Operator op;
PropertyValueNode *plist;
PropertyNode *pnode;
} YYSTYPE;
#ifndef YYLTYPE
......
......@@ -72,8 +72,9 @@ using namespace KJS;
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
ElisionNode *eli;
Operator op;
PropertyValueNode *plist;
PropertyNode *pnode;
}
%start Program
......@@ -118,7 +119,7 @@ using namespace KJS;
/* non-terminal types */
%type <node> Literal PrimaryExpr Expr MemberExpr FunctionExpr NewExpr CallExpr
%type <node> ArrayLiteral PropertyName PropertyNameAndValueList
%type <node> ArrayLiteral
%type <node> LeftHandSideExpr PostfixExpr UnaryExpr
%type <node> MultiplicativeExpr AdditiveExpr
%type <node> ShiftExpr RelationalExpr EqualityExpr
......@@ -152,8 +153,10 @@ using namespace KJS;
%type <cblk> CaseBlock
%type <ccl> CaseClause DefaultClause
%type <clist> CaseClauses CaseClausesOpt
%type <eli> Elision ElisionOpt
%type <ival> Elision ElisionOpt
%type <elm> ElementList
%type <plist> PropertyNameAndValueList
%type <pnode> PropertyName
%%
......@@ -196,13 +199,13 @@ ElementList:
;
ElisionOpt:
/* nothing */ { $$ = 0L; }
/* nothing */ { $$ = 0; }
| Elision
;
Elision:
',' { $$ = new ElisionNode(0L); }
| Elision ',' { $$ = new ElisionNode($1); }
',' { $$ = 1; }
| Elision ',' { $$ = $1 + 1; }
;
PropertyNameAndValueList:
......
......@@ -83,6 +83,7 @@ using namespace KJS;
#ifdef KJS_DEBUG_MEM
std::list<Node *> * Node::s_nodes = 0L;
#endif
// ------------------------------ Node -----------------------------------------
Node::Node()
......@@ -263,98 +264,69 @@ Value GroupNode::evaluate(ExecState *exec)
return group->evaluate(exec);
}
// ------------------------------ ElisionNode ----------------------------------
void ElisionNode::ref()
{
Node::ref();
if ( elision )
elision->ref();
}
bool ElisionNode::deref()
{
if ( elision && elision->deref() )
delete elision;
return Node::deref();
}
// ECMA 11.1.4
Value ElisionNode::evaluate(ExecState *exec)
{
if (elision)
return Number(elision->evaluate(exec).toNumber(exec) + 1);
else
return Number(1);
}
// ------------------------------ ElementNode ----------------------------------
void ElementNode::ref()
{
Node::ref();
if ( list )
list->ref();
if ( elision )
elision->ref();
if ( node )
node->ref();
for (ElementNode *n = this; n; n = n->list) {
n->Node::ref();
if (n->node)
n->node->ref();
}
}
bool ElementNode::deref()
{
if ( list && list->deref() )
delete list;
if ( elision && elision->deref() )
delete elision;
if ( node && node->deref() )
delete node;
ElementNode *next;
for (ElementNode *n = this; n; n = next) {
next = n->list;
if (n->node && n->node->deref())
delete n->node;
if (n != this && n->Node::deref())
delete n;
}
return Node::deref();
}
// ECMA 11.1.4
Value ElementNode::evaluate(ExecState *exec)
{
Object array;
Value val;
Object array = exec->interpreter()->builtinArray().construct(exec, List::empty());
int length = 0;
int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0;
KJS_CHECKEXCEPTIONVALUE
if (list) {
array = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp()));
KJS_CHECKEXCEPTIONVALUE
val = node->evaluate(exec);
length = array.get(exec,lengthPropertyName).toInt32(exec);
} else {
Value newArr = exec->interpreter()->builtinArray().construct(exec,List::empty());
array = Object(static_cast<ObjectImp*>(newArr.imp()));
val = node->evaluate(exec);
for (ElementNode *n = this; n; n = n->list) {
Value val = n->node->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
length += n->elision;
array.put(exec, length++, val);
}
array.put(exec, elisionLen + length, val);
return array;
}
// ------------------------------ ArrayNode ------------------------------------
void ArrayNode::reverseElementList()
{
ElementNode *head = 0;
ElementNode *next;
for (ElementNode *n = element; n; n = next) {
next = n->list;
n->list = head;
head = n;
}
element = head;
}
void ArrayNode::ref()
{
Node::ref();
if ( element )
element->ref();
if ( elision )
elision->ref();
}
bool ArrayNode::deref()
{
if ( element && element->deref() )
delete element;
if ( elision && elision->deref() )
delete elision;
return Node::deref();
}
......@@ -363,8 +335,6 @@ Value ArrayNode::evaluate(ExecState *exec)
{
Object array;
int length;
int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0;
KJS_CHECKEXCEPTIONVALUE
if (element) {
array = Object(static_cast<ObjectImp*>(element->evaluate(exec).imp()));
......@@ -377,13 +347,25 @@ Value ArrayNode::evaluate(ExecState *exec)
}
if (opt)
array.put(exec,lengthPropertyName, Number(elisionLen + length), DontEnum | DontDelete);
array.put(exec,lengthPropertyName, Number(elision + length), DontEnum | DontDelete);
return array;
}
// ------------------------------ ObjectLiteralNode ----------------------------
void ObjectLiteralNode::reverseList()
{
PropertyValueNode *head = 0;
PropertyValueNode *next;
for (PropertyValueNode *n = list; n; n = next) {
next = n->list;
n->list = head;
head = n;
}
list = head;
}
void ObjectLiteralNode::ref()
{
Node::ref();
......@@ -411,44 +393,43 @@ Value ObjectLiteralNode::evaluate(ExecState *exec)
void PropertyValueNode::ref()
{
Node::ref();
if ( name )
name->ref();
if ( assign )
assign->ref();
if ( list )
list->ref();
for (PropertyValueNode *n = this; n; n = n->list) {
n->Node::ref();
if (n->name)
n->name->ref();
if (n->assign)
n->assign->ref();
}
}
bool PropertyValueNode::deref()
{
if ( name && name->deref() )
delete name;
if ( assign && assign->deref() )
delete assign;
if ( list && list->deref() )
delete list;
PropertyValueNode *next;
for (PropertyValueNode *n = this; n; n = next) {
next = n->list;
if ( n->name && n->name->deref() )
delete n->name;
if ( n->assign && n->assign->deref() )
delete n->assign;
if (n != this && n->Node::deref() )
delete n;
}
return Node::deref();
}
// ECMA 11.1.5
Value PropertyValueNode::evaluate(ExecState *exec)
{
Object obj;
if (list) {
obj = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp()));
Object obj = exec->interpreter()->builtinObject().construct(exec, List::empty());
for (PropertyValueNode *p = this; p; p = p->list) {
Value n = p->name->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
Value v = p->assign->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
}
else {
Value newObj = exec->interpreter()->builtinObject().construct(exec,List::empty());
obj = Object(static_cast<ObjectImp*>(newObj.imp()));
}
Value n = name->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
Value v = assign->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
obj.put(exec, Identifier(n.toString(exec)), v);
obj.put(exec, Identifier(n.toString(exec)), v);
}
return obj;
}
......@@ -553,37 +534,23 @@ ArgumentListNode::ArgumentListNode(ArgumentListNode *l, Node *e)
void ArgumentListNode::ref()
{
ArgumentListNode *l = this;
while (l != NULL) {
l->Node::ref();
if ( l->expr )
l->expr->ref();
l = l->list;
for (ArgumentListNode *n = this; n; n = n->list) {
n->Node::ref();
if (n->expr)
n->expr->ref();
}
}
bool ArgumentListNode::deref()
{
if ( expr && expr->deref() )
delete expr;
ArgumentListNode *l = this->list;
while (l != NULL) {
if ( l->expr && l->expr->deref() )
delete l->expr;
ArgumentListNode *next = l->list;
if (l->Node::deref()) {
l->list = NULL;
delete l;
}
l = next;
ArgumentListNode *next;
for (ArgumentListNode *n = this; n; n = next) {
next = n->list;
if (n->expr && n->expr->deref())
delete n->expr;
if (n != this && n->Node::deref())
delete n;
}
return Node::deref();
}
......@@ -598,15 +565,10 @@ List ArgumentListNode::evaluateList(ExecState *exec)
{
List l;
ArgumentListNode *n = this;
while (n != NULL) {
for (ArgumentListNode *n = this; n; n = n->list) {
Value v = n->expr->evaluate(exec);
KJS_CHECKEXCEPTIONLIST
l.append(v);
n = n->list;
}
return l;
......@@ -614,21 +576,16 @@ List ArgumentListNode::evaluateList(ExecState *exec)
// ------------------------------ ArgumentsNode --------------------------------
ArgumentsNode::ArgumentsNode(ArgumentListNode *l) : list(l)
void ArgumentsNode::reverseList()
{
if (list == NULL) {
return;
}
ArgumentListNode *prev = list;
ArgumentListNode *cur = prev->list;
while (cur != NULL) {
prev->list = cur->list;
cur->list = list;
list = cur;
cur = prev->list;
ArgumentListNode *head = 0;
ArgumentListNode *next;
for (ArgumentListNode *n = list; n; n = next) {
next = n->list;
n->list = head;
head = n;
}
list = head;
}
void ArgumentsNode::ref()
......@@ -1670,19 +1627,23 @@ void VarDeclNode::processVarDecls(ExecState *exec)
void VarDeclListNode::ref()
{
Node::ref();
if ( list )
list->ref();
if ( var )
var->ref();
for (VarDeclListNode *n = this; n; n = n->list) {
n->Node::ref();
if (n->var)
n->var->ref();
}
}
bool VarDeclListNode::deref()
{
if ( list && list->deref() )
delete list;
if ( var && var->deref() )
delete var;
VarDeclListNode *next;
for (VarDeclListNode *n = this; n; n = next) {
next = n->list;
if (n->var && n->var->deref())
delete n->var;
if (n != this && n->Node::deref())
delete n;
}
return Node::deref();
}
......@@ -1690,26 +1651,33 @@ bool VarDeclListNode::deref()
// ECMA 12.2
Value VarDeclListNode::evaluate(ExecState *exec)
{
if (list)
(void) list->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
(void) var->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
for (VarDeclListNode *n = this; n; n = n->list) {
n->var->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
}
return Undefined();
}
void VarDeclListNode::processVarDecls(ExecState *exec)
{
if (list)
list->processVarDecls(exec);
var->processVarDecls(exec);
for (VarDeclListNode *n = this; n; n = n->list)
n->var->processVarDecls(exec);
}
// ------------------------------ VarStatementNode -----------------------------
void VarStatementNode::reverseList()
{
VarDeclListNode *head = 0;
VarDeclListNode *next;
for (VarDeclListNode *n = list; n; n = next) {
next = n->list;
n->list = head;
head = n;
}
list = head;
}
void VarStatementNode::ref()
{
Node::ref();
......@@ -2714,54 +2682,19 @@ Value ParameterNode::evaluate(ExecState */*exec*/)
// ------------------------------ FunctionBodyNode -----------------------------
FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
: source(s)
: BlockNode(s)
{
setLoc(-1, -1, -1);
//fprintf(stderr,"FunctionBodyNode::FunctionBodyNode %p\n",this);
}
void FunctionBodyNode::ref()
{
Node::ref();
if ( source )
source->ref();
//fprintf( stderr, "FunctionBodyNode::ref() %p. Refcount now %d\n", (void*)this, refcount);
}
bool FunctionBodyNode::deref()
{
if ( source && source->deref() )
delete source;