mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 770850 - Reimplement DefnOrHeader as DefinitionList. r=njn.
This commit is contained in:
parent
ec7dba8378
commit
5a4279d4f3
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user