Ongoing namespace implementation + first gc.

This commit is contained in:
rogerl%netscape.com 2002-08-28 00:45:55 +00:00
Родитель e6d2aefa12
Коммит 91f00d84f6
5 изменённых файлов: 223 добавлений и 43 удалений

Просмотреть файл

@ -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;