зеркало из https://github.com/mozilla/gecko-dev.git
Ongoing namespace implementation + first gc.
This commit is contained in:
Родитель
e6d2aefa12
Коммит
91f00d84f6
|
@ -88,7 +88,7 @@ js2val JS2Engine::interpreterLoop()
|
|||
// return a pointer to an 8 byte chunk in the gc heap
|
||||
void *JS2Engine::gc_alloc_8()
|
||||
{
|
||||
return STD::malloc(8);
|
||||
return JS2Object::alloc(8);
|
||||
}
|
||||
|
||||
// See if the double value is in the hash table, return it's pointer if so
|
||||
|
@ -243,6 +243,8 @@ int JS2Engine::getStackEffect(JS2Op op)
|
|||
case eQMultiname:
|
||||
return 1; // push the multiname object
|
||||
|
||||
case eUse:
|
||||
return -1; // consume a namespace object
|
||||
|
||||
default:
|
||||
ASSERT(false);
|
||||
|
|
|
@ -62,6 +62,7 @@ enum JS2Op {
|
|||
eNewObject, // <argCount:16>
|
||||
eMultiname, // <multiname index>
|
||||
eQMultiname, // <multiname index>
|
||||
eUse,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -107,6 +107,7 @@ namespace MetaData {
|
|||
case StmtNode::Var:
|
||||
case StmtNode::Const:
|
||||
{
|
||||
bool immutable = (p->getKind() == StmtNode::Const);
|
||||
Attribute *attr = NULL;
|
||||
VariableStmtNode *vs = checked_cast<VariableStmtNode *>(p);
|
||||
|
||||
|
@ -118,14 +119,15 @@ namespace MetaData {
|
|||
VariableBinding *v = vs->bindings;
|
||||
Frame *regionalFrame = env->getRegionalFrame();
|
||||
while (v) {
|
||||
const StringAtom *name = v->name;
|
||||
ValidateTypeExpression(v->type);
|
||||
|
||||
if (cxt->strict && ((regionalFrame->kind == GlobalObjectKind)
|
||||
|| (regionalFrame->kind == FunctionKind))
|
||||
&& (p->getKind() == StmtNode::Var) // !immutable
|
||||
&& !immutable
|
||||
&& (vs->attributes == NULL)
|
||||
&& (v->type == NULL)) {
|
||||
defineHoistedVar(env, *v->name, p);
|
||||
defineHoistedVar(env, *name, p);
|
||||
}
|
||||
else {
|
||||
CompoundAttribute *a = Attribute::toCompoundAttribute(attr);
|
||||
|
@ -137,15 +139,18 @@ namespace MetaData {
|
|||
memberMod = Attribute::Final;
|
||||
switch (memberMod) {
|
||||
case Attribute::NoModifier:
|
||||
case Attribute::Static:
|
||||
case Attribute::Static: {
|
||||
Variable *var = new Variable(NULL, JS2VAL_UNDEFINED, immutable);
|
||||
defineStaticMember(env, *name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, var, p->pos);
|
||||
// XXX - not done !!! XXX
|
||||
// the type and the value are 'future'
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
v = v->next;
|
||||
}
|
||||
if (attr)
|
||||
delete attr;
|
||||
}
|
||||
break;
|
||||
case StmtNode::expression:
|
||||
|
@ -171,6 +176,10 @@ namespace MetaData {
|
|||
defineStaticMember(env, ns->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
|
||||
}
|
||||
break;
|
||||
case StmtNode::Use:
|
||||
{
|
||||
}
|
||||
break;
|
||||
} // switch (p->getKind())
|
||||
}
|
||||
|
||||
|
@ -180,12 +189,16 @@ namespace MetaData {
|
|||
*/
|
||||
js2val JS2Metadata::EvalStmtList(Phase phase, StmtNode *p)
|
||||
{
|
||||
BytecodeContainer *saveBacon = bCon;
|
||||
bCon = new BytecodeContainer();
|
||||
while (p) {
|
||||
EvalStmt(&env, phase, p);
|
||||
p = p->next;
|
||||
}
|
||||
bCon->emitOp(eReturnVoid);
|
||||
return engine->interpret(this, phase, bCon);
|
||||
js2val retval = engine->interpret(this, phase, bCon);
|
||||
bCon = saveBacon;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -236,6 +249,18 @@ namespace MetaData {
|
|||
{
|
||||
}
|
||||
break;
|
||||
case StmtNode::Use:
|
||||
{
|
||||
UseStmtNode *u = checked_cast<UseStmtNode *>(p);
|
||||
ExprList *eList = u->namespaces;
|
||||
while (eList) {
|
||||
Reference *r = EvalExprNode(env, phase, eList->expr);
|
||||
if (r) r->emitReadBytecode(bCon);
|
||||
bCon->emitOp(eUse);
|
||||
eList = eList->next;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
} // switch (p->getKind())
|
||||
|
@ -358,10 +383,12 @@ namespace MetaData {
|
|||
// anything else (just references of one kind or another) must
|
||||
// be compile-time constant values that resolve to namespaces
|
||||
js2val av = EvalExpression(env, CompilePhase, p);
|
||||
if (JS2VAL_IS_NULL(av) || JS2VAL_IS_VOID(av) || !JS2VAL_IS_OBJECT(av))
|
||||
if (JS2VAL_IS_NULL(av) || !JS2VAL_IS_OBJECT(av))
|
||||
reportError(Exception::badValueError, "Namespace expected in attribute", p->pos);
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(av);
|
||||
|
||||
if ((obj->kind != AttributeObjectKind) || (checked_cast<Attribute *>(obj)->attrKind != Attribute::NamespaceAttr))
|
||||
reportError(Exception::badValueError, "Namespace expected in attribute", p->pos);
|
||||
return checked_cast<Attribute *>(obj);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -435,9 +462,13 @@ namespace MetaData {
|
|||
// add the namespace to our list, but only if it's not there already
|
||||
void CompoundAttribute::addNamespace(Namespace *n)
|
||||
{
|
||||
for (NamespaceListIterator i = namespaces->begin(), end = namespaces->end(); (i != end); i++)
|
||||
if (*i == n)
|
||||
return;
|
||||
if (namespaces) {
|
||||
for (NamespaceListIterator i = namespaces->begin(), end = namespaces->end(); (i != end); i++)
|
||||
if (*i == n)
|
||||
return;
|
||||
}
|
||||
else
|
||||
namespaces = new NamespaceList();
|
||||
namespaces->push_back(n);
|
||||
}
|
||||
|
||||
|
@ -538,11 +569,11 @@ namespace MetaData {
|
|||
{
|
||||
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
returnRef = EvalExprNode(env, phase, b->op1);
|
||||
if (returnRef) {
|
||||
Reference *lVal = EvalExprNode(env, phase, b->op1);
|
||||
if (lVal) {
|
||||
Reference *rVal = EvalExprNode(env, phase, b->op2);
|
||||
if (rVal) rVal->emitReadBytecode(bCon);
|
||||
returnRef->emitWriteBytecode(bCon);
|
||||
lVal->emitWriteBytecode(bCon);
|
||||
}
|
||||
else
|
||||
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
|
||||
|
@ -564,7 +595,7 @@ namespace MetaData {
|
|||
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", p->pos);
|
||||
UnaryExprNode *u = checked_cast<UnaryExprNode *>(p);
|
||||
Reference *lVal = EvalExprNode(env, phase, u->op);
|
||||
ASSERT(false); // not an lvalue
|
||||
ASSERT(false);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -578,14 +609,17 @@ namespace MetaData {
|
|||
{
|
||||
QualifyExprNode *qe = checked_cast<QualifyExprNode *>(p);
|
||||
const StringAtom &name = checked_cast<IdentifierExprNode *>(p)->name;
|
||||
EvalExprNode(env, phase, qe->qualifier);
|
||||
Reference *rVal = EvalExprNode(env, phase, qe->qualifier);
|
||||
if (rVal) rVal->emitReadBytecode(bCon);
|
||||
returnRef = new LexicalReference(name, cxt.strict, true);
|
||||
((LexicalReference *)returnRef)->emitBindBytecode(bCon);
|
||||
}
|
||||
break;
|
||||
case ExprNode::identifier:
|
||||
{
|
||||
IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
|
||||
returnRef = new LexicalReference(i->name, cxt.strict);
|
||||
((LexicalReference *)returnRef)->emitBindBytecode(bCon);
|
||||
}
|
||||
break;
|
||||
case ExprNode::boolean:
|
||||
|
@ -826,7 +860,7 @@ namespace MetaData {
|
|||
while (fr != regionalFrame) {
|
||||
for (b = fr->staticReadBindings.lower_bound(id),
|
||||
end = fr->staticReadBindings.upper_bound(id); (b != end); b++) {
|
||||
if (mn->matches(b->second->qname) && (b->second->content->kind != StaticMember::Forbidden))
|
||||
if (mn->matches(b->second->qname) && (b->second->content->kind == StaticMember::Forbidden))
|
||||
reportError(Exception::definitionError, "Duplicate definition {0}", pos, id);
|
||||
}
|
||||
fr = fr->nextFrame;
|
||||
|
@ -841,7 +875,7 @@ namespace MetaData {
|
|||
|
||||
for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) {
|
||||
QualifiedName qName(*nli, id);
|
||||
StaticBinding *sb = new StaticBinding(qName, new HoistedVar());
|
||||
StaticBinding *sb = new StaticBinding(qName, m);
|
||||
const StaticBindingMap::value_type e(id, sb);
|
||||
if (access & ReadAccess)
|
||||
regionalFrame->staticReadBindings.insert(e);
|
||||
|
@ -849,13 +883,12 @@ namespace MetaData {
|
|||
regionalFrame->staticWriteBindings.insert(e);
|
||||
}
|
||||
|
||||
StaticMember *forbidden = new StaticMember(StaticMember::Forbidden);
|
||||
if (localFrame != regionalFrame) {
|
||||
Frame *fr = localFrame->nextFrame;
|
||||
while (fr != regionalFrame) {
|
||||
for (NamespaceListIterator nli = mn->nsList.begin(), nlend = mn->nsList.end(); (nli != nlend); nli++) {
|
||||
QualifiedName qName(*nli, id);
|
||||
StaticBinding *sb = new StaticBinding(qName, forbidden);
|
||||
StaticBinding *sb = new StaticBinding(qName, forbiddenMember);
|
||||
const StaticBindingMap::value_type e(id, sb);
|
||||
if (access & ReadAccess)
|
||||
fr->staticReadBindings.insert(e);
|
||||
|
@ -1063,7 +1096,8 @@ namespace MetaData {
|
|||
reportError(Exception::propertyAccessError, "Forbidden access", errorPos);
|
||||
break;
|
||||
case StaticMember::Variable:
|
||||
break;
|
||||
*rval = (checked_cast<Variable *>(m))->value;
|
||||
return true;
|
||||
case StaticMember::HoistedVariable:
|
||||
*rval = (checked_cast<HoistedVar *>(m))->value;
|
||||
return true;
|
||||
|
@ -1086,7 +1120,8 @@ namespace MetaData {
|
|||
reportError(Exception::propertyAccessError, "Forbidden access", errorPos);
|
||||
break;
|
||||
case StaticMember::Variable:
|
||||
break;
|
||||
(checked_cast<Variable *>(m))->value = newValue;
|
||||
return true;
|
||||
case StaticMember::HoistedVariable:
|
||||
(checked_cast<HoistedVar *>(m))->value = newValue;
|
||||
return true;
|
||||
|
@ -1241,23 +1276,85 @@ namespace MetaData {
|
|||
*
|
||||
************************************************************************************/
|
||||
|
||||
Pond::Pond(size_t sz, Pond *next) : pondSize(sz + POND_SIZE), pondBase(new uint8[pondSize]), pondTop(pondBase), nextPond(next)
|
||||
Pond::Pond(size_t sz, Pond *next) : sanity(POND_SANITY), pondSize(sz + POND_SIZE), pondBase(new uint8[pondSize]), pondTop(pondBase), freeHeader(NULL), nextPond(next)
|
||||
{
|
||||
}
|
||||
|
||||
void *Pond::allocFromPond(size_t sz)
|
||||
// Allocate from this or the next Pond (make a new one if necessary)
|
||||
void *Pond::allocFromPond(int32 sz)
|
||||
{
|
||||
// Try scannning the free list...
|
||||
PondScum *p = freeHeader;
|
||||
PondScum *pre = NULL;
|
||||
while (p) {
|
||||
ASSERT(p->size > 0);
|
||||
if (p->size >= sz) {
|
||||
if (pre)
|
||||
pre->owner = p->owner;
|
||||
else
|
||||
freeHeader = (PondScum *)(p->owner);
|
||||
p->owner = this;
|
||||
return (p + 1);
|
||||
}
|
||||
pre = p;
|
||||
p = (PondScum *)(p->owner);
|
||||
}
|
||||
|
||||
// See if there's room left...
|
||||
if (sz > (pondSize - (pondTop - pondBase))) {
|
||||
if (nextPond == NULL)
|
||||
nextPond = new Pond(sz, nextPond);
|
||||
return nextPond->allocFromPond(sz);
|
||||
}
|
||||
void *p = pondTop;
|
||||
p = (PondScum *)pondTop;
|
||||
p->owner = this;
|
||||
p->size = sz;
|
||||
pondTop += sz;
|
||||
return p;
|
||||
#ifdef DEBUG
|
||||
memset((p + 1), 0xB7, p->size - sizeof(PondScum));
|
||||
#endif
|
||||
return (p + 1);
|
||||
}
|
||||
|
||||
// Stick the chunk at the start of the free list
|
||||
void Pond::returnToPond(PondScum *p)
|
||||
{
|
||||
p->owner = (Pond *)freeHeader;
|
||||
p->size &= 0x7FFFFFFF; // might have lingering mark from previous gc
|
||||
uint8 *t = (uint8 *)(p + 1);
|
||||
#ifdef DEBUG
|
||||
memset(t, 0xB7, p->size - sizeof(PondScum));
|
||||
#endif
|
||||
freeHeader = p;
|
||||
}
|
||||
|
||||
// Clear the mark bit from all PondScums
|
||||
void Pond::resetMarks()
|
||||
{
|
||||
uint8 *t = pondBase;
|
||||
while (t != pondTop) {
|
||||
PondScum *p = (PondScum *)t;
|
||||
p->resetMark();
|
||||
t += p->size;
|
||||
}
|
||||
if (nextPond)
|
||||
nextPond->resetMarks();
|
||||
}
|
||||
|
||||
// Anything left unmarked is now moved to the free list
|
||||
void Pond::moveUnmarkedToFreeList()
|
||||
{
|
||||
uint8 *t = pondBase;
|
||||
while (t != pondTop) {
|
||||
PondScum *p = (PondScum *)t;
|
||||
if (!p->isMarked())
|
||||
returnToPond(p);
|
||||
t += p->size;
|
||||
}
|
||||
if (nextPond)
|
||||
nextPond->moveUnmarkedToFreeList();
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************
|
||||
*
|
||||
* JS2Object
|
||||
|
@ -1265,14 +1362,42 @@ namespace MetaData {
|
|||
************************************************************************************/
|
||||
|
||||
Pond JS2Object::pond(POND_SIZE, NULL);
|
||||
std::vector<PondScum **> JS2Object::rootList;
|
||||
|
||||
void *JS2Object::operator new(size_t s)
|
||||
void JS2Object::addRoot(void *t)
|
||||
{
|
||||
PondScum **p = (PondScum **)t;
|
||||
ASSERT(p);
|
||||
rootList.push_back(p);
|
||||
}
|
||||
|
||||
void JS2Object::gc()
|
||||
{
|
||||
pond.resetMarks();
|
||||
for (std::vector<PondScum **>::iterator i = rootList.begin(), end = rootList.end(); (i != end); i++) {
|
||||
PondScum *p = **i;
|
||||
if (p) {
|
||||
ASSERT(p->owner && (p->size >= sizeof(PondScum)) && (p->owner->sanity == POND_SANITY));
|
||||
p->mark();
|
||||
}
|
||||
}
|
||||
pond.moveUnmarkedToFreeList();
|
||||
}
|
||||
|
||||
void *JS2Object::alloc(size_t s)
|
||||
{
|
||||
s += sizeof(PondScum);
|
||||
// make sure that the thing is 8-byte aligned
|
||||
if (s & 0x7) s += 8 - (s & 0x7);
|
||||
ASSERT(s <= 0x7FFFFFFF);
|
||||
return pond.allocFromPond((int32)s);
|
||||
}
|
||||
|
||||
return pond.allocFromPond(s);
|
||||
|
||||
void JS2Object::unalloc(void *t)
|
||||
{
|
||||
PondScum *p = (PondScum *)t - 1;
|
||||
ASSERT(p->owner && (p->size >= sizeof(PondScum)) && (p->owner->sanity == POND_SANITY));
|
||||
p->owner->returnToPond(p);
|
||||
}
|
||||
|
||||
}; // namespace MetaData
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace JavaScript {
|
|||
namespace MetaData {
|
||||
|
||||
|
||||
// forward definitions:
|
||||
// forward declarations:
|
||||
class JS2Object;
|
||||
class JS2Metadata;
|
||||
class JS2Class;
|
||||
|
@ -49,6 +49,8 @@ class Environment;
|
|||
class Context;
|
||||
class CompoundAttribute;
|
||||
class BytecodeContainer;
|
||||
class Pond;
|
||||
|
||||
|
||||
typedef void (Invokable)();
|
||||
typedef Invokable Callor;
|
||||
|
@ -68,17 +70,37 @@ enum ObjectKind {
|
|||
MultinameKind
|
||||
};
|
||||
|
||||
#define POND_SIZE (8000)
|
||||
class PondScum {
|
||||
public:
|
||||
void resetMark() { size &= 0x7FFFFFFF; }
|
||||
void mark() { size = -size; }
|
||||
bool isMarked() { return (size < 0); }
|
||||
|
||||
Pond *owner;
|
||||
int32 size;
|
||||
};
|
||||
|
||||
// A pond is a place to get chunks of PondScum from and to return them to
|
||||
#define POND_SIZE (8000)
|
||||
#define POND_SANITY (0xFADE2BAD)
|
||||
class Pond {
|
||||
public:
|
||||
Pond(size_t sz, Pond *nextPond);
|
||||
|
||||
void *allocFromPond(size_t t);
|
||||
void *allocFromPond(int32 sz);
|
||||
void returnToPond(PondScum *p);
|
||||
|
||||
void resetMarks();
|
||||
void moveUnmarkedToFreeList();
|
||||
|
||||
uint32 sanity;
|
||||
|
||||
size_t pondSize;
|
||||
uint8 *pondBase;
|
||||
uint8 *pondTop;
|
||||
|
||||
PondScum *freeHeader;
|
||||
|
||||
Pond *nextPond;
|
||||
};
|
||||
|
||||
|
@ -92,8 +114,16 @@ public:
|
|||
|
||||
ObjectKind kind;
|
||||
|
||||
static Pond pond;
|
||||
void *operator new(size_t s);
|
||||
static Pond pond;
|
||||
static std::vector<PondScum **> rootList;
|
||||
static void gc();
|
||||
static void addRoot(void *t); // pass the address of any JS2Object pointer
|
||||
|
||||
static void *alloc(size_t s);
|
||||
static void unalloc(void *p);
|
||||
|
||||
void *operator new(size_t s) { return alloc(s); }
|
||||
void operator delete(void *p) { unalloc(p); }
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -255,17 +285,18 @@ public:
|
|||
typedef std::map<String, js2val> DynamicPropertyMap;
|
||||
typedef DynamicPropertyMap::iterator DynamicPropertyIterator;
|
||||
|
||||
|
||||
// A STATICBINDING describes the member to which one qualified name is bound in a frame. Multiple
|
||||
// qualified names may be bound to the same member in a frame, but a qualified name may not be
|
||||
// bound to multiple members in a frame (except when one binding is for reading only and
|
||||
// the other binding is for writing only).
|
||||
class StaticBinding {
|
||||
public:
|
||||
StaticBinding(QualifiedName &qname, StaticMember *content) : qname(qname), content(content), xplicit(false) { }
|
||||
StaticBinding(QualifiedName &qname, StaticMember *content) : qname(qname), xplicit(false), content(content) { }
|
||||
|
||||
QualifiedName qname; // The qualified name bound by this binding
|
||||
StaticMember *content; // The member to which this qualified name was bound
|
||||
bool xplicit; // true if this binding should not be imported into the global scope by an import statement
|
||||
StaticMember *content; // The member to which this qualified name was bound
|
||||
};
|
||||
|
||||
|
||||
|
@ -435,9 +466,9 @@ public:
|
|||
bool strict; // The strict setting from the context in effect at the point where the reference was created
|
||||
|
||||
|
||||
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); bCon->emitOp(eLexicalRead); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); bCon->emitOp(eLexicalWrite); }
|
||||
void emitBindBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); }
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalRead); }
|
||||
virtual void emitWriteBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalWrite); }
|
||||
};
|
||||
|
||||
class DotReference : public Reference {
|
||||
|
@ -643,6 +674,8 @@ public:
|
|||
// The one and only 'public' namespace
|
||||
Namespace *publicNamespace;
|
||||
|
||||
StaticMember *forbiddenMember; // just need one of these hanging around
|
||||
|
||||
// The base classes:
|
||||
JS2Class *undefinedClass;
|
||||
JS2Class *nullClass;
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
// Get a multiname literal and add the currently open namespaces from the context
|
||||
// Push the resulting multiname object
|
||||
case eMultiname: {
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
|
@ -39,6 +41,8 @@
|
|||
}
|
||||
break;
|
||||
|
||||
// Get a multiname literal and pop a namespace value to add to it
|
||||
// Push the resulting multiname object
|
||||
case eQMultiname: {
|
||||
js2val nsVal = pop();
|
||||
if (!JS2VAL_IS_OBJECT(nsVal))
|
||||
|
@ -53,23 +57,38 @@
|
|||
}
|
||||
break;
|
||||
|
||||
// Pop a multiname object and read it's value from the environment on to the stack.
|
||||
case eLexicalRead: {
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
push(meta->env.lexicalRead(meta, mn, phase));
|
||||
retval = meta->env.lexicalRead(meta, mn, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
// Pop a value and a multiname. Write the value to the multiname in the environment, leave
|
||||
// the value on the stack top.
|
||||
case eLexicalWrite: {
|
||||
retval = pop();
|
||||
js2val mnVal = pop();
|
||||
ASSERT(JS2VAL_IS_OBJECT(mnVal));
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(mnVal);
|
||||
Multiname *mn = checked_cast<Multiname *>(obj);
|
||||
retval = pop();
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
push(retval);
|
||||
}
|
||||
break;
|
||||
|
||||
// Pop a namespace object and add it to the list of currently open namespaces in the context
|
||||
case eUse: {
|
||||
js2val nsVal = pop();
|
||||
if (!JS2VAL_IS_OBJECT(nsVal))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos);
|
||||
JS2Object *obj = JS2VAL_TO_OBJECT(nsVal);
|
||||
if ((obj->kind != AttributeObjectKind) || ((checked_cast<Attribute *>(obj))->attrKind != Attribute::NamespaceAttr))
|
||||
meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos);
|
||||
|
||||
}
|
||||
break;
|
Загрузка…
Ссылка в новой задаче