Changed qualifier evaluation to compile time. Added error handling via

pc map.
This commit is contained in:
rogerl%netscape.com 2002-08-28 17:43:44 +00:00
Родитель 090a86af92
Коммит dde58a082b
7 изменённых файлов: 87 добавлений и 72 удалений

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

@ -64,11 +64,17 @@ namespace MetaData {
BytecodeContainer::~BytecodeContainer()
{
delete mBuffer;
for (std::vector<Multiname *>::iterator i = mMultinameList.begin(), end = mMultinameList.end(); (i != end); i++)
delete *i;
}
size_t BytecodeContainer::getPosition(uint16 pc)
{
for (std::vector<MapEntry>::iterator i = pcMap.begin(), end = pcMap.end(); (i != end); i++)
if (i->first >= pc)
return i->second;
return 0;
}
}
}

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

@ -52,45 +52,50 @@ class Multiname;
class BytecodeContainer {
public:
BytecodeContainer() : mBuffer(new CodeBuffer), mStackTop(0), mStackMax(0) { }
BytecodeContainer() : mStackTop(0), mStackMax(0) { }
BytecodeContainer::~BytecodeContainer() ;
uint8 *getCodeStart() { return mBuffer->begin(); }
uint8 *getCodeStart() { return mBuffer.begin(); }
typedef std::pair<uint16, size_t> MapEntry;
std::vector<MapEntry> pcMap;
void emitOp(JS2Op op) { adjustStack(op); addByte((uint8)op); }
void emitOp(JS2Op op, int32 effect) { adjustStack(op, effect); addByte((uint8)op); }
size_t getPosition(uint16 pc);
void emitOp(JS2Op op, size_t pos) { adjustStack(op); addByte((uint8)op); pcMap.push_back(MapEntry(mBuffer.size(), pos)); }
void emitOp(JS2Op op, size_t pos, int32 effect)
{ adjustStack(op, effect); addByte((uint8)op); pcMap.push_back(std::pair<uint16, size_t>(mBuffer.size(), pos)); }
void adjustStack(JS2Op op) { adjustStack(op, JS2Engine::getStackEffect(op)); }
void adjustStack(JS2Op op, int32 effect){ mStackTop += effect; if (mStackTop > mStackMax) mStackMax = mStackTop; ASSERT(mStackTop >= 0); }
void addByte(uint8 v) { mBuffer->push_back(v); }
void addByte(uint8 v) { mBuffer.push_back(v); }
void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); }
static void *getPointer(void *pc) { return (void *)getLong(pc); }
void addFloat64(float64 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
void addFloat64(float64 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); }
static float64 getFloat64(void *pc) { return *((float64 *)pc); }
void addLong(const uint32 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
void addLong(const uint32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
static uint32 getLong(void *pc) { return *((uint32 *)pc); }
void addShort(uint16 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); }
void addShort(uint16 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); }
static uint16 getShort(void *pc) { return *((uint16 *)pc); }
void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addShort(mMultinameList.size() - 1); }
static Multiname *getMultiname(void *pc){ return (Multiname *)getLong(pc); }
void addString(const StringAtom &x) { emitOp(eString); addPointer(&x); }
void addString(String &x) { emitOp(eString); addPointer(&x); }
void addString(String *x) { emitOp(eString); addPointer(x); }
void addString(const StringAtom &x, size_t pos) { emitOp(eString, pos); addPointer(&x); }
void addString(String &x, size_t pos) { emitOp(eString, pos); addPointer(&x); }
void addString(String *x, size_t pos) { emitOp(eString, pos); addPointer(x); }
static String *getString(void *pc) { return (String *)getPointer(pc); }
// XXX We lose StringAtom here - is there anyway of stashing these in a bytecodecontainer?
typedef std::vector<uint8> CodeBuffer;
CodeBuffer *mBuffer;
CodeBuffer mBuffer;
std::vector<Multiname *> mMultinameList; // gc tracking
int32 mStackTop; // keep these as signed so as to

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

@ -240,7 +240,6 @@ int JS2Engine::getStackEffect(JS2Op op)
return 0;
case eMultiname:
case eQMultiname:
return 1; // push the multiname object
case eUse:
@ -252,5 +251,10 @@ int JS2Engine::getStackEffect(JS2Op op)
return 0;
}
size_t JS2Engine::errorPos()
{
return bCon->getPosition(pc - bCon->getCodeStart());
}
}
}

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

@ -61,7 +61,6 @@ enum JS2Op {
eReturnVoid,
eNewObject, // <argCount:16>
eMultiname, // <multiname index>
eQMultiname, // <multiname index>
eUse,
};
@ -81,6 +80,8 @@ public:
void *gc_alloc_8();
float64 *newDoubleValue(float64 x);
size_t errorPos();
void pushNumber(float64 x);
#define MAX_EXEC_STACK (20)

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

@ -191,11 +191,13 @@ namespace MetaData {
{
BytecodeContainer *saveBacon = bCon;
bCon = new BytecodeContainer();
size_t lastPos = p->pos;
while (p) {
EvalStmt(&env, phase, p);
lastPos = p->pos;
p = p->next;
}
bCon->emitOp(eReturnVoid);
bCon->emitOp(eReturnVoid, lastPos);
js2val retval = engine->interpret(this, phase, bCon);
bCon = saveBacon;
return retval;
@ -242,7 +244,7 @@ namespace MetaData {
{
ExprStmtNode *e = checked_cast<ExprStmtNode *>(p);
Reference *r = EvalExprNode(env, phase, e->expr);
if (r) r->emitReadBytecode(bCon);
if (r) r->emitReadBytecode(bCon, p->pos);
}
break;
case StmtNode::Namespace:
@ -255,8 +257,8 @@ namespace MetaData {
ExprList *eList = u->namespaces;
while (eList) {
Reference *r = EvalExprNode(env, phase, eList->expr);
if (r) r->emitReadBytecode(bCon);
bCon->emitOp(eUse);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eUse, p->pos);
eList = eList->next;
}
}
@ -549,8 +551,8 @@ namespace MetaData {
BytecodeContainer *saveBacon = bCon;
bCon = new BytecodeContainer();
Reference *r = EvalExprNode(env, phase, p);
if (r) r->emitReadBytecode(bCon);
bCon->emitOp(eReturn);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eReturn, p->pos);
js2val retval = engine->interpret(this, phase, bCon);
bCon = saveBacon;
return retval;
@ -572,8 +574,8 @@ namespace MetaData {
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) {
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon);
lVal->emitWriteBytecode(bCon);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
lVal->emitWriteBytecode(bCon, p->pos);
}
else
reportError(Exception::semanticError, "Assignment needs an lValue", p->pos);
@ -584,9 +586,9 @@ namespace MetaData {
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
Reference *lVal = EvalExprNode(env, phase, b->op1);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (lVal) lVal->emitReadBytecode(bCon);
if (rVal) rVal->emitReadBytecode(bCon);
bCon->emitOp(ePlus);
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(ePlus, p->pos);
}
break;
@ -601,7 +603,7 @@ namespace MetaData {
case ExprNode::number:
{
bCon->emitOp(eNumber);
bCon->emitOp(eNumber, p->pos);
bCon->addFloat64(checked_cast<NumberExprNode *>(p)->value);
}
break;
@ -609,24 +611,31 @@ namespace MetaData {
{
QualifyExprNode *qe = checked_cast<QualifyExprNode *>(p);
const StringAtom &name = checked_cast<IdentifierExprNode *>(p)->name;
Reference *rVal = EvalExprNode(env, phase, qe->qualifier);
if (rVal) rVal->emitReadBytecode(bCon);
returnRef = new LexicalReference(name, cxt.strict, true);
((LexicalReference *)returnRef)->emitBindBytecode(bCon);
js2val av = EvalExpression(env, CompilePhase, qe->qualifier);
if (JS2VAL_IS_NULL(av) || !JS2VAL_IS_OBJECT(av))
reportError(Exception::badValueError, "Namespace expected in qualifier", 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 qualifier", p->pos);
Namespace *ns = checked_cast<Namespace *>(obj);
returnRef = new LexicalReference(name, ns, cxt.strict);
((LexicalReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
break;
case ExprNode::identifier:
{
IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
returnRef = new LexicalReference(i->name, cxt.strict);
((LexicalReference *)returnRef)->emitBindBytecode(bCon);
((LexicalReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
break;
case ExprNode::boolean:
if (checked_cast<BooleanExprNode *>(p)->value)
bCon->emitOp(eTrue);
bCon->emitOp(eTrue, p->pos);
else
bCon->emitOp(eFalse);
bCon->emitOp(eFalse, p->pos);
break;
case ExprNode::objectLiteral:
{
@ -636,16 +645,16 @@ namespace MetaData {
while (e) {
ASSERT(e->field && e->value);
Reference *rVal = EvalExprNode(env, phase, e->value);
if (rVal) rVal->emitReadBytecode(bCon);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
switch (e->field->getKind()) {
case ExprNode::identifier:
bCon->addString(checked_cast<IdentifierExprNode *>(e->field)->name);
bCon->addString(checked_cast<IdentifierExprNode *>(e->field)->name, p->pos);
break;
case ExprNode::string:
bCon->addString(checked_cast<StringExprNode *>(e->field)->str);
bCon->addString(checked_cast<StringExprNode *>(e->field)->str, p->pos);
break;
case ExprNode::number:
bCon->addString(numberToString(&(checked_cast<NumberExprNode *>(e->field))->value));
bCon->addString(numberToString(&(checked_cast<NumberExprNode *>(e->field))->value), p->pos);
break;
default:
NOT_REACHED("bad field name");
@ -742,14 +751,12 @@ namespace MetaData {
Frame *pf = firstFrame;
while (pf) {
js2val rval;
// have to wrap the frame in a Monkey object in order
// to have readProperty handle it...
if (meta->readProperty(pf, multiname, &lookup, phase, &rval))
return rval;
pf = pf->nextFrame;
}
meta->reportError(Exception::referenceError, "{0} is undefined", meta->errorPos, multiname->name);
meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name);
return JS2VAL_VOID;
}
@ -758,8 +765,6 @@ namespace MetaData {
LookupKind lookup(true, findThis(false));
Frame *pf = firstFrame;
while (pf) {
// have to wrap the frame in a Monkey object in order
// to have readProperty handle it...
if (meta->writeProperty(pf, multiname, &lookup, false, newValue, phase))
return;
pf = pf->nextFrame;
@ -771,7 +776,7 @@ namespace MetaData {
return;
}
}
meta->reportError(Exception::referenceError, "{0} is undefined", meta->errorPos, multiname->name);
meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name);
}
@ -842,10 +847,9 @@ namespace MetaData {
publicNamespaceList.push_back(publicNamespace);
namespaces = &publicNamespaceList;
}
Multiname *mn = new Multiname(id, true);
Multiname *mn = new Multiname(id);
mn->addNamespace(namespaces);
for (StaticBindingIterator b = localFrame->staticReadBindings.lower_bound(id),
end = localFrame->staticReadBindings.upper_bound(id); (b != end); b++) {
if (mn->matches(b->second->qname))
@ -1003,7 +1007,8 @@ namespace MetaData {
if (!multiname->onList(publicNamespace))
return false;
const StringAtom &name = multiname->name;
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", errorPos);
if (phase == CompilePhase)
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
DynamicPropertyMap *dMap = NULL;
bool isPrototypeInstance = false;
if (container->kind == DynamicInstanceKind)
@ -1093,7 +1098,7 @@ namespace MetaData {
return false; // 'None'
switch (m->kind) {
case StaticMember::Forbidden:
reportError(Exception::propertyAccessError, "Forbidden access", errorPos);
reportError(Exception::propertyAccessError, "Forbidden access", engine->errorPos());
break;
case StaticMember::Variable:
*rval = (checked_cast<Variable *>(m))->value;
@ -1117,7 +1122,7 @@ namespace MetaData {
switch (m->kind) {
case StaticMember::Forbidden:
case StaticMember::ConstructorMethod:
reportError(Exception::propertyAccessError, "Forbidden access", errorPos);
reportError(Exception::propertyAccessError, "Forbidden access", engine->errorPos());
break;
case StaticMember::Variable:
(checked_cast<Variable *>(m))->value = newValue;
@ -1187,7 +1192,7 @@ namespace MetaData {
}
if (multiname->matches(b->second->qname)) {
if (found && (b->second->content != found))
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name);
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", engine->errorPos(), multiname->name);
else
found = b->second->content;
}
@ -1229,7 +1234,7 @@ namespace MetaData {
}
if (multiname->matches(b->second->qname)) {
if (result && (b->second->content != result->content))
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name);
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", engine->errorPos(), multiname->name);
else
result = b->second;
}

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

@ -145,9 +145,7 @@ public:
virtual CompoundAttribute *toCompoundAttribute() { ASSERT(false); return NULL; }
AttributeKind attrKind;
};
// A Namespace (is also an attribute)
@ -179,12 +177,10 @@ typedef std::vector<Namespace *> NamespaceList;
typedef NamespaceList::iterator NamespaceListIterator;
class Multiname : public JS2Object {
public:
Multiname(const StringAtom &name) : JS2Object(MultinameKind), name(name) { }
Multiname(const StringAtom &name, Namespace *ns) : JS2Object(MultinameKind), name(name) { addNamespace(ns); }
Multiname(const StringAtom &name) : JS2Object(MultinameKind), name(name), qualified(false) { }
Multiname(const StringAtom &name, bool qualified) : JS2Object(MultinameKind), name(name), qualified(qualified) { }
void emitBytecode(BytecodeContainer *bCon) { bCon->emitOp(qualified ? eQMultiname : eMultiname); bCon->addMultiname(this); }
void emitBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eMultiname, pos); bCon->addMultiname(this); }
void addNamespace(Namespace *ns) { nsList.push_back(ns); }
void addNamespace(NamespaceList *ns);
@ -195,7 +191,6 @@ public:
NamespaceList nsList;
const StringAtom &name;
bool qualified; // true for q::a, otherwise false
};
@ -446,10 +441,10 @@ public:
// References are generated during the eval stage (bytecode generation)
class Reference {
public:
virtual void emitReadBytecode(BytecodeContainer *bCon) { ASSERT(false); }
virtual void emitWriteBytecode(BytecodeContainer *bCon) { ASSERT(false); }
virtual void emitDeleteBytecode(BytecodeContainer *bCon) { ASSERT(false); };
virtual void emitReadForInvokeBytecode(BytecodeContainer *bCon) { ASSERT(false); }
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
virtual void emitDeleteBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); };
virtual void emitReadForInvokeBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
};
class LexicalReference : public Reference {
@ -458,7 +453,7 @@ class LexicalReference : public Reference {
// q::a.
public:
LexicalReference(const StringAtom &name, bool strict) : variableMultiname(new Multiname(name)), env(NULL), strict(strict) { }
LexicalReference(const StringAtom &name, bool strict, bool qualified) : variableMultiname(new Multiname(name, qualified)), env(NULL), strict(strict) { }
LexicalReference(const StringAtom &name, Namespace *nameSpace, bool strict) : variableMultiname(new Multiname(name, nameSpace)), env(NULL), strict(strict) { }
Multiname *variableMultiname; // A nonempty set of qualified names to which this reference can refer
@ -466,9 +461,9 @@ public:
bool strict; // The strict setting from the context in effect at the point where the reference was created
void emitBindBytecode(BytecodeContainer *bCon) { variableMultiname->emitBytecode(bCon); }
virtual void emitReadBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalRead); }
virtual void emitWriteBytecode(BytecodeContainer *bCon) { bCon->emitOp(eLexicalWrite); }
void emitBindBytecode(BytecodeContainer *bCon, size_t pos) { variableMultiname->emitBytecode(bCon, pos); }
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalRead, pos); }
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalWrite, pos); }
};
class DotReference : public Reference {
@ -687,7 +682,6 @@ public:
JS2Class *namespaceClass;
Parser *mParser; // used for error reporting
size_t errorPos;
BytecodeContainer *bCon; // the current output container

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

@ -40,7 +40,7 @@
push(OBJECT_TO_JS2VAL(mn));
}
break;
#if 0
// Get a multiname literal and pop a namespace value to add to it
// Push the resulting multiname object
case eQMultiname: {
@ -56,7 +56,7 @@
push(OBJECT_TO_JS2VAL(mn));
}
break;
#endif
// Pop a multiname object and read it's value from the environment on to the stack.
case eLexicalRead: {
js2val mnVal = pop();
@ -85,10 +85,10 @@
case eUse: {
js2val nsVal = pop();
if (!JS2VAL_IS_OBJECT(nsVal))
meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos);
meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->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);
meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->errorPos());
}
break;