Divorce analyzeFunctions() and friends from class js::Parser. Bug 696953, part 4 of 4. r=Waldo.

--HG--
rename : js/src/frontend/Parser.cpp => js/src/frontend/SemanticAnalysis.cpp
extra : rebase_source : 735796e90d053bc979060c2b988926954b90f435
This commit is contained in:
Jason Orendorff 2011-10-27 21:16:32 -05:00
parent 2a7055f71e
commit 1486a1a05f
6 changed files with 100 additions and 48 deletions

View File

@ -44,6 +44,7 @@
#include "frontend/BytecodeEmitter.h"
#include "frontend/FoldConstants.h"
#include "frontend/SemanticAnalysis.h"
#include "vm/GlobalObject.h"
#include "jsinferinlines.h"
@ -286,7 +287,7 @@ frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerF
if (!FoldConstants(cx, pn, &bce))
goto out;
if (!parser.analyzeFunctions(&bce))
if (!AnalyzeFunctions(&bce))
goto out;
bce.functionList = NULL;
@ -446,7 +447,7 @@ frontend::CompileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipals *prin
} else if (!FoldConstants(cx, pn, &funbce)) {
/* FoldConstants reported the error already. */
pn = NULL;
} else if (!parser.analyzeFunctions(&funbce)) {
} else if (!AnalyzeFunctions(&funbce)) {
pn = NULL;
} else {
if (fn->pn_body) {

View File

@ -212,8 +212,8 @@ class NodeStack {
/*
* Push the children of |pn| on |stack|. Return true if |pn| itself could be
* safely recycled, or false if it must be cleaned later (pn_used and pn_defn
* nodes, and all function nodes; see comments for
* js::Parser::cleanFunctionList). Some callers want to free |pn|; others
* nodes, and all function nodes; see comments for CleanFunctionList in
* SemanticAnalysis.cpp). Some callers want to free |pn|; others
* (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
* just need to take care of its children.
*/
@ -228,12 +228,12 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
* update them now could result in quadratic behavior when recycling
* trees containing many functions; and the lists can be very long. So
* we put off cleaning the lists up until just before function
* analysis, when we call js::Parser::cleanFunctionList.
* analysis, when we call CleanFunctionList.
*
* In fact, we can't recycle the parse node yet, either: it may appear
* on a method list, and reusing the node would corrupt that. Instead,
* we clear its pn_funbox pointer to mark it as deleted;
* js::Parser::cleanFunctionList recycles it as well.
* CleanFunctionList recycles it as well.
*
* We do recycle the nodes around it, though, so we must clear pointers
* to them to avoid leaving dangling references where someone can find

View File

@ -899,8 +899,8 @@ struct Definition : public ParseNode
* We store definition pointers in PN_NAMESET AtomDefnMapPtrs in the AST,
* but due to redefinition these nodes may become uses of other
* definitions. This is unusual, so we simply chase the pn_lexdef link to
* find the final definition node. See methods called from
* Parser::analyzeFunctions.
* find the final definition node. See functions called from
* js::frontend::AnalyzeFunctions.
*
* FIXME: MakeAssignment mutates for want of a parent link...
*/

View File

@ -128,17 +128,6 @@ struct Parser : private AutoGCRooter
*/
JSFunction *newFunction(TreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind);
/*
* Analyze the tree of functions nested within a single compilation unit,
* starting at funbox, recursively walking its kids, then following its
* siblings, their kids, etc.
*/
bool analyzeFunctions(TreeContext *tc);
void cleanFunctionList(FunctionBox **funbox);
bool markFunArgs(FunctionBox *funbox);
void markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent);
void setFunctionKinds(FunctionBox *funbox, uint32 *tcflags);
void trace(JSTracer *trc);
/*

View File

@ -38,11 +38,12 @@
*
* ***** END LICENSE BLOCK ***** */
#include "frontend/Parser.h"
#include "frontend/SemanticAnalysis.h"
#include "jsfun.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/Parser.h"
#include "jsfuninlines.h"
@ -64,7 +65,7 @@ using namespace js::frontend;
* - Recycled: funbox->node points to the node, but funbox->node->pn_funbox
* is NULL. When a function node is part of a tree that gets recycled, we
* must avoid corrupting any method list the node is on, so we leave the
* function node unrecycled until we call cleanFunctionList. At recycle
* function node unrecycled until we call CleanFunctionList. At recycle
* time, we clear such nodes' pn_funbox pointers to indicate that they
* are deleted and should be recycled once we get here.
*
@ -78,8 +79,8 @@ using namespace js::frontend;
* box's node pointer, disconnecting it entirely from the function box tree,
* and marking the function box to be trimmed out.
*/
void
Parser::cleanFunctionList(FunctionBox **funboxHead)
static void
CleanFunctionList(ParseNodeAllocator *allocator, FunctionBox **funboxHead)
{
FunctionBox **link = funboxHead;
while (FunctionBox *box = *link) {
@ -95,7 +96,7 @@ Parser::cleanFunctionList(FunctionBox **funboxHead)
* the node, and stay at the same link.
*/
*link = box->siblings;
allocator.freeNode(box->node);
allocator->freeNode(box->node);
} else {
/* The function is still live. */
@ -116,7 +117,7 @@ Parser::cleanFunctionList(FunctionBox **funboxHead)
}
/* Second, remove boxes for deleted functions from our kids list. */
cleanFunctionList(&box->kids);
CleanFunctionList(allocator, &box->kids);
/* Keep the box on the list, and move to the next link. */
link = &box->siblings;
@ -124,19 +125,6 @@ Parser::cleanFunctionList(FunctionBox **funboxHead)
}
}
bool
Parser::analyzeFunctions(TreeContext *tc)
{
cleanFunctionList(&tc->functionList);
if (!tc->functionList)
return true;
if (!markFunArgs(tc->functionList))
return false;
markExtensibleScopeDescendants(tc->functionList, false);
setFunctionKinds(tc->functionList, &tc->flags);
return true;
}
/*
* Mark as funargs any functions that reach up to one or more upvars across an
* already-known funarg. The parser will flag the o_m lambda as a funarg in:
@ -270,12 +258,12 @@ FindFunArgs(FunctionBox *funbox, int level, FunctionBoxQueue *queue)
return allskipmin;
}
bool
Parser::markFunArgs(FunctionBox *funbox)
static bool
MarkFunArgs(JSContext *cx, FunctionBox *funbox, uint32 functionCount)
{
FunctionBoxQueue queue;
if (!queue.init(functionCount)) {
js_ReportOutOfMemory(context);
js_ReportOutOfMemory(cx);
return false;
}
@ -563,15 +551,15 @@ ConsiderUnbranding(FunctionBox *funbox)
}
}
void
Parser::setFunctionKinds(FunctionBox *funbox, uint32 *tcflags)
static void
SetFunctionKinds(FunctionBox *funbox, uint32 *tcflags, bool isDirectEval)
{
for (; funbox; funbox = funbox->siblings) {
ParseNode *fn = funbox->node;
ParseNode *pn = fn->pn_body;
if (funbox->kids) {
setFunctionKinds(funbox->kids, tcflags);
SetFunctionKinds(funbox->kids, tcflags, isDirectEval);
ConsiderUnbranding(funbox);
}
@ -581,7 +569,7 @@ Parser::setFunctionKinds(FunctionBox *funbox, uint32 *tcflags)
if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
/* nothing to do */
} else if (callerFrame || funbox->inAnyDynamicScope()) {
} else if (isDirectEval || funbox->inAnyDynamicScope()) {
/*
* Either we are in a with-block or a function scope that is
* subject to direct eval; or we are compiling strict direct eval
@ -685,8 +673,8 @@ Parser::setFunctionKinds(FunctionBox *funbox, uint32 *tcflags)
* must have their OWN_SHAPE flags set; the comments for
* js::Bindings::extensibleParents explain why.
*/
void
Parser::markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent)
static void
MarkExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensibleParent)
{
for (; funbox; funbox = funbox->siblings) {
/*
@ -700,8 +688,22 @@ Parser::markExtensibleScopeDescendants(FunctionBox *funbox, bool hasExtensiblePa
funbox->bindings.setExtensibleParents();
if (funbox->kids) {
markExtensibleScopeDescendants(funbox->kids,
MarkExtensibleScopeDescendants(funbox->kids,
hasExtensibleParent || funbox->scopeIsExtensible());
}
}
}
bool
frontend::AnalyzeFunctions(TreeContext *tc)
{
CleanFunctionList(&tc->parser->allocator, &tc->functionList);
if (!tc->functionList)
return true;
if (!MarkFunArgs(tc->parser->context, tc->functionList, tc->parser->functionCount))
return false;
MarkExtensibleScopeDescendants(tc->functionList, false);
bool isDirectEval = !!tc->parser->callerFrame;
SetFunctionKinds(tc->functionList, &tc->flags, isDirectEval);
return true;
}

View File

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=78:
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is SpiderMonkey JavaScript engine.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef SemanticAnalysis_h__
#define SemanticAnalysis_h__
namespace js {
struct TreeContext;
namespace frontend {
/*
* For each function in the compilation unit given by tc, decide whether the
* function is a full closure, a null closure, or a flat closure, and set the
* heavyweight bit if necessary.
*/
bool
AnalyzeFunctions(TreeContext *tc);
} /* namespace frontend */
} /* namespace js */
#endif /* SemanticAnalysis_h__ */