Bug 770850 - Reimplement DefnOrHeader as DefinitionList. r=njn.

This commit is contained in:
Jason Orendorff 2012-07-06 16:33:58 -05:00
parent ec7dba8378
commit 5a4279d4f3
6 changed files with 278 additions and 285 deletions

View File

@ -89,13 +89,13 @@ class InlineMap
{
friend class InlineMap;
const K &key_;
const V &value_;
V &value_;
Entry(const K &key, const V &value) : key_(key), value_(value) {}
Entry(const K &key, V &value) : key_(key), value_(value) {}
public:
const K &key() { return key_; }
const V &value() { return value_; }
V &value() { return value_; }
}; /* class Entry */
class Ptr

View File

@ -31,10 +31,10 @@ ParseMapPool::acquire<AtomIndexMap>()
}
template <>
inline AtomDOHMap *
ParseMapPool::acquire<AtomDOHMap>()
inline AtomDefnListMap *
ParseMapPool::acquire<AtomDefnListMap>()
{
return reinterpret_cast<AtomDOHMap *>(allocate());
return reinterpret_cast<AtomDefnListMap *>(allocate());
}
inline void *
@ -52,41 +52,31 @@ inline Definition *
AtomDecls::lookupFirst(JSAtom *atom)
{
JS_ASSERT(map);
AtomDOHPtr p = map->lookup(atom);
AtomDefnListPtr p = map->lookup(atom);
if (!p)
return NULL;
if (p.value().isHeader()) {
/* Just return the head defn. */
return p.value().header()->defn;
}
return p.value().defn();
return p.value().front();
}
inline MultiDeclRange
inline DefinitionList::Range
AtomDecls::lookupMulti(JSAtom *atom)
{
JS_ASSERT(map);
AtomDOHPtr p = map->lookup(atom);
if (!p)
return MultiDeclRange((Definition *) NULL);
DefnOrHeader &doh = p.value();
if (doh.isHeader())
return MultiDeclRange(doh.header());
return MultiDeclRange(doh.defn());
if (AtomDefnListPtr p = map->lookup(atom))
return p.value().all();
return DefinitionList::Range();
}
inline bool
AtomDecls::addUnique(JSAtom *atom, Definition *defn)
{
JS_ASSERT(map);
AtomDOHAddPtr p = map->lookupForAdd(atom);
if (p) {
JS_ASSERT(!p.value().isHeader());
p.value() = DefnOrHeader(defn);
return true;
}
return map->add(p, atom, DefnOrHeader(defn));
AtomDefnListAddPtr p = map->lookupForAdd(atom);
if (!p)
return map->add(p, atom, DefinitionList(defn));
JS_ASSERT(!p.value().isMultiple());
p.value() = DefinitionList(defn);
return true;
}
template <class Map>
@ -112,7 +102,7 @@ AtomThingMapPtr<Map>::releaseMap(JSContext *cx)
inline bool
AtomDecls::init()
{
map = cx->parseMapPool().acquire<AtomDOHMap>();
map = cx->parseMapPool().acquire<AtomDefnListMap>();
return map;
}

View File

@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ParseMaps-inl.h"
#include "jscntxt.h"
#include "jscompartment.h"
using namespace js;
@ -18,13 +19,13 @@ ParseMapPool::checkInvariants()
* allocated space for each of the map types.
*/
JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(jsatomid));
JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(DefnOrHeader));
JS_STATIC_ASSERT(sizeof(Definition *) == sizeof(DefinitionList));
JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomIndexMap::Entry));
JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomDOHMap::Entry));
JS_STATIC_ASSERT(sizeof(AtomMapT::Entry) == sizeof(AtomDOHMap::Entry));
JS_STATIC_ASSERT(sizeof(AtomDefnMap::Entry) == sizeof(AtomDefnListMap::Entry));
JS_STATIC_ASSERT(sizeof(AtomMapT::Entry) == sizeof(AtomDefnListMap::Entry));
/* Ensure that the HasTable::clear goes quickly via memset. */
JS_STATIC_ASSERT(tl::IsPodType<AtomIndexMap::WordMap::Entry>::result);
JS_STATIC_ASSERT(tl::IsPodType<AtomDOHMap::WordMap::Entry>::result);
JS_STATIC_ASSERT(tl::IsPodType<AtomDefnListMap::WordMap::Entry>::result);
JS_STATIC_ASSERT(tl::IsPodType<AtomDefnMap::WordMap::Entry>::result);
}
@ -53,23 +54,67 @@ ParseMapPool::allocateFresh()
return (void *) map;
}
DefinitionList::Node *
DefinitionList::allocNode(JSContext *cx, Definition *head, Node *tail)
{
Node *result = cx->tempLifoAlloc().new_<Node>(head, tail);
if (!result)
js_ReportOutOfMemory(cx);
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
void
AtomDecls::dump()
{
for (AtomDOHRange r = map->all(); !r.empty(); r.popFront()) {
for (AtomDefnListRange r = map->all(); !r.empty(); r.popFront()) {
fprintf(stderr, "atom: ");
js_DumpAtom(r.front().key());
const DefnOrHeader &doh = r.front().value();
if (doh.isHeader()) {
AtomDeclNode *node = doh.header();
do {
fprintf(stderr, " node: %p\n", (void *) node);
fprintf(stderr, " defn: %p\n", (void *) node->defn);
node = node->next;
} while (node);
} else {
fprintf(stderr, " defn: %p\n", (void *) doh.defn());
const DefinitionList &dlist = r.front().value();
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
fprintf(stderr, " defn: %p\n", (void *) dr.front());
}
}
}
@ -90,74 +135,21 @@ DumpAtomDefnMap(const AtomDefnMapPtr &map)
}
#endif
AtomDeclNode *
AtomDecls::allocNode(Definition *defn)
{
AtomDeclNode *p = cx->tempLifoAlloc().new_<AtomDeclNode>(defn);
if (!p) {
js_ReportOutOfMemory(cx);
return NULL;
}
return p;
}
bool
AtomDecls::addShadow(JSAtom *atom, Definition *defn)
{
AtomDeclNode *node = allocNode(defn);
if (!node)
return false;
AtomDOHAddPtr p = map->lookupForAdd(atom);
AtomDefnListAddPtr p = map->lookupForAdd(atom);
if (!p)
return map->add(p, atom, DefnOrHeader(node));
return map->add(p, atom, DefinitionList(defn));
AtomDeclNode *toShadow;
if (p.value().isHeader()) {
toShadow = p.value().header();
} else {
toShadow = allocNode(p.value().defn());
if (!toShadow)
return false;
}
node->next = toShadow;
p.value() = DefnOrHeader(node);
return true;
}
AtomDeclNode *
AtomDecls::lastAsNode(DefnOrHeader *doh)
{
if (doh->isHeader()) {
AtomDeclNode *last = doh->header();
while (last->next)
last = last->next;
return last;
}
/* Otherwise, we need to turn the existing defn into a node. */
AtomDeclNode *node = allocNode(doh->defn());
if (!node)
return NULL;
*doh = DefnOrHeader(node);
return node;
return p.value().pushFront(cx, defn);
}
bool
AtomDecls::addHoist(JSAtom *atom, Definition *defn)
{
AtomDeclNode *node = allocNode(defn);
if (!node)
return false;
AtomDOHAddPtr p = map->lookupForAdd(atom);
if (p) {
AtomDeclNode *last = lastAsNode(&p.value());
if (!last)
return false;
last->next = node;
return true;
}
return map->add(p, atom, DefnOrHeader(node));
AtomDefnListAddPtr p = map->lookupForAdd(atom);
if (p)
return p.value().pushBack(cx, defn);
return map->add(p, atom, DefinitionList(defn));
}

View File

@ -18,6 +18,8 @@ namespace js {
struct Definition;
typedef InlineMap<JSAtom *, DefinitionList, 24> AtomDefnListMap;
/*
* A pool that permits the reuse of the backing storage for the defn, index, or
* defn-or-header (multi) maps.
@ -91,7 +93,7 @@ class ParseMapPool
recycle((void *) map);
}
void release(AtomDOHMap *map) {
void release(AtomDefnListMap *map) {
recycle((void *) map);
}
}; /* ParseMapPool */
@ -153,59 +155,156 @@ class OwnedAtomThingMapPtr : public AtomThingMapPtrT
typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
/* Node structure for chaining in AtomDecls. */
struct AtomDeclNode
{
Definition *defn;
AtomDeclNode *next;
explicit AtomDeclNode(Definition *defn)
: defn(defn), next(NULL)
{}
};
/*
* Tagged union of a Definition and an AtomDeclNode, for use in AtomDecl's
* internal map.
* A nonempty list containing one or more pointers to Definitions.
*
* By far the most common case is that the list contains exactly one
* Definition, so the implementation is optimized for that case.
*
* Nodes for the linked list (if any) are allocated from the tempPool of a
* context the caller passes into pushFront and pushBack. This means the
* DefinitionList does not own the memory for the nodes: the JSContext does.
* As a result, DefinitionList is a POD type; it can be safely and cheaply
* copied.
*/
class DefnOrHeader
class DefinitionList
{
public:
class Range;
private:
friend class Range;
/* A node in a linked list of Definitions. */
struct Node
{
Definition *defn;
Node *next;
Node(Definition *defn, Node *next) : defn(defn), next(next) {}
};
union {
Definition *defn;
AtomDeclNode *head;
uintptr_t bits;
Definition *defn;
Node *head;
uintptr_t bits;
} u;
public:
DefnOrHeader() {
u.bits = 0;
}
explicit DefnOrHeader(Definition *defn) {
u.defn = defn;
JS_ASSERT(!isHeader());
}
explicit DefnOrHeader(AtomDeclNode *node) {
u.head = node;
u.bits |= 0x1;
JS_ASSERT(isHeader());
}
bool isHeader() const {
return u.bits & 0x1;
}
Definition *defn() const {
JS_ASSERT(!isHeader());
JS_ASSERT(!isMultiple());
return u.defn;
}
AtomDeclNode *header() const {
JS_ASSERT(isHeader());
return (AtomDeclNode *) (u.bits & ~0x1);
Node *firstNode() const {
JS_ASSERT(isMultiple());
return (Node *) (u.bits & ~0x1);
}
static Node *
allocNode(JSContext *cx, Definition *head, Node *tail);
public:
class Range
{
friend class DefinitionList;
Node *node;
Definition *defn;
explicit Range(const DefinitionList &list) {
if (list.isMultiple()) {
node = list.firstNode();
defn = node->defn;
} else {
node = NULL;
defn = list.defn();
}
}
public:
/* An empty Range. */
Range() : node(NULL), defn(NULL) {}
void popFront() {
JS_ASSERT(!empty());
if (!node) {
defn = NULL;
return;
}
node = node->next;
defn = node ? node->defn : NULL;
}
Definition *front() {
JS_ASSERT(!empty());
return defn;
}
bool empty() const {
JS_ASSERT_IF(!defn, !node);
return !defn;
}
};
DefinitionList() {
u.bits = 0;
}
explicit DefinitionList(Definition *defn) {
u.defn = defn;
JS_ASSERT(!isMultiple());
}
explicit DefinitionList(Node *node) {
u.head = node;
u.bits |= 0x1;
JS_ASSERT(isMultiple());
}
bool isMultiple() const { return (u.bits & 0x1) != 0; }
Definition *front() {
return isMultiple() ? firstNode()->defn : defn();
}
/*
* If there are multiple Definitions in this list, remove the first and
* return true. Otherwise there is exactly one Definition in the list; do
* nothing and return false.
*/
bool popFront() {
if (!isMultiple())
return false;
Node *node = firstNode();
Node *next = node->next;
if (next->next)
*this = DefinitionList(next);
else
*this = DefinitionList(next->defn);
return true;
}
/*
* Add a definition to the front of this list.
*
* Return true on success. On OOM, report on cx and return false.
*/
bool pushFront(JSContext *cx, Definition *val);
/* Like pushFront, but add the given val to the end of the list. */
bool pushBack(JSContext *cx, Definition *val);
/* Overwrite the first Definition in the list. */
void setFront(Definition *val) {
if (isMultiple())
firstNode()->defn = val;
else
*this = DefinitionList(val);
}
Range all() const { return Range(*this); }
#ifdef DEBUG
void dump();
#endif
@ -213,7 +312,7 @@ class DefnOrHeader
namespace tl {
template <> struct IsPodType<DefnOrHeader> {
template <> struct IsPodType<DefinitionList> {
static const bool result = true;
};
@ -222,7 +321,7 @@ template <> struct IsPodType<DefnOrHeader> {
/*
* Multimap for function-scope atom declarations.
*
* Wraps an internal DeclOrHeader map with multi-map functionality.
* Wraps an internal DefinitionList map with multi-map functionality.
*
* In the common case, no block scoping is used, and atoms have a single
* associated definition. In the uncommon (block scoping) case, we map the atom
@ -230,27 +329,17 @@ template <> struct IsPodType<DefnOrHeader> {
*/
class AtomDecls
{
/* AtomDeclsIter needs to get at the DOHMap directly. */
/* AtomDeclsIter needs to get at the DefnListMap directly. */
friend class AtomDeclsIter;
JSContext *cx;
AtomDOHMap *map;
AtomDefnListMap *map;
AtomDecls(const AtomDecls &other) MOZ_DELETE;
void operator=(const AtomDecls &other) MOZ_DELETE;
AtomDeclNode *allocNode(Definition *defn);
/*
* Fallibly return the value in |doh| as a node.
* Update the defn currently occupying |doh| to a node if necessary.
*/
AtomDeclNode *lastAsNode(DefnOrHeader *doh);
public:
explicit AtomDecls(JSContext *cx)
: cx(cx), map(NULL)
{}
explicit AtomDecls(JSContext *cx) : cx(cx), map(NULL) {}
~AtomDecls();
@ -264,7 +353,7 @@ class AtomDecls
inline Definition *lookupFirst(JSAtom *atom);
/* Perform a lookup that can iterate over the definitions associated with |atom|. */
inline MultiDeclRange lookupMulti(JSAtom *atom);
inline DefinitionList::Range lookupMulti(JSAtom *atom);
/* Add-or-update a known-unique definition for |atom|. */
inline bool addUnique(JSAtom *atom, Definition *defn);
@ -274,40 +363,26 @@ class AtomDecls
/* Updating the definition for an entry that is known to exist is infallible. */
void updateFirst(JSAtom *atom, Definition *defn) {
JS_ASSERT(map);
AtomDOHMap::Ptr p = map->lookup(atom);
AtomDefnListMap::Ptr p = map->lookup(atom);
JS_ASSERT(p);
if (p.value().isHeader())
p.value().header()->defn = defn;
else
p.value() = DefnOrHeader(defn);
p.value().setFront(defn);
}
/* Remove the node at the head of the chain for |atom|. */
void remove(JSAtom *atom) {
JS_ASSERT(map);
AtomDOHMap::Ptr p = map->lookup(atom);
AtomDefnListMap::Ptr p = map->lookup(atom);
if (!p)
return;
DefnOrHeader &doh = p.value();
if (!doh.isHeader()) {
DefinitionList &list = p.value();
if (!list.popFront()) {
map->remove(p);
return;
}
AtomDeclNode *node = doh.header();
AtomDeclNode *newHead = node->next;
if (newHead) {
if (newHead->next)
p.value() = DefnOrHeader(newHead);
else
p.value() = DefnOrHeader(newHead->defn);
} else {
map->remove(p);
}
}
AtomDOHMap::Range all() {
AtomDefnListMap::Range all() {
JS_ASSERT(map);
return map->all();
}
@ -317,85 +392,14 @@ class AtomDecls
#endif
};
/*
* Lookup state tracker for those situations where the caller wants to traverse
* multiple definitions associated with a single atom. This occurs due to block
* scoping.
*/
class MultiDeclRange
{
friend class AtomDecls;
AtomDeclNode *node;
Definition *defn;
explicit MultiDeclRange(Definition *defn) : node(NULL), defn(defn) {}
explicit MultiDeclRange(AtomDeclNode *node) : node(node), defn(node->defn) {}
public:
void popFront() {
JS_ASSERT(!empty());
if (!node) {
defn = NULL;
return;
}
node = node->next;
defn = node ? node->defn : NULL;
}
Definition *front() {
JS_ASSERT(!empty());
return defn;
}
bool empty() const {
JS_ASSERT_IF(!defn, !node);
return !defn;
}
};
/* Iterates over all the definitions in an AtomDecls. */
class AtomDeclsIter
{
AtomDOHMap::Range r; /* Range over the map. */
AtomDeclNode *link; /* Optional next node in the current atom's chain. */
public:
explicit AtomDeclsIter(AtomDecls *decls) : r(decls->all()), link(NULL) {}
Definition *next() {
if (link) {
JS_ASSERT(link != link->next);
Definition *result = link->defn;
link = link->next;
JS_ASSERT(result);
return result;
}
if (r.empty())
return NULL;
const DefnOrHeader &doh = r.front().value();
r.popFront();
if (!doh.isHeader())
return doh.defn();
JS_ASSERT(!link);
AtomDeclNode *node = doh.header();
link = node->next;
return node->defn;
}
};
typedef AtomDefnMap::Range AtomDefnRange;
typedef AtomDefnMap::AddPtr AtomDefnAddPtr;
typedef AtomDefnMap::Ptr AtomDefnPtr;
typedef AtomIndexMap::AddPtr AtomIndexAddPtr;
typedef AtomIndexMap::Ptr AtomIndexPtr;
typedef AtomDOHMap::Ptr AtomDOHPtr;
typedef AtomDOHMap::AddPtr AtomDOHAddPtr;
typedef AtomDOHMap::Range AtomDOHRange;
typedef AtomDefnListMap::Ptr AtomDefnListPtr;
typedef AtomDefnListMap::AddPtr AtomDefnListAddPtr;
typedef AtomDefnListMap::Range AtomDefnListRange;
} /* namepsace js */

View File

@ -706,13 +706,17 @@ Parser::functionBody(FunctionBodyType type)
* might, in the case of calls to eval) be assigned.
*/
if (tc->sc->inStrictMode()) {
AtomDeclsIter iter(&tc->decls);
while (Definition *dn = iter.next()) {
if (dn->kind() == Definition::ARG && dn->isAssigned()) {
tc->sc->setFunDefinitelyNeedsArgsObj();
break;
for (AtomDefnListMap::Range r = tc->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();
if (dn->kind() == Definition::ARG && dn->isAssigned()) {
tc->sc->setFunDefinitelyNeedsArgsObj();
goto exitLoop;
}
}
}
exitLoop: ;
}
break;
case ARGUMENT:
@ -1570,14 +1574,18 @@ Parser::functionDef(HandlePropertyName funName, FunctionType type, FunctionSynta
* Parser::functionArguments has returned.
*/
if (prelude) {
AtomDeclsIter iter(&funtc.decls);
while (Definition *apn = iter.next()) {
/* Filter based on pn_op -- see BindDestructuringArg, above. */
if (!apn->isOp(JSOP_SETLOCAL))
continue;
for (AtomDefnListMap::Range r = tc->decls.all(); !r.empty(); r.popFront()) {
DefinitionList &dlist = r.front().value();
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
Definition *apn = dr.front();
if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
return NULL;
/* Filter based on pn_op -- see BindDestructuringArg, above. */
if (!apn->isOp(JSOP_SETLOCAL))
continue;
if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
return NULL;
}
}
}
#endif
@ -2067,7 +2075,7 @@ OuterLet(TreeContext *tc, StmtInfoTC *stmt, JSAtom *atom)
}
static bool
BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContext *tc)
BindFunctionLocal(JSContext *cx, BindData *data, DefinitionList::Range &defs, TreeContext *tc)
{
JS_ASSERT(tc->sc->inFunction());
@ -2093,7 +2101,7 @@ BindFunctionLocal(JSContext *cx, BindData *data, MultiDeclRange &mdl, TreeContex
if (kind == ARGUMENT) {
JS_ASSERT(tc->sc->inFunction());
JS_ASSERT(!mdl.empty() && mdl.front()->kind() == Definition::ARG);
JS_ASSERT(!defs.empty() && defs.front()->kind() == Definition::ARG);
} else {
JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
}
@ -2122,11 +2130,11 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
return true;
}
MultiDeclRange mdl = tc->decls.lookupMulti(atom);
DefinitionList::Range defs = tc->decls.lookupMulti(atom);
JSOp op = data->op;
if (stmt || !mdl.empty()) {
Definition *dn = mdl.empty() ? NULL : mdl.front();
if (stmt || !defs.empty()) {
Definition *dn = defs.empty() ? NULL : defs.front();
Definition::Kind dn_kind = dn ? dn->kind() : Definition::VAR;
if (dn_kind == Definition::ARG) {
@ -2163,14 +2171,14 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
}
}
if (mdl.empty()) {
if (defs.empty()) {
if (!Define(pn, atom, tc))
return false;
} else {
/*
* A var declaration never recreates an existing binding, it restates
* it and possibly reinitializes its value. Beware that if pn becomes a
* use of |mdl.defn()|, and if we have an initializer for this var or
* use of |defs.defn()|, and if we have an initializer for this var or
* const (typically a const would ;-), then pn must be rewritten into a
* PNK_ASSIGN node. See js::Parser::variables, further below.
*
@ -2178,7 +2186,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
* There the x definition is hoisted but the x = 2 assignment mutates
* the block-local binding of x.
*/
Definition *dn = mdl.front();
Definition *dn = defs.front();
data->fresh = false;
@ -2198,10 +2206,10 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
/* Find the first non-let binding of this atom. */
while (dn->kind() == Definition::LET) {
mdl.popFront();
if (mdl.empty())
defs.popFront();
if (defs.empty())
break;
dn = mdl.front();
dn = defs.front();
}
if (dn) {
@ -2240,7 +2248,7 @@ BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
pn->pn_dflags |= PND_CONST;
if (tc->sc->inFunction())
return BindFunctionLocal(cx, data, mdl, tc);
return BindFunctionLocal(cx, data, defs, tc);
return true;
}
@ -2305,11 +2313,11 @@ NoteNameUse(ParseNode *pn, Parser *parser)
PropertyName *name = pn->pn_atom->asPropertyName();
StmtInfoTC *stmt = LexicalLookup(parser->tc, name, NULL, (StmtInfoTC *)NULL);
MultiDeclRange mdl = parser->tc->decls.lookupMulti(name);
DefinitionList::Range defs = parser->tc->decls.lookupMulti(name);
Definition *dn;
if (!mdl.empty()) {
dn = mdl.front();
if (!defs.empty()) {
dn = defs.front();
} else {
if (AtomDefnAddPtr p = parser->tc->lexdeps->lookupForAdd(name)) {
dn = p.value();

View File

@ -174,10 +174,9 @@ struct StackShape;
class MultiDeclRange;
class ParseMapPool;
class DefnOrHeader;
class DefinitionList;
typedef InlineMap<JSAtom *, Definition *, 24> AtomDefnMap;
typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
typedef InlineMap<JSAtom *, DefnOrHeader, 24> AtomDOHMap;
typedef Vector<UpvarCookie, 8> UpvarCookies;
class Breakpoint;