Bug 845596 - Keep track of free variables during syntax parsing, r=jorendorff.

This commit is contained in:
Brian Hackett 2013-04-13 18:59:42 -06:00
parent 4dcc4406e6
commit 78a959193d
9 changed files with 359 additions and 290 deletions

View File

@ -48,7 +48,7 @@ class FullParseHandler
foldConstants(foldConstants)
{}
static Definition *null() { return NULL; }
static ParseNode *null() { return NULL; }
ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); }
void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); }
@ -62,6 +62,16 @@ class FullParseHandler
pn->setOp(JSOP_NAME);
return pn;
}
Definition *newPlaceholder(ParseNode *pn, ParseContext<FullParseHandler> *pc) {
Definition *dn = (Definition *) NameNode::create(PNK_NAME, pn->pn_atom, this, pc);
if (!dn)
return NULL;
dn->setOp(JSOP_NOP);
dn->setDefn(true);
dn->pn_dflags |= PND_PLACEHOLDER;
return dn;
}
ParseNode *newAtom(ParseNodeKind kind, JSAtom *atom, JSOp op = JSOP_NOP) {
ParseNode *pn = NullaryNode::create(kind, this);
if (!pn)
@ -168,6 +178,9 @@ class FullParseHandler
void setFunctionBox(ParseNode *pn, FunctionBox *funbox) {
pn->pn_funbox = funbox;
}
void addFunctionArgument(ParseNode *pn, ParseNode *argpn) {
pn->pn_body->append(argpn);
}
inline ParseNode *newLexicalScope(ObjectBox *blockbox);
bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) {
return pn->isKind(kind) && !pn->isInParens();
@ -192,6 +205,9 @@ class FullParseHandler
JS_ASSERT(pn->pn_pos.begin <= pn->pn_pos.end);
}
void setPosition(ParseNode *pn, const TokenPos &pos) {
pn->pn_pos = pos;
}
TokenPos getPosition(ParseNode *pn) {
return pn->pn_pos;
}
@ -254,6 +270,50 @@ class FullParseHandler
}
inline ParseNode *makeAssignment(ParseNode *pn, ParseNode *rhs);
static Definition *getDefinitionNode(Definition *dn) {
return dn;
}
static Definition::Kind getDefinitionKind(Definition *dn) {
return dn->kind();
}
void linkUseToDef(ParseNode *pn, Definition *dn)
{
JS_ASSERT(!pn->isUsed());
JS_ASSERT(!pn->isDefn());
JS_ASSERT(pn != dn->dn_uses);
JS_ASSERT(dn->isDefn());
pn->pn_link = dn->dn_uses;
dn->dn_uses = pn;
dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
pn->setUsed(true);
pn->pn_lexdef = dn;
}
Definition *resolve(Definition *dn) {
return dn->resolve();
}
void deoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
{
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
JS_ASSERT(pnu->isUsed());
JS_ASSERT(!pnu->isDefn());
if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end)
pnu->pn_dflags |= PND_DEOPTIMIZED;
}
}
bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) {
return pn->pn_blockid >= blockid;
}
static uintptr_t definitionToBits(Definition *dn) {
return uintptr_t(dn);
}
static Definition *definitionFromBits(uintptr_t bits) {
return (Definition *) bits;
}
static Definition *nullDefinition() {
return NULL;
}
};
inline bool

View File

@ -48,18 +48,20 @@ ParseMapPool::allocate()
return map;
}
inline Definition *
AtomDecls::lookupFirst(JSAtom *atom) const
template <typename ParseHandler>
inline typename ParseHandler::DefinitionNode
AtomDecls<ParseHandler>::lookupFirst(JSAtom *atom) const
{
JS_ASSERT(map);
AtomDefnListPtr p = map->lookup(atom);
if (!p)
return NULL;
return p.value().front();
return ParseHandler::nullDefinition();
return p.value().front<ParseHandler>();
}
template <typename ParseHandler>
inline DefinitionList::Range
AtomDecls::lookupMulti(JSAtom *atom) const
AtomDecls<ParseHandler>::lookupMulti(JSAtom *atom) const
{
JS_ASSERT(map);
if (AtomDefnListPtr p = map->lookup(atom))
@ -67,15 +69,16 @@ AtomDecls::lookupMulti(JSAtom *atom) const
return DefinitionList::Range();
}
template <typename ParseHandler>
inline bool
AtomDecls::addUnique(JSAtom *atom, Definition *defn)
AtomDecls<ParseHandler>::addUnique(JSAtom *atom, DefinitionNode defn)
{
JS_ASSERT(map);
AtomDefnListAddPtr p = map->lookupForAdd(atom);
if (!p)
return map->add(p, atom, DefinitionList(defn));
return map->add(p, atom, DefinitionList(ParseHandler::definitionToBits(defn)));
JS_ASSERT(!p.value().isMultiple());
p.value() = DefinitionList(defn);
p.value() = DefinitionList(ParseHandler::definitionToBits(defn));
return true;
}
@ -99,15 +102,17 @@ AtomThingMapPtr<Map>::releaseMap(JSContext *cx)
map_ = NULL;
}
template <typename ParseHandler>
inline bool
AtomDecls::init()
AtomDecls<ParseHandler>::init()
{
map = cx->parseMapPool().acquire<AtomDefnListMap>();
return map;
}
template <typename ParseHandler>
inline
AtomDecls::~AtomDecls()
AtomDecls<ParseHandler>::~AtomDecls()
{
if (map)
cx->parseMapPool().release(map);

View File

@ -5,10 +5,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ParseMaps-inl.h"
#include "jscntxt.h"
#include "jscompartment.h"
#include "FullParseHandler.h"
#include "SyntaxParseHandler.h"
#include "ParseMaps-inl.h"
#include "vm/String-inl.h"
using namespace js;
@ -58,7 +60,7 @@ ParseMapPool::allocateFresh()
}
DefinitionList::Node *
DefinitionList::allocNode(JSContext *cx, Definition *head, Node *tail)
DefinitionList::allocNode(JSContext *cx, uintptr_t head, Node *tail)
{
Node *result = cx->tempLifoAlloc().new_<Node>(head, tail);
if (!result)
@ -66,58 +68,17 @@ DefinitionList::allocNode(JSContext *cx, Definition *head, Node *tail)
return result;
}
bool
DefinitionList::pushFront(JSContext *cx, Definition *val)
{
Node *tail;
if (isMultiple()) {
tail = firstNode();
} else {
tail = allocNode(cx, defn(), NULL);
if (!tail)
return false;
}
Node *node = allocNode(cx, val, tail);
if (!node)
return false;
*this = DefinitionList(node);
return true;
}
bool
DefinitionList::pushBack(JSContext *cx, Definition *val)
{
Node *last;
if (isMultiple()) {
last = firstNode();
while (last->next)
last = last->next;
} else {
last = allocNode(cx, defn(), NULL);
if (!last)
return false;
}
Node *node = allocNode(cx, val, NULL);
if (!node)
return false;
last->next = node;
if (!isMultiple())
*this = DefinitionList(last);
return true;
}
#ifdef DEBUG
template <typename ParseHandler>
void
AtomDecls::dump()
AtomDecls<ParseHandler>::dump()
{
for (AtomDefnListRange r = map->all(); !r.empty(); r.popFront()) {
fprintf(stderr, "atom: ");
js_DumpAtom(r.front().key());
const DefinitionList &dlist = r.front().value();
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
fprintf(stderr, " defn: %p\n", (void *) dr.front());
fprintf(stderr, " defn: %p\n", (void *) dr.front<ParseHandler>());
}
}
}
@ -133,19 +94,20 @@ DumpAtomDefnMap(const AtomDefnMapPtr &map)
for (AtomDefnRange r = map->all(); !r.empty(); r.popFront()) {
fprintf(stderr, "atom: ");
js_DumpAtom(r.front().key());
fprintf(stderr, "defn: %p\n", (void *) r.front().value());
fprintf(stderr, "defn: %p\n", (void *) r.front().value().get<FullParseHandler>());
}
}
#endif
template <typename ParseHandler>
bool
AtomDecls::addShadow(JSAtom *atom, Definition *defn)
AtomDecls<ParseHandler>::addShadow(JSAtom *atom, typename ParseHandler::DefinitionNode defn)
{
AtomDefnListAddPtr p = map->lookupForAdd(atom);
if (!p)
return map->add(p, atom, DefinitionList(defn));
return map->add(p, atom, DefinitionList(ParseHandler::definitionToBits(defn)));
return p.value().pushFront(cx, defn);
return p.value().pushFront<ParseHandler>(cx, defn);
}
void
@ -171,3 +133,6 @@ frontend::InitAtomMap(JSContext *cx, frontend::AtomIndexMap *indices, HeapPtrAto
}
}
}
template class AtomDecls<FullParseHandler>;
template class AtomDecls<SyntaxParseHandler>;

View File

@ -18,11 +18,11 @@
namespace js {
namespace frontend {
struct Definition;
class DefinitionSingle;
class DefinitionList;
typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
typedef InlineMap<JSAtom *, Definition *, 24> AtomDefnMap;
typedef InlineMap<JSAtom *, DefinitionSingle, 24> AtomDefnMap;
typedef InlineMap<JSAtom *, DefinitionList, 24> AtomDefnListMap;
/*
@ -135,15 +135,6 @@ struct AtomThingMapPtr
Map &operator*() const { return *map_; }
};
struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
{
JS_ALWAYS_INLINE
Definition *lookupDefn(JSAtom *atom) {
AtomDefnMap::Ptr p = map_->lookup(atom);
return p ? p.value() : NULL;
}
};
typedef AtomThingMapPtr<AtomIndexMap> AtomIndexMapPtr;
/*
@ -165,9 +156,49 @@ class OwnedAtomThingMapPtr : public AtomThingMapPtrT
}
};
typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
/*
* DefinitionSingle and DefinitionList represent either a single definition
* or a list of them. The representation of definitions varies between
* parse handlers, being either a Definition* (FullParseHandler) or a
* Definition::Kind (SyntaxParseHandler). Methods on the below classes are
* templated to distinguish the kind of value wrapped by the class.
*/
/* Wrapper for a single definition. */
class DefinitionSingle
{
uintptr_t bits;
public:
template <typename ParseHandler>
static DefinitionSingle new_(typename ParseHandler::DefinitionNode defn)
{
DefinitionSingle res;
res.bits = ParseHandler::definitionToBits(defn);
return res;
}
template <typename ParseHandler>
typename ParseHandler::DefinitionNode get() {
return ParseHandler::definitionFromBits(bits);
}
};
struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
{
template <typename ParseHandler>
JS_ALWAYS_INLINE
typename ParseHandler::DefinitionNode lookupDefn(JSAtom *atom) {
AtomDefnMap::Ptr p = map_->lookup(atom);
return p ? p.value().get<ParseHandler>() : ParseHandler::nullDefinition();
}
};
typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
/*
* A nonempty list containing one or more pointers to Definitions.
*
@ -191,30 +222,24 @@ class DefinitionList
/* A node in a linked list of Definitions. */
struct Node
{
Definition *defn;
uintptr_t bits;
Node *next;
Node(Definition *defn, Node *next) : defn(defn), next(next) {}
Node(uintptr_t bits, Node *next) : bits(bits), next(next) {}
};
union {
Definition *defn;
Node *head;
uintptr_t bits;
Node *head;
} u;
Definition *defn() const {
JS_ASSERT(!isMultiple());
return u.defn;
}
Node *firstNode() const {
JS_ASSERT(isMultiple());
return (Node *) (u.bits & ~0x1);
}
static Node *
allocNode(JSContext *cx, Definition *head, Node *tail);
allocNode(JSContext *cx, uintptr_t bits, Node *tail);
public:
class Range
@ -222,40 +247,41 @@ class DefinitionList
friend class DefinitionList;
Node *node;
Definition *defn;
uintptr_t bits;
explicit Range(const DefinitionList &list) {
if (list.isMultiple()) {
node = list.firstNode();
defn = node->defn;
bits = node->bits;
} else {
node = NULL;
defn = list.defn();
bits = list.u.bits;
}
}
public:
/* An empty Range. */
Range() : node(NULL), defn(NULL) {}
Range() : node(NULL), bits(0) {}
void popFront() {
JS_ASSERT(!empty());
if (!node) {
defn = NULL;
bits = 0;
return;
}
node = node->next;
defn = node ? node->defn : NULL;
bits = node ? node->bits : 0;
}
Definition *front() {
template <typename ParseHandler>
typename ParseHandler::DefinitionNode front() {
JS_ASSERT(!empty());
return defn;
return ParseHandler::definitionFromBits(bits);
}
bool empty() const {
JS_ASSERT_IF(!defn, !node);
return !defn;
JS_ASSERT_IF(!bits, !node);
return !bits;
}
};
@ -263,8 +289,8 @@ class DefinitionList
u.bits = 0;
}
explicit DefinitionList(Definition *defn) {
u.defn = defn;
explicit DefinitionList(uintptr_t bits) {
u.bits = bits;
JS_ASSERT(!isMultiple());
}
@ -276,8 +302,9 @@ class DefinitionList
bool isMultiple() const { return (u.bits & 0x1) != 0; }
Definition *front() {
return isMultiple() ? firstNode()->defn : defn();
template <typename ParseHandler>
typename ParseHandler::DefinitionNode front() {
return ParseHandler::definitionFromBits(isMultiple() ? firstNode()->bits : u.bits);
}
/*
@ -294,7 +321,7 @@ class DefinitionList
if (next->next)
*this = DefinitionList(next);
else
*this = DefinitionList(next->defn);
*this = DefinitionList(next->bits);
return true;
}
@ -303,17 +330,31 @@ class DefinitionList
*
* Return true on success. On OOM, report on cx and return false.
*/
bool pushFront(JSContext *cx, Definition *val);
template <typename ParseHandler>
bool pushFront(JSContext *cx, typename ParseHandler::DefinitionNode defn) {
Node *tail;
if (isMultiple()) {
tail = firstNode();
} else {
tail = allocNode(cx, u.bits, NULL);
if (!tail)
return false;
}
/* Like pushFront, but add the given val to the end of the list. */
bool pushBack(JSContext *cx, Definition *val);
Node *node = allocNode(cx, ParseHandler::definitionToBits(defn), tail);
if (!node)
return false;
*this = DefinitionList(node);
return true;
}
/* Overwrite the first Definition in the list. */
void setFront(Definition *val) {
template <typename ParseHandler>
void setFront(typename ParseHandler::DefinitionNode defn) {
if (isMultiple())
firstNode()->defn = val;
firstNode()->bits = ParseHandler::definitionToBits(defn);
else
*this = DefinitionList(val);
*this = DefinitionList(ParseHandler::definitionToBits(defn));
}
Range all() const { return Range(*this); }
@ -341,8 +382,11 @@ class DefinitionList
* method addShadow. When we leave the block associated with the let, the method
* remove is used to unshadow the declaration immediately preceding it.
*/
template <typename ParseHandler>
class AtomDecls
{
typedef typename ParseHandler::DefinitionNode DefinitionNode;
/* AtomDeclsIter needs to get at the DefnListMap directly. */
friend class AtomDeclsIter;
@ -364,21 +408,21 @@ class AtomDecls
}
/* Return the definition at the head of the chain for |atom|. */
inline Definition *lookupFirst(JSAtom *atom) const;
inline DefinitionNode lookupFirst(JSAtom *atom) const;
/* Perform a lookup that can iterate over the definitions associated with |atom|. */
inline DefinitionList::Range lookupMulti(JSAtom *atom) const;
/* Add-or-update a known-unique definition for |atom|. */
inline bool addUnique(JSAtom *atom, Definition *defn);
bool addShadow(JSAtom *atom, Definition *defn);
inline bool addUnique(JSAtom *atom, DefinitionNode defn);
bool addShadow(JSAtom *atom, DefinitionNode defn);
/* Updating the definition for an entry that is known to exist is infallible. */
void updateFirst(JSAtom *atom, Definition *defn) {
void updateFirst(JSAtom *atom, DefinitionNode defn) {
JS_ASSERT(map);
AtomDefnListMap::Ptr p = map->lookup(atom);
JS_ASSERT(p);
p.value().setFront(defn);
p.value().setFront<ParseHandler>(defn);
}
/* Remove the node at the head of the chain for |atom|. */
@ -420,6 +464,9 @@ typedef AtomDefnListMap::Range AtomDefnListRange;
namespace mozilla {
template <>
struct IsPod<js::frontend::DefinitionSingle> : TrueType {};
template <>
struct IsPod<js::frontend::DefinitionList> : TrueType {};

View File

@ -461,7 +461,7 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
*/
if (opn->isDefn()) {
opn->setDefn(false);
LinkUseToDef(opn, (Definition *) pn);
handler.linkUseToDef(opn, (Definition *) pn);
}
}
break;
@ -552,7 +552,7 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn)
pn->pn_dflags &= ~PND_BOUND;
pn->setDefn(false);
LinkUseToDef(pn, (Definition *) opn);
handler.linkUseToDef(pn, (Definition *) opn);
}
}
return pn;

View File

@ -12,7 +12,6 @@
#include "jsscript.h"
#include "frontend/ParseMaps.h"
#include "frontend/TokenStream.h"
namespace js {
@ -1215,7 +1214,7 @@ struct Definition : public ParseNode
return pn_cookie.isFree();
}
enum Kind { VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
enum Kind { MISSING = 0, VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
bool canHaveInitializer() { return int(kind()) <= int(ARG); }
@ -1298,19 +1297,6 @@ ParseNode::isConstant()
}
}
inline void
LinkUseToDef(ParseNode *pn, Definition *dn)
{
JS_ASSERT(!pn->isUsed());
JS_ASSERT(!pn->isDefn());
JS_ASSERT(pn != dn->dn_uses);
pn->pn_link = dn->dn_uses;
dn->dn_uses = pn;
dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
pn->setUsed(true);
pn->pn_lexdef = dn;
}
class ObjectBox {
public:
JSObject *object;

View File

@ -125,7 +125,7 @@ ParseContext<FullParseHandler>::define(JSContext *cx, HandlePropertyName name,
JS_ASSERT(!decls_.lookupFirst(name));
if (!prevDef)
prevDef = lexdeps.lookupDefn(name);
prevDef = lexdeps.lookupDefn<FullParseHandler>(name);
if (prevDef) {
ParseNode **pnup = &prevDef->dn_uses;
@ -196,8 +196,7 @@ ParseContext<FullParseHandler>::define(JSContext *cx, HandlePropertyName name,
return false;
break;
case Definition::PLACEHOLDER:
case Definition::NAMED_LAMBDA:
default:
JS_NOT_REACHED("unexpected kind");
break;
}
@ -210,17 +209,20 @@ bool
ParseContext<SyntaxParseHandler>::define(JSContext *cx, HandlePropertyName name, Node pn,
Definition::Kind kind)
{
return true;
JS_ASSERT(!decls_.lookupFirst(name));
if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
lexdeps->remove(name);
return decls_.addUnique(name, kind);
}
template <typename ParseHandler>
void
ParseContext<ParseHandler>::prepareToAddDuplicateArg(Definition *prevDecl)
ParseContext<ParseHandler>::prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl)
{
JS_ASSERT(prevDecl->kind() == Definition::ARG);
JS_ASSERT(decls_.lookupFirst(prevDecl->name()) == prevDecl);
JS_ASSERT(!prevDecl->isClosed());
decls_.remove(prevDecl->name());
JS_ASSERT(decls_.lookupFirst(name) == prevDecl);
decls_.remove(name);
}
template <typename ParseHandler>
@ -258,7 +260,7 @@ template <typename ParseHandler>
void
ParseContext<ParseHandler>::popLetDecl(JSAtom *atom)
{
JS_ASSERT(decls_.lookupFirst(atom)->isLet());
JS_ASSERT(ParseHandler::getDefinitionKind(decls_.lookupFirst(atom)) == Definition::LET);
decls_.remove(atom);
}
@ -281,9 +283,7 @@ AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec
case Definition::ARG:
kind = ARGUMENT;
break;
case Definition::LET:
case Definition::NAMED_LAMBDA:
case Definition::PLACEHOLDER:
default:
JS_NOT_REACHED("unexpected dn->kind");
}
@ -821,11 +821,6 @@ Parser<ParseHandler>::checkStrictBinding(HandlePropertyName name, Node pn)
return true;
}
template <>
bool
Parser<FullParseHandler>::defineArg(ParseNode *funcpn, HandlePropertyName name,
bool disallowDuplicateArgs, Definition **duplicatedArg);
template <>
ParseNode *
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun, const AutoNameVector &formals,
@ -875,27 +870,21 @@ template <>
bool
Parser<FullParseHandler>::checkFunctionArguments()
{
/* Time to implement the odd semantics of 'arguments'. */
HandlePropertyName arguments = context->names().arguments;
/*
* Non-top-level functions use JSOP_DEFFUN which is a dynamic scope
* operation which means it aliases any bindings with the same name.
* Due to the implicit declaration mechanism (below), 'arguments' will not
* have decls and, even if it did, they will not be noted as closed in the
* emitter. Thus, in the corner case of function-statement-overridding-
* arguments, flag the whole scope as dynamic.
*/
if (FuncStmtSet *set = pc->funcStmts) {
for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
PropertyName *name = r.front()->asPropertyName();
if (name == arguments)
pc->sc->setBindingsAccessedDynamically();
else if (Definition *dn = pc->decls().lookupFirst(name))
if (Definition *dn = pc->decls().lookupFirst(name))
dn->pn_dflags |= PND_CLOSED;
}
}
/* Time to implement the odd semantics of 'arguments'. */
HandlePropertyName arguments = context->names().arguments;
/*
* As explained by the ContextFlags::funArgumentsHasLocalBinding comment,
* create a declaration for 'arguments' if there are any unbound uses in
@ -903,7 +892,7 @@ Parser<FullParseHandler>::checkFunctionArguments()
*/
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
if (r.front().key() == arguments) {
Definition *dn = r.front().value();
Definition *dn = r.front().value().get<FullParseHandler>();
pc->lexdeps->remove(arguments);
dn->pn_dflags |= PND_IMPLICITARGUMENTS;
if (!pc->define(context, arguments, dn, Definition::VAR))
@ -979,7 +968,7 @@ Parser<FullParseHandler>::checkFunctionArguments()
for (AtomDefnListMap::Range r = pc->decls().all(); !r.empty(); r.popFront()) {
DefinitionList &dlist = r.front().value();
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
Definition *dn = dr.front();
Definition *dn = dr.front<FullParseHandler>();
if (dn->kind() == Definition::ARG && dn->isAssigned())
funbox->setDefinitelyNeedsArgsObj();
}
@ -1045,23 +1034,6 @@ Parser<ParseHandler>::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ
return pn;
}
// Create a placeholder Definition node for |atom|.
// Nb: unlike most functions that are passed a Parser, this one gets a
// SharedContext passed in separately, because in this case |pc| may not equal
// |parser->pc|.
static Definition *
MakePlaceholder(ParseNode *pn, FullParseHandler *handler, ParseContext<FullParseHandler> *pc)
{
Definition *dn = (Definition *) NameNode::create(PNK_NAME, pn->pn_atom, handler, pc);
if (!dn)
return NULL;
dn->setOp(JSOP_NOP);
dn->setDefn(true);
dn->pn_dflags |= PND_PLACEHOLDER;
return dn;
}
static void
ForgetUse(ParseNode *pn)
{
@ -1253,23 +1225,6 @@ MatchOrInsertSemicolon(JSContext *cx, TokenStream *ts)
return true;
}
static bool
DeoptimizeUsesWithin(Definition *dn, const TokenPos &pos)
{
unsigned ndeoptimized = 0;
for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
JS_ASSERT(pnu->isUsed());
JS_ASSERT(!pnu->isDefn());
if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) {
pnu->pn_dflags |= PND_DEOPTIMIZED;
++ndeoptimized;
}
}
return ndeoptimized != 0;
}
/*
* Beware: this function is called for functions nested in other functions or
* global scripts but not for functions compiled through the Function
@ -1294,7 +1249,7 @@ Parser<FullParseHandler>::leaveFunction(ParseNode *fn, HandlePropertyName funNam
if (pc->lexdeps->count()) {
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
JSAtom *atom = r.front().key();
Definition *dn = r.front().value();
Definition *dn = r.front().value().get<FullParseHandler>();
JS_ASSERT(dn->isPlaceholder());
if (atom == funName && kind == Expression) {
@ -1337,12 +1292,12 @@ Parser<FullParseHandler>::leaveFunction(ParseNode *fn, HandlePropertyName funNam
* having an extensible scope) or any enclosing 'with'.
*/
if (funbox->hasExtensibleScope() || outerpc->parsingWith)
DeoptimizeUsesWithin(dn, fn->pn_pos);
handler.deoptimizeUsesWithin(dn, fn->pn_pos);
if (!outer_dn) {
AtomDefnAddPtr p = outerpc->lexdeps->lookupForAdd(atom);
if (p) {
outer_dn = p.value();
outer_dn = p.value().get<FullParseHandler>();
} else {
/*
* Create a new placeholder for our outer lexdep. We could
@ -1365,8 +1320,11 @@ Parser<FullParseHandler>::leaveFunction(ParseNode *fn, HandlePropertyName funNam
* inherited lexdeps into uses of a new outer definition
* allows us to handle both these cases in a natural way.
*/
outer_dn = MakePlaceholder(dn, &handler, outerpc);
if (!outer_dn || !outerpc->lexdeps->add(p, atom, outer_dn))
outer_dn = handler.newPlaceholder(dn, outerpc);
if (!outer_dn)
return false;
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(outer_dn);
if (!outerpc->lexdeps->add(p, atom, def))
return false;
}
}
@ -1438,26 +1396,28 @@ Parser<SyntaxParseHandler>::leaveFunction(Node fn, HandlePropertyName funName,
* argument with the same name. The caller may use this to report an error when
* one of the abovementioned features occurs after a duplicate.
*/
template <>
template <typename ParseHandler>
bool
Parser<FullParseHandler>::defineArg(ParseNode *funcpn, HandlePropertyName name,
bool disallowDuplicateArgs, Definition **duplicatedArg)
Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
bool disallowDuplicateArgs, Node *duplicatedArg)
{
SharedContext *sc = pc->sc;
/* Handle duplicate argument names. */
if (Definition *prevDecl = pc->decls().lookupFirst(name)) {
if (DefinitionNode prevDecl = pc->decls().lookupFirst(name)) {
Node pn = handler.getDefinitionNode(prevDecl);
/*
* Strict-mode disallows duplicate args. We may not know whether we are
* in strict mode or not (since the function body hasn't been parsed).
* In such cases, reportStrictModeError will queue up the potential
* error and return 'true'.
* In such cases, report will queue up the potential error and return
* 'true'.
*/
if (sc->needStrictChecks()) {
JSAutoByteString bytes;
if (!js_AtomToPrintableString(context, name, &bytes))
return false;
if (!report(ParseStrictError, pc->sc->strict, prevDecl,
if (!report(ParseStrictError, pc->sc->strict, pn,
JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
{
return false;
@ -1465,36 +1425,29 @@ Parser<FullParseHandler>::defineArg(ParseNode *funcpn, HandlePropertyName name,
}
if (disallowDuplicateArgs) {
report(ParseError, false, prevDecl, JSMSG_BAD_DUP_ARGS);
report(ParseError, false, pn, JSMSG_BAD_DUP_ARGS);
return false;
}
if (duplicatedArg)
*duplicatedArg = prevDecl;
*duplicatedArg = pn;
/* ParseContext::define assumes and asserts prevDecl is not in decls. */
pc->prepareToAddDuplicateArg(prevDecl);
JS_ASSERT(handler.getDefinitionKind(prevDecl) == Definition::ARG);
pc->prepareToAddDuplicateArg(name, prevDecl);
}
ParseNode *argpn = handler.newName(name, pc);
Node argpn = handler.newName(name, pc);
if (!argpn)
return false;
if (!checkStrictBinding(name, argpn))
return false;
funcpn->pn_body->append(argpn);
handler.addFunctionArgument(funcpn, argpn);
return pc->define(context, name, argpn, Definition::ARG);
}
template <>
bool
Parser<SyntaxParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
bool disallowDuplicateArgs, DefinitionNode *duplicatedArg)
{
return true;
}
#if JS_HAS_DESTRUCTURING
template <typename ParseHandler>
/* static */ bool
@ -1547,7 +1500,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
if (parenFreeArrow || !tokenStream.matchToken(TOK_RP)) {
bool hasDefaults = false;
DefinitionNode duplicatedArg = null();
Node duplicatedArg = null();
bool destructuringArg = false;
#if JS_HAS_DESTRUCTURING
Node list = null();
@ -1737,7 +1690,7 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
* pre-created definition node for this function that primaryExpr
* put in pc->lexdeps on first forward reference, and recycle pn.
*/
if (Definition *fn = pc->lexdeps.lookupDefn(funName)) {
if (Definition *fn = pc->lexdeps.lookupDefn<FullParseHandler>(funName)) {
JS_ASSERT(fn->isDefn());
fn->setKind(PNK_FUNCTION);
fn->setArity(PN_CODE);
@ -1790,6 +1743,15 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
}
if (!pc->funcStmts->put(funName))
return false;
/*
* Due to the implicit declaration mechanism, 'arguments' will not
* have decls and, even if it did, they will not be noted as closed
* in the emitter. Thus, in the corner case of function statements
* overridding arguments, flag the whole scope as dynamic.
*/
if (funName == context->names().arguments)
pc->sc->setBindingsAccessedDynamically();
}
/* No further binding (in BindNameToSlot) is needed for functions. */
@ -1807,6 +1769,36 @@ bool
Parser<SyntaxParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
Node *pn, FunctionSyntaxKind kind)
{
/* Function statements add a binding to the enclosing scope. */
bool bodyLevel = pc->atBodyLevel();
if (kind == Statement) {
/*
* Handle redeclaration and optimize cases where we can statically bind the
* function (thereby avoiding JSOP_DEFFUN and dynamic name lookup).
*/
if (DefinitionNode dn = pc->decls().lookupFirst(funName)) {
if (dn == Definition::CONST) {
JSAutoByteString name;
if (!js_AtomToPrintableString(context, funName, &name) ||
!report(ParseError, false, null(), JSMSG_REDECLARED_VAR,
Definition::kindString(dn), name.ptr()))
{
return false;
}
}
} else if (bodyLevel) {
if (pc->lexdeps.lookupDefn<SyntaxParseHandler>(funName))
pc->lexdeps->remove(funName);
if (!pc->define(context, funName, *pn, Definition::VAR))
return false;
}
if (!bodyLevel && funName == context->names().arguments)
pc->sc->setBindingsAccessedDynamically();
}
return true;
}
@ -2474,17 +2466,17 @@ OuterLet(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, HandleAtom atom)
return false;
}
template <>
template <typename ParseHandler>
/* static */ bool
Parser<FullParseHandler>::bindVarOrConst(JSContext *cx, BindData<FullParseHandler> *data,
HandlePropertyName name, Parser<FullParseHandler> *parser)
Parser<ParseHandler>::bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data,
HandlePropertyName name, Parser<ParseHandler> *parser)
{
ParseContext<FullParseHandler> *pc = parser->pc;
ParseNode *pn = data->pn;
ParseContext<ParseHandler> *pc = parser->pc;
Node pn = data->pn;
bool isConstDecl = data->op == JSOP_DEFCONST;
/* Default best op for pn is JSOP_NAME; we'll try to improve below. */
pn->setOp(JSOP_NAME);
parser->handler.setOp(pn, JSOP_NAME);
if (!parser->checkStrictBinding(name, pn))
return false;
@ -2492,7 +2484,7 @@ Parser<FullParseHandler>::bindVarOrConst(JSContext *cx, BindData<FullParseHandle
StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL);
if (stmt && stmt->type == STMT_WITH) {
pn->pn_dflags |= PND_DEOPTIMIZED;
parser->handler.setFlag(pn, PND_DEOPTIMIZED);
if (pc->sc->isFunctionBox()) {
FunctionBox *funbox = pc->sc->asFunctionBox();
funbox->setMightAliasLocals();
@ -2523,8 +2515,8 @@ Parser<FullParseHandler>::bindVarOrConst(JSContext *cx, BindData<FullParseHandle
* is not allowed which allows us to turn any non-error redeclaration
* into a use of the initial declaration.
*/
Definition *dn = defs.front();
Definition::Kind dn_kind = dn->kind();
DefinitionNode dn = defs.front<ParseHandler>();
Definition::Kind dn_kind = parser->handler.getDefinitionKind(dn);
if (dn_kind == Definition::ARG) {
JSAutoByteString bytes;
if (!js_AtomToPrintableString(cx, name, &bytes))
@ -2557,16 +2549,7 @@ Parser<FullParseHandler>::bindVarOrConst(JSContext *cx, BindData<FullParseHandle
}
}
LinkUseToDef(pn, dn);
return true;
}
template <>
/* static */ bool
Parser<SyntaxParseHandler>::bindVarOrConst(JSContext *cx, BindData<SyntaxParseHandler> *data,
HandlePropertyName name,
Parser<SyntaxParseHandler> *parser)
{
parser->handler.linkUseToDef(pn, dn);
return true;
}
@ -2589,21 +2572,20 @@ Parser<FullParseHandler>::makeSetCall(ParseNode *pn, unsigned msg)
return true;
}
template <>
template <typename ParseHandler>
bool
Parser<FullParseHandler>::noteNameUse(ParseNode *pn)
Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
{
RootedPropertyName name(context, pn->pn_atom->asPropertyName());
StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL);
DefinitionList::Range defs = pc->decls().lookupMulti(name);
Definition *dn;
DefinitionNode dn;
if (!defs.empty()) {
dn = defs.front();
dn = defs.front<ParseHandler>();
} else {
if (AtomDefnAddPtr p = pc->lexdeps->lookupForAdd(name)) {
dn = p.value();
dn = p.value().get<ParseHandler>();
} else {
/*
* No definition before this use in any lexical scope.
@ -2613,28 +2595,23 @@ Parser<FullParseHandler>::noteNameUse(ParseNode *pn)
* - Be left as a free variable definition if we never
* see the real definition.
*/
dn = MakePlaceholder(pn, &handler, pc);
if (!dn || !pc->lexdeps->add(p, name, dn))
dn = handler.newPlaceholder(pn, pc);
if (!dn)
return false;
DefinitionSingle def = DefinitionSingle::new_<ParseHandler>(dn);
if (!pc->lexdeps->add(p, name, def))
return false;
}
}
JS_ASSERT(dn->isDefn());
LinkUseToDef(pn, dn);
handler.linkUseToDef(pn, dn);
if (stmt && stmt->type == STMT_WITH)
pn->pn_dflags |= PND_DEOPTIMIZED;
handler.setFlag(pn, PND_DEOPTIMIZED);
return true;
}
template <>
bool
Parser<SyntaxParseHandler>::noteNameUse(Node pn)
{
return true;
}
#if JS_HAS_DESTRUCTURING
template <>
@ -2816,7 +2793,8 @@ Parser<FullParseHandler>::checkDestructuring(BindData<FullParseHandler> *data,
* officially linked to its def or registered in lexdeps. Do
* that now.
*/
if (pair->pn_right == pair->pn_left && !noteNameUse(pn))
RootedPropertyName name(context, pn->pn_atom->asPropertyName());
if (pair->pn_right == pair->pn_left && !noteNameUse(name, pn))
return false;
ok = bindDestructuringLHS(pn);
}
@ -3143,9 +3121,9 @@ PushBlocklikeStatement(StmtInfoPC *stmt, StmtType type, ParseContext<ParseHandle
return GenerateBlockId(pc, stmt->blockid);
}
template <>
ParseNode *
Parser<FullParseHandler>::newBindingNode(PropertyName *name, VarContext varContext)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, VarContext varContext)
{
/*
* If this name is being injected into an existing block/function, see if
@ -3156,13 +3134,15 @@ Parser<FullParseHandler>::newBindingNode(PropertyName *name, VarContext varConte
*/
if (varContext == HoistVars) {
if (AtomDefnPtr p = pc->lexdeps->lookup(name)) {
ParseNode *lexdep = p.value();
JS_ASSERT(lexdep->isPlaceholder());
if (lexdep->pn_blockid >= pc->blockid()) {
lexdep->pn_blockid = pc->blockid();
DefinitionNode lexdep = p.value().get<ParseHandler>();
JS_ASSERT(handler.getDefinitionKind(lexdep) == Definition::PLACEHOLDER);
Node pn = handler.getDefinitionNode(lexdep);
if (handler.dependencyCovered(pn, pc->blockid(), functionScope)) {
handler.setBlockId(pn, pc->blockid());
pc->lexdeps->remove(p);
lexdep->pn_pos = tokenStream.currentToken().pos;
return lexdep;
handler.setPosition(pn, tokenStream.currentToken().pos);
return pn;
}
}
}
@ -3172,13 +3152,6 @@ Parser<FullParseHandler>::newBindingNode(PropertyName *name, VarContext varConte
return handler.newName(name, pc);
}
template <>
SyntaxParseHandler::Node
Parser<SyntaxParseHandler>::newBindingNode(PropertyName *name, VarContext varContext)
{
return SyntaxParseHandler::NodeGeneric;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::switchStatement()
@ -3904,7 +3877,7 @@ Parser<ParseHandler>::tryStatement()
case TOK_NAME:
{
RootedPropertyName label(context, tokenStream.currentToken().name());
catchName = newBindingNode(label);
catchName = newBindingNode(label, false);
if (!catchName)
return null();
data.pn = catchName;
@ -4020,9 +3993,10 @@ Parser<ParseHandler>::withStatement()
* to safely optimize binding globals (see bug 561923).
*/
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
Definition *defn = r.front().value();
Definition *lexdep = defn->resolve();
DeoptimizeUsesWithin(lexdep, TokenPos::make(begin, tokenStream.currentToken().pos.begin));
DefinitionNode defn = r.front().value().get<ParseHandler>();
DefinitionNode lexdep = handler.resolve(defn);
handler.deoptimizeUsesWithin(lexdep,
TokenPos::make(begin, tokenStream.currentToken().pos.begin));
}
Node pn = handler.newBinary(PNK_WITH, objectExpr, innerBlock);
@ -4594,7 +4568,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
}
RootedPropertyName name(context, tokenStream.currentToken().name());
pn2 = newBindingNode(name, varContext);
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
if (!pn2)
return null();
if (data.op == JSOP_DEFCONST)
@ -5445,7 +5419,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
* generator) a use of a new placeholder in the generator's
* lexdeps.
*/
Definition *dn2 = MakePlaceholder(pn, &parser->handler, parser->pc);
Definition *dn2 = parser->handler.newPlaceholder(pn, parser->pc);
if (!dn2)
return false;
dn2->pn_pos = root->pn_pos;
@ -5464,7 +5438,8 @@ CompExprTransplanter::transplant(ParseNode *pn)
dn2->dn_uses = dn->dn_uses;
dn->dn_uses = *pnup;
*pnup = NULL;
if (!pc->lexdeps->put(atom, dn2))
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn2);
if (!pc->lexdeps->put(atom, def))
return false;
if (dn->isClosed())
dn2->pn_dflags |= PND_CLOSED;
@ -5475,7 +5450,8 @@ CompExprTransplanter::transplant(ParseNode *pn)
* from the parent's lexdeps into the generator's lexdeps.
*/
outerpc->lexdeps->remove(atom);
if (!pc->lexdeps->put(atom, dn))
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn);
if (!pc->lexdeps->put(atom, def))
return false;
} else if (dn->isImplicitArguments()) {
/*
@ -5629,7 +5605,7 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
* and it tries to bind all names to slots, so we must let it do
* the deed.
*/
pn3 = newBindingNode(name);
pn3 = newBindingNode(name, false);
if (!pn3)
return null();
break;
@ -6145,12 +6121,12 @@ Parser<ParseHandler>::identifierName()
{
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
PropertyName *name = tokenStream.currentToken().name();
RootedPropertyName name(context, tokenStream.currentToken().name());
Node pn = handler.newName(name, pc);
if (!pn)
return null();
if (!pc->inDeclDestructuring && !noteNameUse(pn))
if (!pc->inDeclDestructuring && !noteNameUse(name, pn))
return null();
return pn;

View File

@ -85,6 +85,7 @@ struct ParseContext : public GenericParseContext
{
typedef StmtInfoPC StmtInfo;
typedef typename ParseHandler::Node Node;
typedef typename ParseHandler::DefinitionNode DefinitionNode;
uint32_t bodyid; /* block number of program/function body */
uint32_t blockidGen; /* preincremented block number generator */
@ -103,12 +104,12 @@ struct ParseContext : public GenericParseContext
Node blockNode; /* parse node for a block with let declarations
(block with its own lexical scope) */
private:
AtomDecls decls_; /* function, const, and var declarations */
AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
DeclVector args_; /* argument definitions */
DeclVector vars_; /* var/const definitions */
public:
const AtomDecls &decls() const {
const AtomDecls<ParseHandler> &decls() const {
return decls_;
}
@ -161,7 +162,7 @@ struct ParseContext : public GenericParseContext
void popLetDecl(JSAtom *atom);
/* See the sad story in defineArg. */
void prepareToAddDuplicateArg(Definition *prevDecl);
void prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl);
/* See the sad story in MakeDefIntoUse. */
void updateDecl(JSAtom *atom, Node newDecl);
@ -494,13 +495,13 @@ struct Parser : private AutoGCRooter, public StrictModeGetter
bool checkStrictBinding(HandlePropertyName name, Node pn);
bool checkDeleteExpression(Node *pn);
bool defineArg(Node funcpn, HandlePropertyName name,
bool disallowDuplicateArgs = false, DefinitionNode *duplicatedArg = NULL);
bool disallowDuplicateArgs = false, Node *duplicatedArg = NULL);
Node pushLexicalScope(StmtInfoPC *stmt);
Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
bool noteNameUse(Node pn);
bool noteNameUse(HandlePropertyName name, Node pn);
Node newRegExp(const jschar *chars, size_t length, RegExpFlag flags);
Node newBindingNode(PropertyName *name, VarContext varContext = HoistVars);
Node newBindingNode(PropertyName *name, bool functionScope, VarContext varContext = HoistVars);
bool checkDestructuring(BindData<ParseHandler> *data, Node left, bool toplevel = true);
bool bindDestructuringVar(BindData<ParseHandler> *data, Node pn);
bool bindDestructuringLHS(Node pn);
@ -521,7 +522,7 @@ struct Parser : private AutoGCRooter, public StrictModeGetter
bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data,
HandlePropertyName name, Parser<ParseHandler> *parser);
static DefinitionNode null() { return ParseHandler::null(); }
static Node null() { return ParseHandler::null(); }
bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom);
bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);

View File

@ -27,7 +27,7 @@ class SyntaxParseHandler
NodeStringExprStatement,
NodeLValue
};
typedef Node DefinitionNode;
typedef Definition::Kind DefinitionNode;
SyntaxParseHandler(JSContext *cx, TokenStream &tokenStream, bool foldConstants)
: lastAtom(NULL),
@ -43,6 +43,9 @@ class SyntaxParseHandler
lastAtom = name;
return NodeName;
}
DefinitionNode newPlaceholder(Node pn, ParseContext<SyntaxParseHandler> *pc) {
return Definition::PLACEHOLDER;
}
Node newAtom(ParseNodeKind kind, JSAtom *atom, JSOp op = JSOP_NOP) {
if (kind == PNK_STRING) {
lastAtom = atom;
@ -102,6 +105,7 @@ class SyntaxParseHandler
Node newFunctionDefinition() { return NodeGeneric; }
void setFunctionBody(Node pn, Node kid) {}
void setFunctionBox(Node pn, FunctionBox *funbox) {}
void addFunctionArgument(Node pn, Node argpn) {}
Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; }
bool isOperationWithoutParens(Node pn, ParseNodeKind kind) {
// It is OK to return false here, callers should only use this method
@ -119,6 +123,8 @@ class SyntaxParseHandler
void setEndPosition(Node pn, Node oth) {}
void setEndPosition(Node pn, uint32_t end) {}
void setPosition(Node pn, const TokenPos &pos) {}
TokenPos getPosition(Node pn) {
return tokenStream.currentToken().pos;
}
@ -154,6 +160,29 @@ class SyntaxParseHandler
bool isEmptySemicolon(Node pn) { return false; }
Node makeAssignment(Node pn, Node rhs) { return NodeGeneric; }
static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; }
static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; }
void linkUseToDef(Node pn, DefinitionNode dn) {}
DefinitionNode resolve(DefinitionNode dn) { return dn; }
void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {}
bool dependencyCovered(Node pn, unsigned blockid, bool functionScope) {
// Only resolve lexical dependencies in cases where a definition covers
// the entire function. Not enough information is kept to compare the
// dependency location with blockid.
return functionScope;
}
static uintptr_t definitionToBits(DefinitionNode dn) {
// Use a shift, as DefinitionList tags the lower bit of its associated union.
return uintptr_t(dn << 1);
}
static DefinitionNode definitionFromBits(uintptr_t bits) {
return (DefinitionNode) (bits >> 1);
}
static DefinitionNode nullDefinition() {
return Definition::MISSING;
}
};
} // namespace frontend