зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
f706c43ad4
Коммит
9a2cb74eae
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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...
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
Загрузка…
Ссылка в новой задаче