mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Back out 104ba36f44c0 (bug 845596) for jsreftest assertions
CLOSED TREE
This commit is contained in:
parent
57eb01050d
commit
748dfe1092
@ -48,7 +48,7 @@ class FullParseHandler
|
||||
foldConstants(foldConstants)
|
||||
{}
|
||||
|
||||
static ParseNode *null() { return NULL; }
|
||||
static Definition *null() { return NULL; }
|
||||
|
||||
ParseNode *freeTree(ParseNode *pn) { return allocator.freeTree(pn); }
|
||||
void prepareNodeForMutation(ParseNode *pn) { return allocator.prepareNodeForMutation(pn); }
|
||||
@ -62,16 +62,6 @@ 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)
|
||||
@ -178,9 +168,6 @@ 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();
|
||||
@ -205,9 +192,6 @@ 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;
|
||||
}
|
||||
@ -270,50 +254,6 @@ 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
|
||||
|
@ -48,20 +48,18 @@ ParseMapPool::allocate()
|
||||
return map;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline typename ParseHandler::DefinitionNode
|
||||
AtomDecls<ParseHandler>::lookupFirst(JSAtom *atom) const
|
||||
inline Definition *
|
||||
AtomDecls::lookupFirst(JSAtom *atom) const
|
||||
{
|
||||
JS_ASSERT(map);
|
||||
AtomDefnListPtr p = map->lookup(atom);
|
||||
if (!p)
|
||||
return ParseHandler::nullDefinition();
|
||||
return p.value().front<ParseHandler>();
|
||||
return NULL;
|
||||
return p.value().front();
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline DefinitionList::Range
|
||||
AtomDecls<ParseHandler>::lookupMulti(JSAtom *atom) const
|
||||
AtomDecls::lookupMulti(JSAtom *atom) const
|
||||
{
|
||||
JS_ASSERT(map);
|
||||
if (AtomDefnListPtr p = map->lookup(atom))
|
||||
@ -69,16 +67,15 @@ AtomDecls<ParseHandler>::lookupMulti(JSAtom *atom) const
|
||||
return DefinitionList::Range();
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline bool
|
||||
AtomDecls<ParseHandler>::addUnique(JSAtom *atom, DefinitionNode defn)
|
||||
AtomDecls::addUnique(JSAtom *atom, Definition *defn)
|
||||
{
|
||||
JS_ASSERT(map);
|
||||
AtomDefnListAddPtr p = map->lookupForAdd(atom);
|
||||
if (!p)
|
||||
return map->add(p, atom, DefinitionList(ParseHandler::definitionToBits(defn)));
|
||||
return map->add(p, atom, DefinitionList(defn));
|
||||
JS_ASSERT(!p.value().isMultiple());
|
||||
p.value() = DefinitionList(ParseHandler::definitionToBits(defn));
|
||||
p.value() = DefinitionList(defn);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -102,17 +99,15 @@ AtomThingMapPtr<Map>::releaseMap(JSContext *cx)
|
||||
map_ = NULL;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline bool
|
||||
AtomDecls<ParseHandler>::init()
|
||||
AtomDecls::init()
|
||||
{
|
||||
map = cx->parseMapPool().acquire<AtomDefnListMap>();
|
||||
return map;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
inline
|
||||
AtomDecls<ParseHandler>::~AtomDecls()
|
||||
AtomDecls::~AtomDecls()
|
||||
{
|
||||
if (map)
|
||||
cx->parseMapPool().release(map);
|
||||
|
@ -5,12 +5,10 @@
|
||||
* 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;
|
||||
@ -60,7 +58,7 @@ ParseMapPool::allocateFresh()
|
||||
}
|
||||
|
||||
DefinitionList::Node *
|
||||
DefinitionList::allocNode(JSContext *cx, uintptr_t head, Node *tail)
|
||||
DefinitionList::allocNode(JSContext *cx, Definition *head, Node *tail)
|
||||
{
|
||||
Node *result = cx->tempLifoAlloc().new_<Node>(head, tail);
|
||||
if (!result)
|
||||
@ -68,17 +66,58 @@ DefinitionList::allocNode(JSContext *cx, uintptr_t 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<ParseHandler>::dump()
|
||||
AtomDecls::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<ParseHandler>());
|
||||
fprintf(stderr, " defn: %p\n", (void *) dr.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,20 +133,19 @@ 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().get<FullParseHandler>());
|
||||
fprintf(stderr, "defn: %p\n", (void *) r.front().value());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
AtomDecls<ParseHandler>::addShadow(JSAtom *atom, typename ParseHandler::DefinitionNode defn)
|
||||
AtomDecls::addShadow(JSAtom *atom, Definition *defn)
|
||||
{
|
||||
AtomDefnListAddPtr p = map->lookupForAdd(atom);
|
||||
if (!p)
|
||||
return map->add(p, atom, DefinitionList(ParseHandler::definitionToBits(defn)));
|
||||
return map->add(p, atom, DefinitionList(defn));
|
||||
|
||||
return p.value().pushFront<ParseHandler>(cx, defn);
|
||||
return p.value().pushFront(cx, defn);
|
||||
}
|
||||
|
||||
void
|
||||
@ -133,6 +171,3 @@ frontend::InitAtomMap(JSContext *cx, frontend::AtomIndexMap *indices, HeapPtrAto
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template class AtomDecls<FullParseHandler>;
|
||||
template class AtomDecls<SyntaxParseHandler>;
|
||||
|
@ -18,11 +18,11 @@
|
||||
namespace js {
|
||||
namespace frontend {
|
||||
|
||||
class DefinitionSingle;
|
||||
struct Definition;
|
||||
class DefinitionList;
|
||||
|
||||
typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
|
||||
typedef InlineMap<JSAtom *, DefinitionSingle, 24> AtomDefnMap;
|
||||
typedef InlineMap<JSAtom *, Definition *, 24> AtomDefnMap;
|
||||
typedef InlineMap<JSAtom *, DefinitionList, 24> AtomDefnListMap;
|
||||
|
||||
/*
|
||||
@ -135,6 +135,15 @@ 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;
|
||||
|
||||
/*
|
||||
@ -156,48 +165,8 @@ class OwnedAtomThingMapPtr : public AtomThingMapPtrT
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
|
||||
|
||||
/*
|
||||
* A nonempty list containing one or more pointers to Definitions.
|
||||
@ -222,24 +191,30 @@ class DefinitionList
|
||||
/* A node in a linked list of Definitions. */
|
||||
struct Node
|
||||
{
|
||||
uintptr_t bits;
|
||||
Definition *defn;
|
||||
Node *next;
|
||||
|
||||
Node(uintptr_t bits, Node *next) : bits(bits), next(next) {}
|
||||
Node(Definition *defn, Node *next) : defn(defn), next(next) {}
|
||||
};
|
||||
|
||||
union {
|
||||
uintptr_t bits;
|
||||
Definition *defn;
|
||||
Node *head;
|
||||
uintptr_t bits;
|
||||
} 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, uintptr_t bits, Node *tail);
|
||||
allocNode(JSContext *cx, Definition *head, Node *tail);
|
||||
|
||||
public:
|
||||
class Range
|
||||
@ -247,41 +222,40 @@ class DefinitionList
|
||||
friend class DefinitionList;
|
||||
|
||||
Node *node;
|
||||
uintptr_t bits;
|
||||
Definition *defn;
|
||||
|
||||
explicit Range(const DefinitionList &list) {
|
||||
if (list.isMultiple()) {
|
||||
node = list.firstNode();
|
||||
bits = node->bits;
|
||||
defn = node->defn;
|
||||
} else {
|
||||
node = NULL;
|
||||
bits = list.u.bits;
|
||||
defn = list.defn();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/* An empty Range. */
|
||||
Range() : node(NULL), bits(0) {}
|
||||
Range() : node(NULL), defn(NULL) {}
|
||||
|
||||
void popFront() {
|
||||
JS_ASSERT(!empty());
|
||||
if (!node) {
|
||||
bits = 0;
|
||||
defn = NULL;
|
||||
return;
|
||||
}
|
||||
node = node->next;
|
||||
bits = node ? node->bits : 0;
|
||||
defn = node ? node->defn : NULL;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::DefinitionNode front() {
|
||||
Definition *front() {
|
||||
JS_ASSERT(!empty());
|
||||
return ParseHandler::definitionFromBits(bits);
|
||||
return defn;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
JS_ASSERT_IF(!bits, !node);
|
||||
return !bits;
|
||||
JS_ASSERT_IF(!defn, !node);
|
||||
return !defn;
|
||||
}
|
||||
};
|
||||
|
||||
@ -289,8 +263,8 @@ class DefinitionList
|
||||
u.bits = 0;
|
||||
}
|
||||
|
||||
explicit DefinitionList(uintptr_t bits) {
|
||||
u.bits = bits;
|
||||
explicit DefinitionList(Definition *defn) {
|
||||
u.defn = defn;
|
||||
JS_ASSERT(!isMultiple());
|
||||
}
|
||||
|
||||
@ -302,9 +276,8 @@ class DefinitionList
|
||||
|
||||
bool isMultiple() const { return (u.bits & 0x1) != 0; }
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::DefinitionNode front() {
|
||||
return ParseHandler::definitionFromBits(isMultiple() ? firstNode()->bits : u.bits);
|
||||
Definition *front() {
|
||||
return isMultiple() ? firstNode()->defn : defn();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -321,7 +294,7 @@ class DefinitionList
|
||||
if (next->next)
|
||||
*this = DefinitionList(next);
|
||||
else
|
||||
*this = DefinitionList(next->bits);
|
||||
*this = DefinitionList(next->defn);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -330,31 +303,17 @@ class DefinitionList
|
||||
*
|
||||
* Return true on success. On OOM, report on cx and return false.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
bool pushFront(JSContext *cx, Definition *val);
|
||||
|
||||
Node *node = allocNode(cx, ParseHandler::definitionToBits(defn), tail);
|
||||
if (!node)
|
||||
return false;
|
||||
*this = DefinitionList(node);
|
||||
return true;
|
||||
}
|
||||
/* 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. */
|
||||
template <typename ParseHandler>
|
||||
void setFront(typename ParseHandler::DefinitionNode defn) {
|
||||
void setFront(Definition *val) {
|
||||
if (isMultiple())
|
||||
firstNode()->bits = ParseHandler::definitionToBits(defn);
|
||||
firstNode()->defn = val;
|
||||
else
|
||||
*this = DefinitionList(ParseHandler::definitionToBits(defn));
|
||||
*this = DefinitionList(val);
|
||||
}
|
||||
|
||||
Range all() const { return Range(*this); }
|
||||
@ -382,11 +341,8 @@ 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;
|
||||
|
||||
@ -408,21 +364,21 @@ class AtomDecls
|
||||
}
|
||||
|
||||
/* Return the definition at the head of the chain for |atom|. */
|
||||
inline DefinitionNode lookupFirst(JSAtom *atom) const;
|
||||
inline Definition *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, DefinitionNode defn);
|
||||
bool addShadow(JSAtom *atom, DefinitionNode defn);
|
||||
inline bool addUnique(JSAtom *atom, Definition *defn);
|
||||
bool addShadow(JSAtom *atom, Definition *defn);
|
||||
|
||||
/* Updating the definition for an entry that is known to exist is infallible. */
|
||||
void updateFirst(JSAtom *atom, DefinitionNode defn) {
|
||||
void updateFirst(JSAtom *atom, Definition *defn) {
|
||||
JS_ASSERT(map);
|
||||
AtomDefnListMap::Ptr p = map->lookup(atom);
|
||||
JS_ASSERT(p);
|
||||
p.value().setFront<ParseHandler>(defn);
|
||||
p.value().setFront(defn);
|
||||
}
|
||||
|
||||
/* Remove the node at the head of the chain for |atom|. */
|
||||
@ -464,9 +420,6 @@ typedef AtomDefnListMap::Range AtomDefnListRange;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template <>
|
||||
struct IsPod<js::frontend::DefinitionSingle> : TrueType {};
|
||||
|
||||
template <>
|
||||
struct IsPod<js::frontend::DefinitionList> : TrueType {};
|
||||
|
||||
|
@ -461,7 +461,7 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode *opn)
|
||||
*/
|
||||
if (opn->isDefn()) {
|
||||
opn->setDefn(false);
|
||||
handler.linkUseToDef(opn, (Definition *) pn);
|
||||
LinkUseToDef(opn, (Definition *) pn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -552,7 +552,7 @@ Parser<FullParseHandler>::cloneLeftHandSide(ParseNode *opn)
|
||||
pn->pn_dflags &= ~PND_BOUND;
|
||||
pn->setDefn(false);
|
||||
|
||||
handler.linkUseToDef(pn, (Definition *) opn);
|
||||
LinkUseToDef(pn, (Definition *) opn);
|
||||
}
|
||||
}
|
||||
return pn;
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "frontend/ParseMaps.h"
|
||||
#include "frontend/TokenStream.h"
|
||||
|
||||
namespace js {
|
||||
@ -1214,7 +1215,7 @@ struct Definition : public ParseNode
|
||||
return pn_cookie.isFree();
|
||||
}
|
||||
|
||||
enum Kind { MISSING = 0, VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
|
||||
enum Kind { VAR, CONST, LET, ARG, NAMED_LAMBDA, PLACEHOLDER };
|
||||
|
||||
bool canHaveInitializer() { return int(kind()) <= int(ARG); }
|
||||
|
||||
@ -1297,6 +1298,19 @@ 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;
|
||||
|
@ -125,7 +125,7 @@ ParseContext<FullParseHandler>::define(JSContext *cx, HandlePropertyName name,
|
||||
JS_ASSERT(!decls_.lookupFirst(name));
|
||||
|
||||
if (!prevDef)
|
||||
prevDef = lexdeps.lookupDefn<FullParseHandler>(name);
|
||||
prevDef = lexdeps.lookupDefn(name);
|
||||
|
||||
if (prevDef) {
|
||||
ParseNode **pnup = &prevDef->dn_uses;
|
||||
@ -196,7 +196,8 @@ ParseContext<FullParseHandler>::define(JSContext *cx, HandlePropertyName name,
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
case Definition::PLACEHOLDER:
|
||||
case Definition::NAMED_LAMBDA:
|
||||
JS_NOT_REACHED("unexpected kind");
|
||||
break;
|
||||
}
|
||||
@ -209,20 +210,17 @@ bool
|
||||
ParseContext<SyntaxParseHandler>::define(JSContext *cx, HandlePropertyName name, Node pn,
|
||||
Definition::Kind kind)
|
||||
{
|
||||
JS_ASSERT(!decls_.lookupFirst(name));
|
||||
|
||||
if (lexdeps.lookupDefn<SyntaxParseHandler>(name))
|
||||
lexdeps->remove(name);
|
||||
|
||||
return decls_.addUnique(name, kind);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
void
|
||||
ParseContext<ParseHandler>::prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl)
|
||||
ParseContext<ParseHandler>::prepareToAddDuplicateArg(Definition *prevDecl)
|
||||
{
|
||||
JS_ASSERT(decls_.lookupFirst(name) == prevDecl);
|
||||
decls_.remove(name);
|
||||
JS_ASSERT(prevDecl->kind() == Definition::ARG);
|
||||
JS_ASSERT(decls_.lookupFirst(prevDecl->name()) == prevDecl);
|
||||
JS_ASSERT(!prevDecl->isClosed());
|
||||
decls_.remove(prevDecl->name());
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@ -260,7 +258,7 @@ template <typename ParseHandler>
|
||||
void
|
||||
ParseContext<ParseHandler>::popLetDecl(JSAtom *atom)
|
||||
{
|
||||
JS_ASSERT(ParseHandler::getDefinitionKind(decls_.lookupFirst(atom)) == Definition::LET);
|
||||
JS_ASSERT(decls_.lookupFirst(atom)->isLet());
|
||||
decls_.remove(atom);
|
||||
}
|
||||
|
||||
@ -283,7 +281,9 @@ AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec
|
||||
case Definition::ARG:
|
||||
kind = ARGUMENT;
|
||||
break;
|
||||
default:
|
||||
case Definition::LET:
|
||||
case Definition::NAMED_LAMBDA:
|
||||
case Definition::PLACEHOLDER:
|
||||
JS_NOT_REACHED("unexpected dn->kind");
|
||||
}
|
||||
|
||||
@ -821,6 +821,11 @@ 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,
|
||||
@ -870,21 +875,27 @@ 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 (Definition *dn = pc->decls().lookupFirst(name))
|
||||
if (name == arguments)
|
||||
pc->sc->setBindingsAccessedDynamically();
|
||||
else 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
|
||||
@ -892,7 +903,7 @@ Parser<FullParseHandler>::checkFunctionArguments()
|
||||
*/
|
||||
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
|
||||
if (r.front().key() == arguments) {
|
||||
Definition *dn = r.front().value().get<FullParseHandler>();
|
||||
Definition *dn = r.front().value();
|
||||
pc->lexdeps->remove(arguments);
|
||||
dn->pn_dflags |= PND_IMPLICITARGUMENTS;
|
||||
if (!pc->define(context, arguments, dn, Definition::VAR))
|
||||
@ -968,7 +979,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<FullParseHandler>();
|
||||
Definition *dn = dr.front();
|
||||
if (dn->kind() == Definition::ARG && dn->isAssigned())
|
||||
funbox->setDefinitelyNeedsArgsObj();
|
||||
}
|
||||
@ -1034,6 +1045,23 @@ 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)
|
||||
{
|
||||
@ -1225,6 +1253,23 @@ 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
|
||||
@ -1249,7 +1294,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().get<FullParseHandler>();
|
||||
Definition *dn = r.front().value();
|
||||
JS_ASSERT(dn->isPlaceholder());
|
||||
|
||||
if (atom == funName && kind == Expression) {
|
||||
@ -1292,12 +1337,12 @@ Parser<FullParseHandler>::leaveFunction(ParseNode *fn, HandlePropertyName funNam
|
||||
* having an extensible scope) or any enclosing 'with'.
|
||||
*/
|
||||
if (funbox->hasExtensibleScope() || outerpc->parsingWith)
|
||||
handler.deoptimizeUsesWithin(dn, fn->pn_pos);
|
||||
DeoptimizeUsesWithin(dn, fn->pn_pos);
|
||||
|
||||
if (!outer_dn) {
|
||||
AtomDefnAddPtr p = outerpc->lexdeps->lookupForAdd(atom);
|
||||
if (p) {
|
||||
outer_dn = p.value().get<FullParseHandler>();
|
||||
outer_dn = p.value();
|
||||
} else {
|
||||
/*
|
||||
* Create a new placeholder for our outer lexdep. We could
|
||||
@ -1320,11 +1365,8 @@ 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 = handler.newPlaceholder(dn, outerpc);
|
||||
if (!outer_dn)
|
||||
return false;
|
||||
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(outer_dn);
|
||||
if (!outerpc->lexdeps->add(p, atom, def))
|
||||
outer_dn = MakePlaceholder(dn, &handler, outerpc);
|
||||
if (!outer_dn || !outerpc->lexdeps->add(p, atom, outer_dn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1396,28 +1438,26 @@ 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 <typename ParseHandler>
|
||||
template <>
|
||||
bool
|
||||
Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
|
||||
bool disallowDuplicateArgs, Node *duplicatedArg)
|
||||
Parser<FullParseHandler>::defineArg(ParseNode *funcpn, HandlePropertyName name,
|
||||
bool disallowDuplicateArgs, Definition **duplicatedArg)
|
||||
{
|
||||
SharedContext *sc = pc->sc;
|
||||
|
||||
/* Handle duplicate argument names. */
|
||||
if (DefinitionNode prevDecl = pc->decls().lookupFirst(name)) {
|
||||
Node pn = handler.getDefinitionNode(prevDecl);
|
||||
|
||||
if (Definition *prevDecl = pc->decls().lookupFirst(name)) {
|
||||
/*
|
||||
* 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, report will queue up the potential error and return
|
||||
* 'true'.
|
||||
* In such cases, reportStrictModeError 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, pn,
|
||||
if (!report(ParseStrictError, pc->sc->strict, prevDecl,
|
||||
JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
|
||||
{
|
||||
return false;
|
||||
@ -1425,29 +1465,36 @@ Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
|
||||
}
|
||||
|
||||
if (disallowDuplicateArgs) {
|
||||
report(ParseError, false, pn, JSMSG_BAD_DUP_ARGS);
|
||||
report(ParseError, false, prevDecl, JSMSG_BAD_DUP_ARGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duplicatedArg)
|
||||
*duplicatedArg = pn;
|
||||
*duplicatedArg = prevDecl;
|
||||
|
||||
/* ParseContext::define assumes and asserts prevDecl is not in decls. */
|
||||
JS_ASSERT(handler.getDefinitionKind(prevDecl) == Definition::ARG);
|
||||
pc->prepareToAddDuplicateArg(name, prevDecl);
|
||||
pc->prepareToAddDuplicateArg(prevDecl);
|
||||
}
|
||||
|
||||
Node argpn = handler.newName(name, pc);
|
||||
ParseNode *argpn = handler.newName(name, pc);
|
||||
if (!argpn)
|
||||
return false;
|
||||
|
||||
if (!checkStrictBinding(name, argpn))
|
||||
return false;
|
||||
|
||||
handler.addFunctionArgument(funcpn, argpn);
|
||||
funcpn->pn_body->append(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
|
||||
@ -1500,7 +1547,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, Node *listp, No
|
||||
|
||||
if (parenFreeArrow || !tokenStream.matchToken(TOK_RP)) {
|
||||
bool hasDefaults = false;
|
||||
Node duplicatedArg = null();
|
||||
DefinitionNode duplicatedArg = null();
|
||||
bool destructuringArg = false;
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
Node list = null();
|
||||
@ -1690,7 +1737,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<FullParseHandler>(funName)) {
|
||||
if (Definition *fn = pc->lexdeps.lookupDefn(funName)) {
|
||||
JS_ASSERT(fn->isDefn());
|
||||
fn->setKind(PNK_FUNCTION);
|
||||
fn->setArity(PN_CODE);
|
||||
@ -1743,15 +1790,6 @@ 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. */
|
||||
@ -1769,36 +1807,6 @@ 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;
|
||||
}
|
||||
|
||||
@ -2466,17 +2474,17 @@ OuterLet(ParseContext<ParseHandler> *pc, StmtInfoPC *stmt, HandleAtom atom)
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
template <>
|
||||
/* static */ bool
|
||||
Parser<ParseHandler>::bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data,
|
||||
HandlePropertyName name, Parser<ParseHandler> *parser)
|
||||
Parser<FullParseHandler>::bindVarOrConst(JSContext *cx, BindData<FullParseHandler> *data,
|
||||
HandlePropertyName name, Parser<FullParseHandler> *parser)
|
||||
{
|
||||
ParseContext<ParseHandler> *pc = parser->pc;
|
||||
Node pn = data->pn;
|
||||
ParseContext<FullParseHandler> *pc = parser->pc;
|
||||
ParseNode *pn = data->pn;
|
||||
bool isConstDecl = data->op == JSOP_DEFCONST;
|
||||
|
||||
/* Default best op for pn is JSOP_NAME; we'll try to improve below. */
|
||||
parser->handler.setOp(pn, JSOP_NAME);
|
||||
pn->setOp(JSOP_NAME);
|
||||
|
||||
if (!parser->checkStrictBinding(name, pn))
|
||||
return false;
|
||||
@ -2484,7 +2492,7 @@ Parser<ParseHandler>::bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data
|
||||
StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL);
|
||||
|
||||
if (stmt && stmt->type == STMT_WITH) {
|
||||
parser->handler.setFlag(pn, PND_DEOPTIMIZED);
|
||||
pn->pn_dflags |= PND_DEOPTIMIZED;
|
||||
if (pc->sc->isFunctionBox()) {
|
||||
FunctionBox *funbox = pc->sc->asFunctionBox();
|
||||
funbox->setMightAliasLocals();
|
||||
@ -2515,8 +2523,8 @@ Parser<ParseHandler>::bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data
|
||||
* is not allowed which allows us to turn any non-error redeclaration
|
||||
* into a use of the initial declaration.
|
||||
*/
|
||||
DefinitionNode dn = defs.front<ParseHandler>();
|
||||
Definition::Kind dn_kind = parser->handler.getDefinitionKind(dn);
|
||||
Definition *dn = defs.front();
|
||||
Definition::Kind dn_kind = dn->kind();
|
||||
if (dn_kind == Definition::ARG) {
|
||||
JSAutoByteString bytes;
|
||||
if (!js_AtomToPrintableString(cx, name, &bytes))
|
||||
@ -2549,7 +2557,16 @@ Parser<ParseHandler>::bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data
|
||||
}
|
||||
}
|
||||
|
||||
parser->handler.linkUseToDef(pn, dn);
|
||||
LinkUseToDef(pn, dn);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
/* static */ bool
|
||||
Parser<SyntaxParseHandler>::bindVarOrConst(JSContext *cx, BindData<SyntaxParseHandler> *data,
|
||||
HandlePropertyName name,
|
||||
Parser<SyntaxParseHandler> *parser)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2572,20 +2589,21 @@ Parser<FullParseHandler>::makeSetCall(ParseNode *pn, unsigned msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
template <>
|
||||
bool
|
||||
Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
|
||||
Parser<FullParseHandler>::noteNameUse(ParseNode *pn)
|
||||
{
|
||||
RootedPropertyName name(context, pn->pn_atom->asPropertyName());
|
||||
StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL);
|
||||
|
||||
DefinitionList::Range defs = pc->decls().lookupMulti(name);
|
||||
|
||||
DefinitionNode dn;
|
||||
Definition *dn;
|
||||
if (!defs.empty()) {
|
||||
dn = defs.front<ParseHandler>();
|
||||
dn = defs.front();
|
||||
} else {
|
||||
if (AtomDefnAddPtr p = pc->lexdeps->lookupForAdd(name)) {
|
||||
dn = p.value().get<ParseHandler>();
|
||||
dn = p.value();
|
||||
} else {
|
||||
/*
|
||||
* No definition before this use in any lexical scope.
|
||||
@ -2595,23 +2613,28 @@ Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
|
||||
* - Be left as a free variable definition if we never
|
||||
* see the real definition.
|
||||
*/
|
||||
dn = handler.newPlaceholder(pn, pc);
|
||||
if (!dn)
|
||||
return false;
|
||||
DefinitionSingle def = DefinitionSingle::new_<ParseHandler>(dn);
|
||||
if (!pc->lexdeps->add(p, name, def))
|
||||
dn = MakePlaceholder(pn, &handler, pc);
|
||||
if (!dn || !pc->lexdeps->add(p, name, dn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
handler.linkUseToDef(pn, dn);
|
||||
JS_ASSERT(dn->isDefn());
|
||||
LinkUseToDef(pn, dn);
|
||||
|
||||
if (stmt && stmt->type == STMT_WITH)
|
||||
handler.setFlag(pn, PND_DEOPTIMIZED);
|
||||
pn->pn_dflags |= PND_DEOPTIMIZED;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<SyntaxParseHandler>::noteNameUse(Node pn)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_DESTRUCTURING
|
||||
|
||||
template <>
|
||||
@ -2793,8 +2816,7 @@ Parser<FullParseHandler>::checkDestructuring(BindData<FullParseHandler> *data,
|
||||
* officially linked to its def or registered in lexdeps. Do
|
||||
* that now.
|
||||
*/
|
||||
RootedPropertyName name(context, pn->pn_atom->asPropertyName());
|
||||
if (pair->pn_right == pair->pn_left && !noteNameUse(name, pn))
|
||||
if (pair->pn_right == pair->pn_left && !noteNameUse(pn))
|
||||
return false;
|
||||
ok = bindDestructuringLHS(pn);
|
||||
}
|
||||
@ -3121,9 +3143,9 @@ PushBlocklikeStatement(StmtInfoPC *stmt, StmtType type, ParseContext<ParseHandle
|
||||
return GenerateBlockId(pc, stmt->blockid);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, VarContext varContext)
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::newBindingNode(PropertyName *name, VarContext varContext)
|
||||
{
|
||||
/*
|
||||
* If this name is being injected into an existing block/function, see if
|
||||
@ -3134,15 +3156,13 @@ Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, Var
|
||||
*/
|
||||
if (varContext == HoistVars) {
|
||||
if (AtomDefnPtr p = pc->lexdeps->lookup(name)) {
|
||||
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());
|
||||
ParseNode *lexdep = p.value();
|
||||
JS_ASSERT(lexdep->isPlaceholder());
|
||||
if (lexdep->pn_blockid >= pc->blockid()) {
|
||||
lexdep->pn_blockid = pc->blockid();
|
||||
pc->lexdeps->remove(p);
|
||||
handler.setPosition(pn, tokenStream.currentToken().pos);
|
||||
return pn;
|
||||
lexdep->pn_pos = tokenStream.currentToken().pos;
|
||||
return lexdep;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3152,6 +3172,13 @@ Parser<ParseHandler>::newBindingNode(PropertyName *name, bool functionScope, Var
|
||||
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()
|
||||
@ -3877,7 +3904,7 @@ Parser<ParseHandler>::tryStatement()
|
||||
case TOK_NAME:
|
||||
{
|
||||
RootedPropertyName label(context, tokenStream.currentToken().name());
|
||||
catchName = newBindingNode(label, false);
|
||||
catchName = newBindingNode(label);
|
||||
if (!catchName)
|
||||
return null();
|
||||
data.pn = catchName;
|
||||
@ -3993,10 +4020,9 @@ Parser<ParseHandler>::withStatement()
|
||||
* to safely optimize binding globals (see bug 561923).
|
||||
*/
|
||||
for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) {
|
||||
DefinitionNode defn = r.front().value().get<ParseHandler>();
|
||||
DefinitionNode lexdep = handler.resolve(defn);
|
||||
handler.deoptimizeUsesWithin(lexdep,
|
||||
TokenPos::make(begin, tokenStream.currentToken().pos.begin));
|
||||
Definition *defn = r.front().value();
|
||||
Definition *lexdep = defn->resolve();
|
||||
DeoptimizeUsesWithin(lexdep, TokenPos::make(begin, tokenStream.currentToken().pos.begin));
|
||||
}
|
||||
|
||||
Node pn = handler.newBinary(PNK_WITH, objectExpr, innerBlock);
|
||||
@ -4568,7 +4594,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
|
||||
}
|
||||
|
||||
RootedPropertyName name(context, tokenStream.currentToken().name());
|
||||
pn2 = newBindingNode(name, kind == PNK_VAR || kind == PNK_CONST, varContext);
|
||||
pn2 = newBindingNode(name, varContext);
|
||||
if (!pn2)
|
||||
return null();
|
||||
if (data.op == JSOP_DEFCONST)
|
||||
@ -5419,7 +5445,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
|
||||
* generator) a use of a new placeholder in the generator's
|
||||
* lexdeps.
|
||||
*/
|
||||
Definition *dn2 = parser->handler.newPlaceholder(pn, parser->pc);
|
||||
Definition *dn2 = MakePlaceholder(pn, &parser->handler, parser->pc);
|
||||
if (!dn2)
|
||||
return false;
|
||||
dn2->pn_pos = root->pn_pos;
|
||||
@ -5438,8 +5464,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
|
||||
dn2->dn_uses = dn->dn_uses;
|
||||
dn->dn_uses = *pnup;
|
||||
*pnup = NULL;
|
||||
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn2);
|
||||
if (!pc->lexdeps->put(atom, def))
|
||||
if (!pc->lexdeps->put(atom, dn2))
|
||||
return false;
|
||||
if (dn->isClosed())
|
||||
dn2->pn_dflags |= PND_CLOSED;
|
||||
@ -5450,8 +5475,7 @@ CompExprTransplanter::transplant(ParseNode *pn)
|
||||
* from the parent's lexdeps into the generator's lexdeps.
|
||||
*/
|
||||
outerpc->lexdeps->remove(atom);
|
||||
DefinitionSingle def = DefinitionSingle::new_<FullParseHandler>(dn);
|
||||
if (!pc->lexdeps->put(atom, def))
|
||||
if (!pc->lexdeps->put(atom, dn))
|
||||
return false;
|
||||
} else if (dn->isImplicitArguments()) {
|
||||
/*
|
||||
@ -5605,7 +5629,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, false);
|
||||
pn3 = newBindingNode(name);
|
||||
if (!pn3)
|
||||
return null();
|
||||
break;
|
||||
@ -6121,12 +6145,12 @@ Parser<ParseHandler>::identifierName()
|
||||
{
|
||||
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
|
||||
|
||||
RootedPropertyName name(context, tokenStream.currentToken().name());
|
||||
PropertyName *name = tokenStream.currentToken().name();
|
||||
Node pn = handler.newName(name, pc);
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
if (!pc->inDeclDestructuring && !noteNameUse(name, pn))
|
||||
if (!pc->inDeclDestructuring && !noteNameUse(pn))
|
||||
return null();
|
||||
|
||||
return pn;
|
||||
|
@ -85,7 +85,6 @@ 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 */
|
||||
@ -104,12 +103,12 @@ struct ParseContext : public GenericParseContext
|
||||
Node blockNode; /* parse node for a block with let declarations
|
||||
(block with its own lexical scope) */
|
||||
private:
|
||||
AtomDecls<ParseHandler> decls_; /* function, const, and var declarations */
|
||||
AtomDecls decls_; /* function, const, and var declarations */
|
||||
DeclVector args_; /* argument definitions */
|
||||
DeclVector vars_; /* var/const definitions */
|
||||
|
||||
public:
|
||||
const AtomDecls<ParseHandler> &decls() const {
|
||||
const AtomDecls &decls() const {
|
||||
return decls_;
|
||||
}
|
||||
|
||||
@ -162,7 +161,7 @@ struct ParseContext : public GenericParseContext
|
||||
void popLetDecl(JSAtom *atom);
|
||||
|
||||
/* See the sad story in defineArg. */
|
||||
void prepareToAddDuplicateArg(HandlePropertyName name, DefinitionNode prevDecl);
|
||||
void prepareToAddDuplicateArg(Definition *prevDecl);
|
||||
|
||||
/* See the sad story in MakeDefIntoUse. */
|
||||
void updateDecl(JSAtom *atom, Node newDecl);
|
||||
@ -495,13 +494,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, Node *duplicatedArg = NULL);
|
||||
bool disallowDuplicateArgs = false, DefinitionNode *duplicatedArg = NULL);
|
||||
Node pushLexicalScope(StmtInfoPC *stmt);
|
||||
Node pushLexicalScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
|
||||
Node pushLetScope(Handle<StaticBlockObject*> blockObj, StmtInfoPC *stmt);
|
||||
bool noteNameUse(HandlePropertyName name, Node pn);
|
||||
bool noteNameUse(Node pn);
|
||||
Node newRegExp(const jschar *chars, size_t length, RegExpFlag flags);
|
||||
Node newBindingNode(PropertyName *name, bool functionScope, VarContext varContext = HoistVars);
|
||||
Node newBindingNode(PropertyName *name, VarContext varContext = HoistVars);
|
||||
bool checkDestructuring(BindData<ParseHandler> *data, Node left, bool toplevel = true);
|
||||
bool bindDestructuringVar(BindData<ParseHandler> *data, Node pn);
|
||||
bool bindDestructuringLHS(Node pn);
|
||||
@ -522,7 +521,7 @@ struct Parser : private AutoGCRooter, public StrictModeGetter
|
||||
bindVarOrConst(JSContext *cx, BindData<ParseHandler> *data,
|
||||
HandlePropertyName name, Parser<ParseHandler> *parser);
|
||||
|
||||
static Node null() { return ParseHandler::null(); }
|
||||
static DefinitionNode null() { return ParseHandler::null(); }
|
||||
|
||||
bool reportRedeclaration(Node pn, bool isConst, JSAtom *atom);
|
||||
bool reportBadReturn(Node pn, ParseReportKind kind, unsigned errnum, unsigned anonerrnum);
|
||||
|
@ -27,7 +27,7 @@ class SyntaxParseHandler
|
||||
NodeStringExprStatement,
|
||||
NodeLValue
|
||||
};
|
||||
typedef Definition::Kind DefinitionNode;
|
||||
typedef Node DefinitionNode;
|
||||
|
||||
SyntaxParseHandler(JSContext *cx, TokenStream &tokenStream, bool foldConstants)
|
||||
: lastAtom(NULL),
|
||||
@ -43,9 +43,6 @@ 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;
|
||||
@ -105,7 +102,6 @@ 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
|
||||
@ -123,8 +119,6 @@ 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;
|
||||
}
|
||||
@ -160,29 +154,6 @@ 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
|
||||
|
Loading…
Reference in New Issue
Block a user