зеркало из https://github.com/mozilla/gecko-dev.git
Disneyland progress.
This commit is contained in:
Родитель
7ef02807ad
Коммит
36ebbbe9b2
|
@ -32,6 +32,14 @@
|
|||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
// Turn off warnings about identifiers too long in browser information
|
||||
#pragma warning(disable: 4786)
|
||||
#pragma warning(disable: 4711)
|
||||
#pragma warning(disable: 4710)
|
||||
#endif
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <assert.h>
|
||||
|
||||
|
|
|
@ -60,20 +60,33 @@ public:
|
|||
|
||||
|
||||
void emitOp(JS2Op op) { adjustStack(op); addByte((uint8)op); }
|
||||
void adjustStack(JS2Op op) { mStackTop += JS2Engine::getStackEffect(op); if (mStackTop > mStackMax) mStackMax = mStackTop; ASSERT(mStackTop >= 0); }
|
||||
void emitOp(JS2Op op, int32 effect) { adjustStack(op, effect); addByte((uint8)op); }
|
||||
|
||||
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 addPointer(void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(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)); }
|
||||
static float64 getFloat64(void *pc) { return *((float64 *)pc); }
|
||||
|
||||
void addLong(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 addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addPointer(mn); }
|
||||
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); }
|
||||
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;
|
||||
|
||||
|
|
|
@ -61,9 +61,10 @@
|
|||
namespace JavaScript {
|
||||
namespace MetaData {
|
||||
|
||||
js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, uint8 *start)
|
||||
js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon)
|
||||
{
|
||||
pc = start;
|
||||
bCon = targetbCon;
|
||||
pc = bCon->getCodeStart();
|
||||
meta = metadata;
|
||||
phase = execPhase;
|
||||
return interpreterLoop();
|
||||
|
@ -171,6 +172,9 @@ js2val JS2Engine::convertValueToPrimitive(js2val x)
|
|||
// return [[DefaultValue]] --> get property 'toString' and invoke it,
|
||||
// if not available or result is not primitive then try property 'valueOf'
|
||||
// if that's not available or returns a non primitive, throw a TypeError
|
||||
|
||||
return STRING_TO_JS2VAL(&object_StringAtom);
|
||||
|
||||
ASSERT(false);
|
||||
return JS2VAL_VOID;
|
||||
}
|
||||
|
@ -196,11 +200,13 @@ float64 JS2Engine::convertValueToDouble(js2val x)
|
|||
#define INIT_STRINGATOM(n) n##_StringAtom(world.identifiers[#n])
|
||||
|
||||
JS2Engine::JS2Engine(World &world)
|
||||
: INIT_STRINGATOM(true),
|
||||
: world(world),
|
||||
INIT_STRINGATOM(true),
|
||||
INIT_STRINGATOM(false),
|
||||
INIT_STRINGATOM(null),
|
||||
INIT_STRINGATOM(undefined),
|
||||
INIT_STRINGATOM(public)
|
||||
INIT_STRINGATOM(public),
|
||||
INIT_STRINGATOM(object)
|
||||
{
|
||||
nanValue = (float64 *)gc_alloc_8();
|
||||
*nanValue = nan;
|
||||
|
@ -218,6 +224,7 @@ int JS2Engine::getStackEffect(JS2Op op)
|
|||
case eReturn:
|
||||
case ePlus:
|
||||
return -1;
|
||||
case eString:
|
||||
case eTrue:
|
||||
case eFalse:
|
||||
case eNumber:
|
||||
|
|
|
@ -53,22 +53,25 @@ enum JS2Op {
|
|||
eTrue,
|
||||
eFalse,
|
||||
eNumber,
|
||||
eString, // <string pointer>
|
||||
eObject, // <named argument count>
|
||||
eLexicalRead, // <multiname index>
|
||||
eLexicalWrite, // <multiname index>
|
||||
eReturn,
|
||||
eReturnVoid
|
||||
eReturnVoid,
|
||||
eNewObject // <argCount:16>
|
||||
};
|
||||
|
||||
|
||||
class JS2Metadata;
|
||||
|
||||
class BytecodeContainer;
|
||||
|
||||
class JS2Engine {
|
||||
public:
|
||||
|
||||
JS2Engine(World &world);
|
||||
|
||||
js2val interpret(JS2Metadata *metadata, Phase execPhase, uint8 *start);
|
||||
js2val interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon);
|
||||
|
||||
js2val interpreterLoop();
|
||||
|
||||
|
@ -91,8 +94,10 @@ public:
|
|||
float64 toNumber(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else if (JS2VAL_IS_DOUBLE(x)) return *JS2VAL_TO_DOUBLE(x); else return convertValueToDouble(x); }
|
||||
|
||||
uint8 *pc;
|
||||
BytecodeContainer *bCon;
|
||||
JS2Metadata *meta;
|
||||
Phase phase;
|
||||
World &world;
|
||||
|
||||
float64 *nanValue;
|
||||
float64 *float64Table[256];
|
||||
|
@ -102,6 +107,7 @@ public:
|
|||
StringAtom &null_StringAtom;
|
||||
StringAtom &undefined_StringAtom;
|
||||
StringAtom &public_StringAtom;
|
||||
StringAtom &object_StringAtom;
|
||||
|
||||
js2val *execStack;
|
||||
js2val *sp;
|
||||
|
@ -113,6 +119,7 @@ public:
|
|||
};
|
||||
|
||||
|
||||
String *numberToString(float64 *number);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ namespace MetaData {
|
|||
while (v) {
|
||||
ValidateTypeExpression(v->type);
|
||||
|
||||
if (cxt->strict && ((regionalFrame->kind == Frame::GlobalObject)
|
||||
|| (regionalFrame->kind == Frame::Function))
|
||||
if (cxt->strict && ((regionalFrame->kind == GlobalObjectKind)
|
||||
|| (regionalFrame->kind == FunctionKind))
|
||||
&& (p->getKind() == StmtNode::Var) // !immutable
|
||||
&& (vs->attributes == NULL)
|
||||
&& (v->type == NULL)) {
|
||||
|
@ -132,7 +132,7 @@ namespace MetaData {
|
|||
if (a->dynamic || a->prototype)
|
||||
reportError(Exception::definitionError, "Illegal attribute", p->pos);
|
||||
Attribute::MemberModifier memberMod = a->memberMod;
|
||||
if ((env->getTopFrame()->kind == Frame::Class)
|
||||
if ((env->getTopFrame()->kind == ClassKind)
|
||||
&& (memberMod == Attribute::NoModifier))
|
||||
memberMod = Attribute::Final;
|
||||
switch (memberMod) {
|
||||
|
@ -168,7 +168,7 @@ namespace MetaData {
|
|||
p = p->next;
|
||||
}
|
||||
bCon->emitOp(eReturnVoid);
|
||||
return engine->interpret(this, phase, bCon->getCodeStart());
|
||||
return engine->interpret(this, phase, bCon);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -458,6 +458,16 @@ namespace MetaData {
|
|||
void JS2Metadata::ValidateExpression(Context *cxt, Environment *env, ExprNode *p)
|
||||
{
|
||||
switch (p->getKind()) {
|
||||
case ExprNode::number:
|
||||
case ExprNode::boolean:
|
||||
break;
|
||||
case ExprNode::objectLiteral:
|
||||
break;
|
||||
case ExprNode::dot:
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::assignment:
|
||||
case ExprNode::add:
|
||||
{
|
||||
|
@ -471,6 +481,8 @@ namespace MetaData {
|
|||
// IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
} // switch (p->getKind())
|
||||
}
|
||||
|
||||
|
@ -483,7 +495,7 @@ namespace MetaData {
|
|||
{
|
||||
EvalExprNode(env, phase, p);
|
||||
bCon->emitOp(eReturnVoid);
|
||||
return engine->interpret(this, phase, bCon->getCodeStart());
|
||||
return engine->interpret(this, phase, bCon);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -494,10 +506,6 @@ namespace MetaData {
|
|||
Reference *returnRef = NULL;
|
||||
|
||||
switch (p->getKind()) {
|
||||
case ExprNode::index:
|
||||
{
|
||||
}
|
||||
break;
|
||||
|
||||
case ExprNode::assignment:
|
||||
{
|
||||
|
@ -542,7 +550,7 @@ namespace MetaData {
|
|||
case ExprNode::identifier:
|
||||
{
|
||||
IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
|
||||
returnRef = new LexicalReference(new Multiname(i->name, cxt), env, cxt.strict);
|
||||
returnRef = new LexicalReference(i->name, cxt.strict);
|
||||
}
|
||||
break;
|
||||
case ExprNode::boolean:
|
||||
|
@ -552,6 +560,38 @@ namespace MetaData {
|
|||
bCon->emitOp(eFalse);
|
||||
break;
|
||||
case ExprNode::objectLiteral:
|
||||
{
|
||||
uint32 argCount = 0;
|
||||
PairListExprNode *plen = checked_cast<PairListExprNode *>(p);
|
||||
ExprPairList *e = plen->pairs;
|
||||
while (e) {
|
||||
ASSERT(e->field && e->value);
|
||||
Reference *rVal = EvalExprNode(env, phase, e->value);
|
||||
if (rVal) rVal->emitReadBytecode(bCon);
|
||||
switch (e->field->getKind()) {
|
||||
case ExprNode::identifier:
|
||||
bCon->addString(checked_cast<IdentifierExprNode *>(e->field)->name);
|
||||
break;
|
||||
case ExprNode::string:
|
||||
bCon->addString(checked_cast<StringExprNode *>(e->field)->str);
|
||||
break;
|
||||
case ExprNode::number:
|
||||
bCon->addString(numberToString(&(checked_cast<NumberExprNode *>(e->field))->value));
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad field name");
|
||||
}
|
||||
argCount++;
|
||||
e = e->next;
|
||||
}
|
||||
bCon->emitOp(eNewObject, -argCount + 1);
|
||||
bCon->addShort(argCount);
|
||||
}
|
||||
break;
|
||||
case ExprNode::dot:
|
||||
{
|
||||
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("Not Yet Implemented");
|
||||
|
@ -574,7 +614,7 @@ namespace MetaData {
|
|||
JS2Class *Environment::getEnclosingClass()
|
||||
{
|
||||
Frame *pf = firstFrame;
|
||||
while (pf && (pf->kind != Frame::Class))
|
||||
while (pf && (pf->kind != ClassKind))
|
||||
pf = pf->nextFrame;
|
||||
return checked_cast<JS2Class *>(pf);
|
||||
}
|
||||
|
@ -584,11 +624,11 @@ namespace MetaData {
|
|||
{
|
||||
Frame *pf = firstFrame;
|
||||
Frame *prev = NULL;
|
||||
while (pf->kind == Frame::Block) {
|
||||
while (pf->kind == BlockKind) {
|
||||
prev = pf;
|
||||
pf = pf->nextFrame;
|
||||
}
|
||||
if (pf->nextFrame && (pf->kind == Frame::Class))
|
||||
if (pf->nextFrame && (pf->kind == ClassKind))
|
||||
pf = prev;
|
||||
return pf;
|
||||
}
|
||||
|
@ -610,7 +650,7 @@ namespace MetaData {
|
|||
{
|
||||
Frame *pf = firstFrame;
|
||||
while (pf) {
|
||||
if ((pf->kind == Frame::Function)
|
||||
if ((pf->kind == FunctionKind)
|
||||
&& !JS2VAL_IS_NULL(checked_cast<FunctionFrame *>(pf)->thisObject))
|
||||
if (allowPrototypeThis || !checked_cast<FunctionFrame *>(pf)->prototype)
|
||||
return checked_cast<FunctionFrame *>(pf)->thisObject;
|
||||
|
@ -651,7 +691,7 @@ namespace MetaData {
|
|||
}
|
||||
if (createIfMissing) {
|
||||
pf = getPackageOrGlobalFrame();
|
||||
if (pf->kind == Frame::GlobalObject) {
|
||||
if (pf->kind == GlobalObjectKind) {
|
||||
if (meta->writeProperty(pf, multiname, &lookup, true, newValue, phase))
|
||||
return;
|
||||
}
|
||||
|
@ -705,7 +745,7 @@ namespace MetaData {
|
|||
{
|
||||
QualifiedName qName(publicNamespace, id);
|
||||
Frame *regionalFrame = env->getRegionalFrame();
|
||||
ASSERT((env->getTopFrame()->kind == Frame::GlobalObject) || (env->getTopFrame()->kind == Frame::Function));
|
||||
ASSERT((env->getTopFrame()->kind == GlobalObjectKind) || (env->getTopFrame()->kind == FunctionKind));
|
||||
|
||||
// run through all the existing bindings, both read and write, to see if this
|
||||
// variable already exists.
|
||||
|
@ -734,7 +774,7 @@ namespace MetaData {
|
|||
}
|
||||
}
|
||||
if (!existing) {
|
||||
if (regionalFrame->kind == Frame::GlobalObject) {
|
||||
if (regionalFrame->kind == GlobalObjectKind) {
|
||||
GlobalObject *gObj = checked_cast<GlobalObject *>(regionalFrame);
|
||||
DynamicPropertyIterator dp = gObj->dynamicProperties.find(id);
|
||||
if (dp != gObj->dynamicProperties.end())
|
||||
|
@ -791,14 +831,98 @@ namespace MetaData {
|
|||
*/
|
||||
}
|
||||
|
||||
bool JS2Metadata::readDynamicProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
|
||||
// Read the property from the container given by the public id in multiname - if that exists
|
||||
//
|
||||
bool JS2Metadata::readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
|
||||
{
|
||||
return true;
|
||||
ASSERT(container && ((container->kind == DynamicInstanceKind)
|
||||
|| (container->kind == GlobalObjectKind)
|
||||
|| (container->kind == PrototypeInstanceKind)));
|
||||
if (!multiname->onList(publicNamespace))
|
||||
return false;
|
||||
const StringAtom &name = multiname->name;
|
||||
if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", errorPos);
|
||||
DynamicPropertyMap *dMap = NULL;
|
||||
bool isPrototypeInstance = false;
|
||||
if (container->kind == DynamicInstanceKind)
|
||||
dMap = &(checked_cast<DynamicInstance *>(container))->dynamicProperties;
|
||||
else
|
||||
if (container->kind == GlobalObjectKind)
|
||||
dMap = &(checked_cast<GlobalObject *>(container))->dynamicProperties;
|
||||
else {
|
||||
isPrototypeInstance = true;
|
||||
dMap = &(checked_cast<PrototypeInstance *>(container))->dynamicProperties;
|
||||
}
|
||||
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
|
||||
if (i->first == name) {
|
||||
*rval = i->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (isPrototypeInstance) {
|
||||
PrototypeInstance *pInst = (checked_cast<PrototypeInstance *>(container))->parent;
|
||||
while (pInst) {
|
||||
for (DynamicPropertyIterator i = pInst->dynamicProperties.begin(), end = pInst->dynamicProperties.end(); (i != end); i++) {
|
||||
if (i->first == name) {
|
||||
*rval = i->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
pInst = pInst->parent;
|
||||
}
|
||||
}
|
||||
if (lookupKind->isPropertyLookup()) {
|
||||
*rval = JS2VAL_UNDEFINED;
|
||||
return true;
|
||||
}
|
||||
return false; // 'None'
|
||||
}
|
||||
|
||||
bool JS2Metadata::writeDynamicProperty(Frame *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase)
|
||||
{
|
||||
return true;
|
||||
ASSERT(container && ((container->kind == DynamicInstanceKind)
|
||||
|| (container->kind == GlobalObjectKind)
|
||||
|| (container->kind == PrototypeInstanceKind)));
|
||||
if (!multiname->onList(publicNamespace))
|
||||
return false;
|
||||
const StringAtom &name = multiname->name;
|
||||
DynamicPropertyMap *dMap = NULL;
|
||||
if (container->kind == DynamicInstanceKind)
|
||||
dMap = &(checked_cast<DynamicInstance *>(container))->dynamicProperties;
|
||||
else
|
||||
if (container->kind == GlobalObjectKind)
|
||||
dMap = &(checked_cast<GlobalObject *>(container))->dynamicProperties;
|
||||
else
|
||||
dMap = &(checked_cast<PrototypeInstance *>(container))->dynamicProperties;
|
||||
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
|
||||
if (i->first == name) {
|
||||
i->second = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!createIfMissing)
|
||||
return false;
|
||||
if (container->kind == DynamicInstanceKind) {
|
||||
DynamicInstance *dynInst = checked_cast<DynamicInstance *>(container);
|
||||
InstanceBinding *ib = resolveInstanceMemberName(dynInst->type, multiname, ReadAccess, phase);
|
||||
if (ib == NULL) {
|
||||
const DynamicPropertyMap::value_type e(name, newValue);
|
||||
dynInst->dynamicProperties.insert(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (container->kind == GlobalObjectKind) {
|
||||
GlobalObject *glob = checked_cast<GlobalObject *>(container);
|
||||
StaticMember *m = findFlatMember(glob, multiname, ReadAccess, phase);
|
||||
if (m == NULL) {
|
||||
const DynamicPropertyMap::value_type e(name, newValue);
|
||||
glob->dynamicProperties.insert(e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // 'None'
|
||||
}
|
||||
|
||||
bool JS2Metadata::readStaticMember(StaticMember *m, Phase phase, js2val *rval)
|
||||
|
@ -856,7 +980,7 @@ namespace MetaData {
|
|||
bool JS2Metadata::readProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
|
||||
{
|
||||
StaticMember *m = findFlatMember(container, multiname, ReadAccess, phase);
|
||||
if (!m && (container->kind == Frame::GlobalObject))
|
||||
if (!m && (container->kind == GlobalObjectKind))
|
||||
return readDynamicProperty(container, multiname, lookupKind, phase, rval);
|
||||
else
|
||||
return readStaticMember(m, phase, rval);
|
||||
|
@ -867,7 +991,7 @@ namespace MetaData {
|
|||
bool JS2Metadata::writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase)
|
||||
{
|
||||
StaticMember *m = findFlatMember(container, multiname, WriteAccess, phase);
|
||||
if (!m && (container->kind == Frame::GlobalObject))
|
||||
if (!m && (container->kind == GlobalObjectKind))
|
||||
return writeDynamicProperty(container, multiname, createIfMissing, newValue, phase);
|
||||
else
|
||||
return writeStaticMember(m, newValue, phase);
|
||||
|
@ -898,7 +1022,7 @@ namespace MetaData {
|
|||
break;
|
||||
}
|
||||
if (multiname->matches(b->second->qname)) {
|
||||
if (found)
|
||||
if (found && (b->second->content != found))
|
||||
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name);
|
||||
else
|
||||
found = b->second->content;
|
||||
|
@ -908,6 +1032,48 @@ namespace MetaData {
|
|||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start from the root class (Object) and proceed through more specific classes that are ancestors of c.
|
||||
* Find the binding that matches the given access and multiname, it's an error if more than one such exists.
|
||||
*
|
||||
*/
|
||||
InstanceBinding *JS2Metadata::resolveInstanceMemberName(JS2Class *c, Multiname *multiname, Access access, Phase phase)
|
||||
{
|
||||
InstanceBinding *result = NULL;
|
||||
if (c->super) {
|
||||
result = resolveInstanceMemberName(c->super, multiname, access, phase);
|
||||
if (result) return result;
|
||||
}
|
||||
InstanceBindingIterator b, end;
|
||||
if ((access == ReadAccess) || (access == ReadWriteAccess)) {
|
||||
b = c->instanceReadBindings.lower_bound(multiname->name);
|
||||
end = c->instanceReadBindings.upper_bound(multiname->name);
|
||||
}
|
||||
else {
|
||||
b = c->instanceWriteBindings.lower_bound(multiname->name);
|
||||
end = c->instanceWriteBindings.upper_bound(multiname->name);
|
||||
}
|
||||
while (true) {
|
||||
if (b == end) {
|
||||
if (access == ReadWriteAccess) {
|
||||
access = WriteAccess;
|
||||
b = c->instanceWriteBindings.lower_bound(multiname->name);
|
||||
end = c->instanceWriteBindings.upper_bound(multiname->name);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (multiname->matches(b->second->qname)) {
|
||||
if (result && (b->second->content != result->content))
|
||||
reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name);
|
||||
else
|
||||
result = b->second;
|
||||
}
|
||||
b++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Throw an exception of the specified kind, indicating the position 'pos' and
|
||||
* attaching the given message. If 'arg' is specified, replace {0} in the message
|
||||
|
|
|
@ -54,14 +54,35 @@ typedef void (Invokable)();
|
|||
typedef Invokable Callor;
|
||||
typedef JS2Object *(Constructor)();
|
||||
|
||||
|
||||
enum ObjectKind {
|
||||
AttributeObjectKind,
|
||||
SystemKind,
|
||||
GlobalObjectKind,
|
||||
PackageKind,
|
||||
FunctionKind,
|
||||
ClassKind,
|
||||
BlockKind,
|
||||
PrototypeInstanceKind,
|
||||
FixedInstanceKind,
|
||||
DynamicInstanceKind };
|
||||
|
||||
class JS2Object {
|
||||
// Every object is either undefined, null, a Boolean,
|
||||
// a number, a string, a namespace, a compound attribute, a class, a method closure,
|
||||
// a prototype instance, a class instance, a package object, or the global object.
|
||||
public:
|
||||
|
||||
JS2Object(ObjectKind kind) : kind(kind) { }
|
||||
|
||||
ObjectKind kind;
|
||||
|
||||
|
||||
void *operator new(size_t s);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function
|
||||
#endif
|
||||
};
|
||||
|
||||
class Attribute : public JS2Object {
|
||||
|
@ -71,7 +92,7 @@ public:
|
|||
enum OverrideModifier { NoOverride, DoOverride, DontOverride, OverrideUndefined };
|
||||
|
||||
|
||||
Attribute(AttributeKind kind) : kind(kind) { }
|
||||
Attribute(AttributeKind kind) : JS2Object(AttributeObjectKind), kind(kind) { }
|
||||
|
||||
static Attribute *combineAttributes(Attribute *a, Attribute *b);
|
||||
static CompoundAttribute *toCompoundAttribute(Attribute *a);
|
||||
|
@ -102,7 +123,9 @@ public:
|
|||
};
|
||||
|
||||
// MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup.
|
||||
// We keep Multinames as a basename and a list of namespace qualifiers
|
||||
// We keep Multinames as a basename and a list of namespace qualifiers (XXX is that right - would the basename
|
||||
// ever be different for the same multiname?)
|
||||
// Pointers to Multiname instances get embedded in the bytecode.
|
||||
typedef std::vector<Namespace *> NamespaceList;
|
||||
typedef NamespaceList::iterator NamespaceListIterator;
|
||||
class Multiname {
|
||||
|
@ -257,33 +280,28 @@ public:
|
|||
typedef std::multimap<String, StaticBinding *> StaticBindingMap;
|
||||
typedef StaticBindingMap::iterator StaticBindingIterator;
|
||||
|
||||
class InstanceBindingMap {
|
||||
public:
|
||||
};
|
||||
typedef std::multimap<String, InstanceBinding *> InstanceBindingMap;
|
||||
typedef InstanceBindingMap::iterator InstanceBindingIterator;
|
||||
|
||||
|
||||
// A frame contains bindings defined at a particular scope in a program. A frame is either the top-level system frame,
|
||||
// a global object, a package, a function frame, a class, or a block frame
|
||||
class Frame {
|
||||
class Frame : public JS2Object {
|
||||
public:
|
||||
enum Plurality { Singular, Plural };
|
||||
enum FrameKind { System, GlobalObject, Package, Function, Class, Block };
|
||||
|
||||
Frame(FrameKind kind) : kind(kind), nextFrame(NULL) { }
|
||||
Frame(ObjectKind kind) : JS2Object(kind), nextFrame(NULL) { }
|
||||
|
||||
StaticBindingMap staticReadBindings; // Map of qualified names to readable static members defined in this frame
|
||||
StaticBindingMap staticWriteBindings; // Map of qualified names to writable static members defined in this frame
|
||||
|
||||
FrameKind kind; // [rather than use RTTI (in general)]
|
||||
Frame *nextFrame;
|
||||
#ifdef DEBUG
|
||||
virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
class JS2Class : public Frame {
|
||||
public:
|
||||
JS2Class() : Frame(Class) { }
|
||||
JS2Class() : Frame(ClassKind) { }
|
||||
|
||||
StringAtom &getName();
|
||||
|
||||
|
@ -310,7 +328,7 @@ public:
|
|||
|
||||
class GlobalObject : public Frame {
|
||||
public:
|
||||
GlobalObject(World &world) : Frame(Frame::GlobalObject), internalNamespace(new Namespace(world.identifiers["internal"])) { }
|
||||
GlobalObject(World &world) : Frame(GlobalObjectKind), internalNamespace(new Namespace(world.identifiers["internal"])) { }
|
||||
|
||||
Namespace *internalNamespace; // This global object's internal namespace
|
||||
DynamicPropertyMap dynamicProperties; // A set of this global object's dynamic properties
|
||||
|
@ -325,8 +343,10 @@ public:
|
|||
};
|
||||
|
||||
// Instances of non-dynamic classes are represented as FIXEDINSTANCE records. These instances can contain only fixed properties.
|
||||
class FixedInstance {
|
||||
class FixedInstance : public JS2Object {
|
||||
public:
|
||||
FixedInstance() : JS2Object(FixedInstanceKind), typeofString(type->getName()) { }
|
||||
|
||||
JS2Class *type; // This instance's type
|
||||
Invokable *call; // A procedure to call when this instance is used in a call expression
|
||||
Invokable *construct; // A procedure to call when this instance is used in a new expression
|
||||
|
@ -336,9 +356,9 @@ public:
|
|||
};
|
||||
|
||||
// Instances of dynamic classes are represented as DYNAMICINSTANCE records. These instances can contain fixed and dynamic properties.
|
||||
class DynamicInstance {
|
||||
class DynamicInstance : public JS2Object {
|
||||
public:
|
||||
DynamicInstance(JS2Class *type) : type(type), call(NULL), construct(NULL), env(NULL), typeofString(type->getName()) { }
|
||||
DynamicInstance(JS2Class *type) : JS2Object(DynamicInstanceKind), type(type), call(NULL), construct(NULL), env(NULL), typeofString(type->getName()) { }
|
||||
|
||||
JS2Class *type; // This instance's type
|
||||
Invokable *call; // A procedure to call when this instance is used in a call expression
|
||||
|
@ -349,7 +369,24 @@ public:
|
|||
DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties
|
||||
};
|
||||
|
||||
// Prototype instances are represented as PROTOTYPE records. Prototype instances
|
||||
// contain no fixed properties.
|
||||
class PrototypeInstance : public JS2Object {
|
||||
public:
|
||||
PrototypeInstance(PrototypeInstance *parent) : JS2Object(PrototypeInstanceKind), parent(parent) { }
|
||||
|
||||
|
||||
PrototypeInstance *parent; // If this instance was created by calling new on a prototype function,
|
||||
// the value of the function’s prototype property at the time of the call;
|
||||
// none otherwise.
|
||||
DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// Base class for all references (lvalues)
|
||||
// References are generated during the eval stage (bytecode generation)
|
||||
class Reference {
|
||||
public:
|
||||
virtual void emitReadBytecode(BytecodeContainer *bCon) { ASSERT(false); }
|
||||
|
@ -363,6 +400,7 @@ class LexicalReference : public Reference {
|
|||
// of a given set of qualified names. LEXICALREFERENCE tuples arise from evaluating identifiers a and qualified identifiers
|
||||
// q::a.
|
||||
public:
|
||||
LexicalReference(const StringAtom &name, bool strict) : variableMultiname(new Multiname(name)), env(NULL), strict(strict) { }
|
||||
LexicalReference(Multiname *vm, Environment *env, bool strict) : variableMultiname(vm), env(env), strict(strict) { }
|
||||
|
||||
Multiname *variableMultiname; // A nonempty set of qualified names to which this reference can refer
|
||||
|
@ -419,13 +457,13 @@ public:
|
|||
// The top-level frame containing predefined constants, functions, and classes.
|
||||
class SystemFrame : public Frame {
|
||||
public:
|
||||
SystemFrame() : Frame(System) { }
|
||||
SystemFrame() : Frame(SystemKind) { }
|
||||
};
|
||||
|
||||
// Frames holding bindings for invoked functions
|
||||
class FunctionFrame : public Frame {
|
||||
public:
|
||||
FunctionFrame() : Frame(Function) { }
|
||||
FunctionFrame() : Frame(FunctionKind) { }
|
||||
|
||||
Plurality plurality;
|
||||
js2val thisObject; // The value of this; none if this function doesn't define this;
|
||||
|
@ -439,7 +477,7 @@ public:
|
|||
|
||||
class BlockFrame : public Frame {
|
||||
public:
|
||||
BlockFrame() : Frame(Block) { }
|
||||
BlockFrame() : Frame(BlockKind) { }
|
||||
|
||||
Plurality plurality;
|
||||
};
|
||||
|
@ -448,6 +486,9 @@ public:
|
|||
class LookupKind {
|
||||
public:
|
||||
LookupKind(bool isLexical, js2val thisObject) : isLexical(isLexical), thisObject(thisObject) { }
|
||||
|
||||
bool isPropertyLookup() { return !isLexical; }
|
||||
|
||||
bool isLexical; // if isLexical, use the 'this' below. Otherwise it's a propertyLookup
|
||||
js2val thisObject;
|
||||
};
|
||||
|
@ -547,11 +588,12 @@ public:
|
|||
JS2Class *objectType(js2val obj);
|
||||
|
||||
StaticMember *findFlatMember(Frame *container, Multiname *multiname, Access access, Phase phase);
|
||||
InstanceBinding *resolveInstanceMemberName(JS2Class *js2class, Multiname *multiname, Access access, Phase phase);
|
||||
|
||||
|
||||
bool readProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
bool readProperty(Frame *pf, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
bool readDynamicProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
bool readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
|
||||
bool readStaticMember(StaticMember *m, Phase phase, js2val *rval);
|
||||
|
||||
|
||||
|
@ -594,7 +636,6 @@ public:
|
|||
|
||||
};
|
||||
|
||||
|
||||
}; // namespace MetaData
|
||||
}; // namespace Javascript
|
||||
|
||||
|
|
|
@ -33,15 +33,17 @@
|
|||
|
||||
|
||||
case eLexicalRead: {
|
||||
Multiname *mn = BytecodeContainer::getMultiname(pc);
|
||||
pc += sizeof(Multiname *);
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
meta->env.lexicalRead(meta, mn, phase);
|
||||
}
|
||||
break;
|
||||
|
||||
case eLexicalWrite: {
|
||||
Multiname *mn = BytecodeContainer::getMultiname(pc);
|
||||
pc += sizeof(Multiname *);
|
||||
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
|
||||
pc += sizeof(short);
|
||||
mn->addNamespace(meta->cxt);
|
||||
retval = pop();
|
||||
meta->env.lexicalWrite(meta, mn, retval, true, phase);
|
||||
}
|
||||
|
|
|
@ -44,4 +44,19 @@
|
|||
}
|
||||
break;
|
||||
|
||||
|
||||
case eNewObject: {
|
||||
uint16 argCount = BytecodeContainer::getShort(pc);
|
||||
pc += sizeof(uint16);
|
||||
PrototypeInstance *pInst = new PrototypeInstance(NULL); // XXX Object prototype object
|
||||
for (uint16 i = 0; i < argCount; i++) {
|
||||
js2val nameVal = pop();
|
||||
ASSERT(JS2VAL_IS_STRING(nameVal));
|
||||
String *name = JS2VAL_TO_STRING(nameVal);
|
||||
const StringAtom &nameAtom = world.identifiers[*name];
|
||||
js2val fieldVal = pop();
|
||||
const DynamicPropertyMap::value_type e(nameAtom, fieldVal);
|
||||
pInst->dynamicProperties.insert(e);
|
||||
}
|
||||
push(OBJECT_TO_JS2VAL(pInst));
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -48,3 +48,9 @@
|
|||
push(JS2VAL_TRUE);
|
||||
}
|
||||
break;
|
||||
|
||||
case eString: {
|
||||
push(STRING_TO_JS2VAL(BytecodeContainer::getString(pc)));
|
||||
pc += sizeof(String *);
|
||||
}
|
||||
break;
|
||||
|
|
Загрузка…
Ссылка в новой задаче