Labor day progress. DotReference, class instance variable definition and

associated oevrride resolution support. Branch logic support.
This commit is contained in:
rogerl%netscape.com 2002-09-03 15:20:24 +00:00
parent 89f954057e
commit ff6ac62d63
11 changed files with 867 additions and 137 deletions

View File

@ -60,14 +60,34 @@
namespace JavaScript {
namespace MetaData {
BytecodeContainer::~BytecodeContainer()
{
for (std::vector<Multiname *>::iterator i = mMultinameList.begin(), end = mMultinameList.end(); (i != end); i++)
delete *i;
// Establish the label's location in a bytecode container
void Label::setLocation(BytecodeContainer *bCon, uint32 location)
{
mHasLocation = true;
mLocation = location;
for (std::vector<uint32>::iterator i = mFixupList.begin(), end = mFixupList.end();
(i != end); i++)
{
uint32 branchLocation = *i;
bCon->setOffset(branchLocation, int32(mLocation - branchLocation));
}
}
// Add a branch location to the list of fixups for this label
// (or resolve the branch if the location is known already)
void Label::addFixup(BytecodeContainer *bCon, uint32 branchLocation)
{
if (mHasLocation)
bCon->addOffset(int32(mLocation - branchLocation));
else {
mFixupList.push_back(branchLocation);
bCon->addLong(0);
}
}
// Look up the pc and return a position from the map
size_t BytecodeContainer::getPosition(uint16 pc)
{
for (std::vector<MapEntry>::iterator i = pcMap.begin(), end = pcMap.end(); (i != end); i++)
@ -76,6 +96,57 @@ namespace MetaData {
return 0;
}
// insert the opcode, marking it's position in the pcmap and
// adjusting the stack as appropriate.
void BytecodeContainer::emitOp(JS2Op op, size_t pos)
{
adjustStack(op);
addByte((uint8)op);
pcMap.push_back(MapEntry(mBuffer.size(), pos));
}
// insert the opcode, marking it's position in the pcmap and
// adjusting the stack as supplied.
void BytecodeContainer::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));
}
// Track the high-water mark for the stack
// and watch for a bad negative stack
void BytecodeContainer::adjustStack(JS2Op op, int32 effect)
{
mStackTop += effect;
if (mStackTop > mStackMax)
mStackMax = mStackTop;
ASSERT(mStackTop >= 0);
}
// get a new label
BytecodeContainer::LabelID BytecodeContainer::getLabel()
{
LabelID result = mLabelList.size();
mLabelList.push_back(Label());
return result;
}
// set the current pc as needing a fixup to a label
void BytecodeContainer::addFixup(LabelID label)
{
ASSERT(label < mLabelList.size());
mLabelList[label].addFixup(this, mBuffer.size());
}
// set the current pc as the position for a label
void BytecodeContainer::setLabel(LabelID label)
{
ASSERT(label < mLabelList.size());
mLabelList[label].setLocation(this, mBuffer.size());
}
}
}

View File

@ -47,6 +47,40 @@
namespace JavaScript {
namespace MetaData {
class BytecodeContainer;
class Label {
public:
typedef enum { InternalLabel, NamedLabel, BreakLabel, ContinueLabel } LabelKind;
Label() : mKind(InternalLabel), mHasLocation(false) { }
Label(LabelStmtNode *lbl) : mKind(NamedLabel), mHasLocation(false), mLabelStmt(lbl) { }
Label(LabelKind kind) : mKind(kind), mHasLocation(false) { }
bool matches(const StringAtom *name)
{
return ((mKind == NamedLabel) && (mLabelStmt->name.compare(*name) == 0));
}
bool matches(LabelKind kind)
{
return (mKind == kind);
}
void addFixup(BytecodeContainer *bcg, uint32 branchLocation);
void setLocation(BytecodeContainer *bcg, uint32 location);
std::vector<uint32> mFixupList;
LabelKind mKind;
bool mHasLocation;
LabelStmtNode *mLabelStmt;
uint32 mLocation;
};
class Multiname;
class Frame;
@ -54,22 +88,25 @@ class Frame;
class BytecodeContainer {
public:
BytecodeContainer() : mStackTop(0), mStackMax(0) { }
BytecodeContainer::~BytecodeContainer() ;
BytecodeContainer::~BytecodeContainer() { }
uint8 *getCodeStart() { return mBuffer.begin(); }
typedef std::pair<uint16, size_t> MapEntry;
std::vector<MapEntry> pcMap;
typedef uint32 LabelID;
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 emitOp(JS2Op op, size_t pos);
void emitOp(JS2Op op, size_t pos, int32 effect);
void emitBranch(JS2Op op, LabelID tgt, size_t pos)
{ emitOp(op, pos); addFixup(tgt); }
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 adjustStack(JS2Op op, int32 effect);
void addByte(uint8 v) { mBuffer.push_back(v); }
@ -89,12 +126,15 @@ public:
void addFrame(Frame *f) { mFrameList.push_back(f); addShort(mFrameList.size() - 1); }
void addOffset(int32 v) { mBuffer.insert(mBuffer.end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(int32)); }
void setOffset(uint32 index, int32 v) { *((int32 *)(mBuffer.begin() + index)) = v; }
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?
// XXX We lose StringAtom here (and is it safe to stash the address of a StringAtom?)
// - is there any way of keeping StringAtoms themselves in a bytecodeContainer?
typedef std::vector<uint8> CodeBuffer;
@ -102,9 +142,14 @@ public:
std::vector<Multiname *> mMultinameList; // gc tracking
std::vector<Frame *> mFrameList; // gc tracking
int32 mStackTop; // keep these as signed so as to
int32 mStackMax; // track if they go negative.
int32 mStackTop; // keep these as signed so as to...
int32 mStackMax; // ...track if they go negative.
std::vector<Label> mLabelList;
LabelID getLabel();
void addFixup(LabelID label);
void setLabel(LabelID label);
};

View File

@ -44,11 +44,6 @@
#include "bytecodecontainer.h"
#include "js2metadata.h"
#ifdef DEBUG
#include "tracer.h"
#include "collector.h"
#endif
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
#include <MacTypes.h>

View File

@ -80,6 +80,7 @@ js2val JS2Engine::interpreterLoop()
#include "js2op_invocation.cpp"
#include "js2op_access.cpp"
#include "js2op_literal.cpp"
#include "js2op_flowcontrol.cpp"
}
}
return retval;
@ -200,6 +201,27 @@ float64 JS2Engine::convertValueToDouble(js2val x)
}
// x is not a bool
bool JS2Engine::convertValueToBoolean(js2val x)
{
if (JS2VAL_IS_UNDEFINED(x))
return false;
if (JS2VAL_IS_NULL(x))
return false;
if (JS2VAL_IS_INT(x))
return (JS2VAL_TO_INT(x) != 0);
if (JS2VAL_IS_DOUBLE(x)) {
float64 *xd = JS2VAL_TO_DOUBLE(x);
return ! (JSDOUBLE_IS_POSZERO(*xd) || JSDOUBLE_IS_NEGZERO(*xd) || JSDOUBLE_IS_NaN(*xd));
}
if (JS2VAL_IS_STRING(x)) {
String *str = JS2VAL_TO_STRING(x);
return (str->length() != 0);
}
return true;
}
#define INIT_STRINGATOM(n) n##_StringAtom(world.identifiers[#n])
JS2Engine::JS2Engine(World &world)
@ -226,28 +248,47 @@ int JS2Engine::getStackEffect(JS2Op op)
{
switch (op) {
case eReturn:
case ePlus:
return -1;
return -1;
case eAdd: // pop two, push one
case eSubtract:
return -1;
case eString:
case eTrue:
case eFalse:
case eNumber:
return 1;
return 1; // push literal value
case eLexicalRead:
return 0; // consumes a multiname, pushes the value
return 1; // push the value
case eLexicalWrite:
return -2; // consumes a multiname and the value
return -1; // pop the value
case eDotRead:
return 0; // pop a base, push the value
case eDotWrite:
return -2; // pop a base and the value
case eReturnVoid:
case eBranch:
return 0;
case eToBoolean: // pop object, push boolean
return 0;
case eMultiname:
return 1; // push the multiname object
case ePushFrame:
case ePopFrame:
case ePushFrame: // affect the frame stack...
case ePopFrame: // ...not the exec stack
return 0;
case eBranchFalse:
case eBranchTrue:
return -1; // pop the boolean condition
case eNew: // pop the class or function, push the new instance
return 0;
default:
@ -261,5 +302,22 @@ size_t JS2Engine::errorPos()
return bCon->getPosition(pc - bCon->getCodeStart());
}
JS2Object *JS2Engine::defaultConstructor(JS2Engine *engine)
{
js2val v = engine->pop();
ASSERT(JS2VAL_IS_OBJECT(v) && !JS2VAL_IS_NULL(v));
JS2Object *obj = JS2VAL_TO_OBJECT(v);
ASSERT(obj->kind == ClassKind);
JS2Class *c = checked_cast<JS2Class *>(obj);
if (c->dynamic)
return new DynamicInstance(c);
else
if (c->prototype)
return new PrototypeInstance(NULL);
else
return new FixedInstance(c);
}
}
}

View File

@ -49,23 +49,30 @@ namespace MetaData {
enum JS2Op {
ePlus,
eAdd,
eSubtract,
eTrue,
eFalse,
eNumber,
eString, // <string pointer>
eObject, // <named argument count>
eLexicalRead,
eLexicalWrite,
eString, // <string pointer:u32>
eNewObject, // <argCount:u16>
eLexicalRead, // <multiname index:u16>
eLexicalWrite, // <multiname index:u16>
eDotRead, // <multiname index:u16>
eDotWrite, // <multiname index:u16>
eReturn,
eReturnVoid,
eNewObject, // <argCount:16>
eMultiname, // <multiname index>
ePushFrame, // <frame index>
ePopFrame
ePushFrame, // <frame index:u16>
ePopFrame,
eToBoolean,
eBranchFalse, // <branch displacement:s32> XXX save space with short and long versions instead ?
eBranchTrue, // <branch displacement:s32>
eBranch, // <branch displacement:s32>
eNew
};
class JS2Object;
class JS2Metadata;
class BytecodeContainer;
@ -89,14 +96,17 @@ public:
void push(js2val x) { ASSERT(sp < (execStack + MAX_EXEC_STACK)); *sp++ = x; }
js2val pop() { ASSERT(sp > execStack); return *--sp; }
js2val top() { return *(sp - 1); }
String *convertValueToString(js2val x);
js2val convertValueToPrimitive(js2val x);
float64 convertValueToDouble(js2val x);
bool convertValueToBoolean(js2val x);
String *toString(js2val x) { if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); }
js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); }
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); }
bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); }
uint8 *pc;
BytecodeContainer *bCon;
@ -119,6 +129,9 @@ public:
js2val *sp;
static JS2Object *defaultConstructor(JS2Engine *engine);
static int getStackEffect(JS2Op op);

View File

@ -102,6 +102,21 @@ namespace MetaData {
ValidateStmt(cxt, env, l->stmt);
}
break;
case StmtNode::If:
{
UnaryStmtNode *i = checked_cast<UnaryStmtNode *>(p);
ValidateExpression(cxt, env, i->expr);
ValidateStmt(cxt, env, i->stmt);
}
break;
case StmtNode::IfElse:
{
BinaryStmtNode *i = checked_cast<BinaryStmtNode *>(p);
ValidateExpression(cxt, env, i->expr);
ValidateStmt(cxt, env, i->stmt);
ValidateStmt(cxt, env, i->stmt2);
}
break;
case StmtNode::Var:
case StmtNode::Const:
{
@ -144,6 +159,28 @@ namespace MetaData {
// the type and the value are 'future'
}
break;
case Attribute::Abstract:
case Attribute::Virtual:
case Attribute::Final:
{
JS2Class *c = checked_cast<JS2Class *>(env->getTopFrame());
InstanceMember *m = NULL;
switch (memberMod) {
case Attribute::Abstract:
if (v->initializer)
reportError(Exception::syntaxError, "Abstract member may not have initializer", p->pos);
m = new InstanceAccessor(NULL, false);
break;
case Attribute::Virtual:
m = new InstanceVariable(immutable, false);
break;
case Attribute::Final:
m = new InstanceVariable(immutable, true);
break;
}
defineInstanceMember(c, cxt, *name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, m, p->pos);
}
break;
}
}
@ -230,7 +267,7 @@ namespace MetaData {
reportError(Exception::definitionError, "Illegal modifier for class definition", p->pos);
break;
}
JS2Class *c = new JS2Class(superClass, proto, new Namespace(engine->public_StringAtom), (a->dynamic || superClass->dynamic), final);
JS2Class *c = new JS2Class(superClass, proto, new Namespace(engine->private_StringAtom), (a->dynamic || superClass->dynamic), final, classStmt->name);
classStmt->c = c;
Variable *v = new Variable(classClass, OBJECT_TO_JS2VAL(c), true);
defineStaticMember(env, classStmt->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
@ -291,6 +328,34 @@ namespace MetaData {
EvalStmt(env, phase, l->stmt);
}
break;
case StmtNode::If:
{
BytecodeContainer::LabelID skipOverStmt = bCon->getLabel();
UnaryStmtNode *i = checked_cast<UnaryStmtNode *>(p);
Reference *r = EvalExprNode(env, phase, i->expr);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eToBoolean, p->pos);
bCon->emitBranch(eBranchFalse, skipOverStmt, p->pos);
EvalStmt(env, phase, i->stmt);
bCon->setLabel(skipOverStmt);
}
break;
case StmtNode::IfElse:
{
BytecodeContainer::LabelID falseStmt = bCon->getLabel();
BytecodeContainer::LabelID skipOverFalseStmt = bCon->getLabel();
BinaryStmtNode *i = checked_cast<BinaryStmtNode *>(p);
Reference *r = EvalExprNode(env, phase, i->expr);
if (r) r->emitReadBytecode(bCon, p->pos);
bCon->emitOp(eToBoolean, p->pos);
bCon->emitBranch(eBranchFalse, falseStmt, p->pos);
EvalStmt(env, phase, i->stmt);
bCon->emitBranch(eBranch, skipOverFalseStmt, p->pos);
bCon->setLabel(falseStmt);
EvalStmt(env, phase, i->stmt2);
bCon->setLabel(skipOverFalseStmt);
}
break;
case StmtNode::Var:
case StmtNode::Const:
{
@ -593,11 +658,15 @@ namespace MetaData {
break;
case ExprNode::dot:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
ValidateExpression(cxt, env, b->op1);
ValidateExpression(cxt, env, b->op2);
}
break;
case ExprNode::assignment:
case ExprNode::add:
case ExprNode::subtract:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
ValidateExpression(cxt, env, b->op1);
@ -610,6 +679,17 @@ namespace MetaData {
// IdentifierExprNode *i = checked_cast<IdentifierExprNode *>(p);
}
break;
case ExprNode::New:
{
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
ValidateExpression(cxt, env, i->op);
ExprPairList *args = i->pairs;
while (args) {
ValidateExpression(cxt, env, args->value);
args = args->next;
}
}
break;
default:
NOT_REACHED("Not Yet Implemented");
} // switch (p->getKind())
@ -638,6 +718,7 @@ namespace MetaData {
Reference *JS2Metadata::EvalExprNode(Environment *env, Phase phase, ExprNode *p)
{
Reference *returnRef = NULL;
JS2Op binaryOp;
switch (p->getKind()) {
@ -656,13 +737,19 @@ namespace MetaData {
}
break;
case ExprNode::add:
binaryOp = eAdd;
goto doBinary;
case ExprNode::subtract:
binaryOp = eSubtract;
goto doBinary;
doBinary:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
Reference *lVal = EvalExprNode(env, phase, b->op1);
if (lVal) lVal->emitReadBytecode(bCon, p->pos);
Reference *rVal = EvalExprNode(env, phase, b->op2);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
bCon->emitOp(ePlus, p->pos);
bCon->emitOp(binaryOp, p->pos);
}
break;
@ -684,7 +771,7 @@ namespace MetaData {
case ExprNode::qualify:
{
QualifyExprNode *qe = checked_cast<QualifyExprNode *>(p);
const StringAtom &name = checked_cast<IdentifierExprNode *>(p)->name;
const StringAtom &name = qe->name;
js2val av = EvalExpression(env, CompilePhase, qe->qualifier);
if (JS2VAL_IS_NULL(av) || !JS2VAL_IS_OBJECT(av))
@ -695,6 +782,7 @@ namespace MetaData {
Namespace *ns = checked_cast<Namespace *>(obj);
returnRef = new LexicalReference(name, ns, cxt.strict);
// Calling emitBindBytecode causes the multiname to get loaded onto the stack
((LexicalReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
break;
@ -706,6 +794,27 @@ namespace MetaData {
((LexicalReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
break;
case ExprNode::dot:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
Reference *baseVal = EvalExprNode(env, phase, b->op1);
if (baseVal) baseVal->emitReadBytecode(bCon, p->pos);
if (b->op2->getKind() == ExprNode::identifier) {
returnRef = new DotReference(i->name);
((DotReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
else {
if (b->op2->getKind() == ExprNode::qualify) {
Reference *rVal = EvalExprNode(env, phase, b->op2);
ASSERT(rVal && checked_cast<LexicalReference *>(rVal));
returnRef = new DotReference(((LexicalReference *)rVal)->variableMultiname);
((DotReference *)returnRef)->emitBindBytecode(bCon, p->pos);
}
// else bracketRef...
}
}
break;
case ExprNode::boolean:
if (checked_cast<BooleanExprNode *>(p)->value)
bCon->emitOp(eTrue, p->pos);
@ -741,15 +850,19 @@ namespace MetaData {
bCon->addShort(argCount);
}
break;
case ExprNode::dot:
case ExprNode::New:
{
BinaryExprNode *b = checked_cast<BinaryExprNode *>(p);
if (b->op2->getKind() == ExprNode::identifier) {
}
else {
if (b->op2->getKind() == ExprNode::qualify) {
}
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
Reference *rVal = EvalExprNode(env, phase, i->op);
if (rVal) rVal->emitReadBytecode(bCon, p->pos);
ExprPairList *args = i->pairs;
uint32 argCount = 0;
while (args) {
EvalExprNode(env, phase, args->value);
argCount++;
args = args->next;
}
bCon->emitOp(eNew, p->pos);
}
break;
default:
@ -787,7 +900,7 @@ namespace MetaData {
prev = pf;
pf = pf->nextFrame;
}
if (pf->nextFrame && (pf->kind == ClassKind))
if ((pf != firstFrame) && (pf->kind == ClassKind))
pf = prev;
return pf;
}
@ -980,7 +1093,165 @@ namespace MetaData {
}
// Look through 'c' and all it's super classes for a identifier
// matching the qualified name and access.
InstanceMember *JS2Metadata::findInstanceMember(JS2Class *c, QualifiedName *qname, Access access)
{
if (qname == NULL)
return NULL;
JS2Class *s = c;
while (s) {
if (access & ReadAccess) {
for (InstanceBindingIterator b = s->instanceReadBindings.lower_bound(qname->id),
end = s->instanceReadBindings.upper_bound(qname->id); (b != end); b++) {
if (*qname == b->second->qname)
return b->second->content;
}
}
if (access & WriteAccess) {
for (InstanceBindingIterator b = s->instanceWriteBindings.lower_bound(qname->id),
end = s->instanceWriteBindings.upper_bound(qname->id); (b != end); b++) {
if (*qname == b->second->qname)
return b->second->content;
}
}
s = s->super;
}
return NULL;
}
// Examine class 'c' and find all instance members that would be overridden
// by 'id' in any of the given namespaces.
OverrideStatus *JS2Metadata::searchForOverrides(JS2Class *c, const StringAtom &id, NamespaceList *namespaces, Access access, size_t pos)
{
OverrideStatus *os = new OverrideStatus(NULL, id);
for (NamespaceListIterator ns = namespaces->begin(), end = namespaces->end(); (ns != end); ns++) {
QualifiedName qname(*ns, id);
InstanceMember *m = findInstanceMember(c, &qname, access);
if (m) {
os->multiname.addNamespace(*ns);
if (os->overriddenMember == NULL)
os->overriddenMember = m;
else
if (os->overriddenMember != m) // different instance members by same id
reportError(Exception::definitionError, "Illegal override", pos);
}
}
return os;
}
// Find the possible override conflicts that arise from the given id and namespaces
// Fall back on the currently open namespace list if no others are specified.
OverrideStatus *JS2Metadata::resolveOverrides(JS2Class *c, Context *cxt, const StringAtom &id, NamespaceList *namespaces, Access access, bool expectMethod, size_t pos)
{
OverrideStatus *os = NULL;
if ((namespaces == NULL) || namespaces->empty()) {
os = searchForOverrides(c, id, &cxt->openNamespaces, access, pos);
if (os->overriddenMember == NULL) {
ASSERT(os->multiname.nsList.empty());
os->multiname.addNamespace(publicNamespace);
}
}
else {
OverrideStatus *os2 = searchForOverrides(c, id, namespaces, access, pos);
if (os2->overriddenMember == NULL) {
OverrideStatus *os3 = searchForOverrides(c, id, &cxt->openNamespaces, access, pos);
if (os3->overriddenMember == NULL) {
os->multiname.addNamespace(namespaces);
}
else {
os->potentialConflict = true; // Didn't find the member with a specified namespace, but did with
// the use'd ones. That'll be an error unless the override is
// disallowed (in defineInstanceMember below)
os->multiname.addNamespace(namespaces);
}
delete os3;
delete os2;
}
else {
os = os2;
os->multiname.addNamespace(namespaces);
}
}
// For all the discovered possible overrides, make sure the member doesn't already exist in the class
for (NamespaceListIterator nli = os->multiname.nsList.begin(), nlend = os->multiname.nsList.end(); (nli != nlend); nli++) {
QualifiedName qname(*nli, id);
if (access & ReadAccess) {
for (InstanceBindingIterator b = c->instanceReadBindings.lower_bound(id),
end = c->instanceReadBindings.upper_bound(id); (b != end); b++) {
if (qname == b->second->qname)
reportError(Exception::definitionError, "Illegal override", pos);
}
}
if (access & WriteAccess) {
for (InstanceBindingIterator b = c->instanceWriteBindings.lower_bound(id),
end = c->instanceWriteBindings.upper_bound(id); (b != end); b++) {
if (qname == b->second->qname)
reportError(Exception::definitionError, "Illegal override", pos);
}
}
}
// Make sure we're getting what we expected
if (expectMethod) {
if (os->overriddenMember && !os->potentialConflict && (os->overriddenMember->kind != InstanceMember::InstanceMethodKind))
reportError(Exception::definitionError, "Illegal override, expected method", pos);
}
else {
if (os->overriddenMember && !os->potentialConflict && (os->overriddenMember->kind == InstanceMember::InstanceMethodKind))
reportError(Exception::definitionError, "Illegal override, didn't expect method", pos);
}
return os;
}
OverrideStatusPair JS2Metadata::defineInstanceMember(JS2Class *c, Context *cxt, const StringAtom &id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, InstanceMember *m, size_t pos)
{
OverrideStatus *readStatus;
OverrideStatus *writeStatus;
if (xplicit)
reportError(Exception::definitionError, "Illegal use of explicit", pos);
if (access & ReadAccess)
readStatus = resolveOverrides(c, cxt, id, namespaces, ReadAccess, (m->kind == InstanceMember::InstanceMethodKind), pos);
else
readStatus = new OverrideStatus(NULL, id);
if (access & WriteAccess)
writeStatus = resolveOverrides(c, cxt, id, namespaces, WriteAccess, (m->kind == InstanceMember::InstanceMethodKind), pos);
else
writeStatus = new OverrideStatus(NULL, id);
if ((!readStatus->potentialConflict && (readStatus->overriddenMember != NULL))
|| (!writeStatus->potentialConflict && (writeStatus->overriddenMember != NULL))) {
if ((overrideMod != Attribute::DoOverride) && (overrideMod != Attribute::OverrideUndefined))
reportError(Exception::definitionError, "Illegal override", pos);
}
else {
if (readStatus->potentialConflict || writeStatus->potentialConflict) {
if ((overrideMod != Attribute::DontOverride) && (overrideMod != Attribute::OverrideUndefined))
reportError(Exception::definitionError, "Illegal override", pos);
}
}
NamespaceListIterator nli, nlend;
for (nli = readStatus->multiname.nsList.begin(), nlend = readStatus->multiname.nsList.end(); (nli != nlend); nli++) {
QualifiedName qName(*nli, id);
InstanceBinding *ib = new InstanceBinding(qName, m);
const InstanceBindingMap::value_type e(id, ib);
c->instanceReadBindings.insert(e);
}
for (nli = writeStatus->multiname.nsList.begin(), nlend = writeStatus->multiname.nsList.end(); (nli != nlend); nli++) {
QualifiedName qName(*nli, id);
InstanceBinding *ib = new InstanceBinding(qName, m);
const InstanceBindingMap::value_type e(id, ib);
c->instanceWriteBindings.insert(e);
}
OverrideStatusPair osp(readStatus, writeStatus);
return osp;
}
// Define a hoisted var in the current frame (either Global or a Function)
void JS2Metadata::defineHoistedVar(Environment *env, const StringAtom &id, StmtNode *p)
{
@ -1042,6 +1313,9 @@ namespace MetaData {
{
cxt.openNamespaces.clear();
cxt.openNamespaces.push_back(publicNamespace);
objectClass = new JS2Class(NULL, new JS2Object(PrototypeInstanceKind), new Namespace(engine->private_StringAtom), true, false, engine->object_StringAtom);
objectClass->complete = true;
}
// objectType(o) returns an OBJECT o's most specific type.
@ -1062,16 +1336,33 @@ namespace MetaData {
return stringClass;
}
ASSERT(JS2VAL_IS_OBJECT(obj));
return NULL;
/*
NAMESPACE do return namespaceClass;
COMPOUNDATTRIBUTE do return attributeClass;
CLASS do return classClass;
METHODCLOSURE do return functionClass;
PROTOTYPE do return prototypeClass;
INSTANCE do return resolveAlias(o).type;
PACKAGE or GLOBAL do return packageClass
*/
JS2Object *obj = JS2VAL_TO_OBJECT(obj);
switch (obj->kind) {
case AttributeObjectKind:
return attributeClass;
case MultinameKind:
return namespaceClass;
case ClassKind:
return classClass;
case PrototypeInstanceKind:
return prototypeClass;
case FixedInstanceKind:
return checked_cast<FixedInstance *>(obj)->type;
case DynamicInstanceKind:
return checked_cast<DynamicInstance *>(obj)->type;
case GlobalObjectKind:
case PackageKind:
return packageClass;
case SystemKind:
case FunctionKind:
case BlockKind:
default:
ASSERT(false);
return NULL;
}
}
// Read the property from the container given by the public id in multiname - if that exists
@ -1216,9 +1507,103 @@ namespace MetaData {
// Read the value of a property in the container. Return true/false if that container has
// the property or not. If it does, return it's value
bool JS2Metadata::readProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
bool JS2Metadata::readProperty(js2val containerVal, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval)
{
return true;
bool isDynamicInstance = false;
if (JS2VAL_IS_PRIMITIVE(containerVal)) {
readClassProperty:
JS2Class *c = objectType(containerVal);
InstanceBinding *ib = resolveInstanceMemberName(c, multiname, ReadAccess, Phase phase);
if ((ib == NULL) && isDynamicInstance)
return readDynamicProperty(JS2VAL_TO_OBJECT(containerVal), multiname, lookupKind, phase, rval);
else
// XXX passing a primitive here ???
return readInstanceMember(containerVal, c, (ib)? &ib->qname : NULL, phase, rval);
}
JS2Object *obj = JS2VAL_TO_OBJECT(containerVal);
switch (obj->kind) {
case AttributeObjectKind:
case MultinameKind:
case FixedInstanceKind:
goto readClassProperty;
case DynamicInstanceKind:
isDynamicInstance = true;
goto readClassProperty;
case SystemKind:
case GlobalObjectKind:
case PackageKind:
case FunctionKind:
case BlockKind:
{
}
break;
case ClassKind:
{
}
break;
case PrototypeInstanceKind:
return readDynamicProperty(obj, multiname, lookupKind, phase, rval);
default:
ASSERT(false);
return false;
}
}
/*
m: INSTANCEMEMBEROPT ¨ findInstanceMember(c, qname, read);
case m of
{none} do return none;
INSTANCEVARIABLE do
if phase = compile and not m.immutable then throw compileExpressionError
end if;
v: OBJECTU ¨ findSlot(this, m).value;
if v = uninitialised then throw uninitialisedError end if;
return v;
INSTANCEMETHOD do return METHODCLOSURE·this: this, method: ;
INSTANCEGETTER do return m.call(this, m.env, phase);
INSTANCESETTER do
m cannot be an INSTANCESETTER because these are only represented as write-only members.
end case
end proc;
*/
proc findSlot(o: OBJECT, id: INSTANCEVARIABLE): SLOT
o must be an INSTANCE;
matchingSlots: SLOT{} ¨ {s | "s Œ resolveAlias(o).slots such that s.id = id};
return the one element of matchingSlots
end proc;
JS2MetaData::findSlot(js2val thisObjVal, InstanceVariable *id)
{
ASSERT(JS2VAL_IS_OBJECT(thisObjVal)
&& ((JS2VAL_TO_OBJECT(thisObjVal)->kind == DynamicInstanceKind)
|| (JS2VAL_TO_OBJECT(thisObjVal)->kind == FixedInstanceKind)));
JS2Object *thisObj = JS2VAL_TO_OBJECT(thisObjVal);
Slots *s;
if (thisObj->kind == DynamicInstanceKind)
s = checked_cast<DynamicInstance *>(thisObj)->slots;
else
s = checked_cast<FixedInstance *>(thisObj)->slots;
}
bool JS2Metadata::readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval)
{
InstanceMember *m = findInstanceMember(c, qname, ReadAccess);
if (m == NULL) return false;
switch (m->kind) {
case InstanceVariableKind:
if ((phase == CompilePhase) && !checked_cast<InstanceVariable *>(m)->immutable)
reportError(Exception::compileExpressionError, "Inappropriate compile time expression", engine->errorPos());
findSlot(containerVal, m);
case InstanceMethodKind:
case InstanceAccessorKind:
break;
}
}
// Read the value of a property in the frame. Return true/false if that frame has
@ -1444,7 +1829,8 @@ namespace MetaData {
*
************************************************************************************/
JS2Class::JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final)
JS2Class::JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final, const StringAtom &name)
: Frame(ClassKind),
instanceInitOrder(NULL),
complete(false),
@ -1455,8 +1841,25 @@ namespace MetaData {
primitive(false),
final(final),
call(NULL),
construct(NULL)
{ }
construct(JS2Engine::defaultConstructor),
name(name)
{
}
// examine the instancebinding map to determine the number of slots required
uint32 JS2Class::countSlots()
{
uint32 count = 0;
InstanceBindingIterator b, end;
for (b = instanceReadBindings.begin(), end = instanceReadBindings.end(); (b != end); b++) {
}
for (b = instanceWriteBindings.begin(), end = instanceWriteBindings.end(); (b != end); b++) {
}
}
/************************************************************************************
*

View File

@ -54,7 +54,7 @@ class Pond;
typedef void (Invokable)();
typedef Invokable Callor;
typedef JS2Object *(Constructor)();
typedef JS2Object *(Constructor)(JS2Engine *engine);
enum ObjectKind {
AttributeObjectKind,
@ -180,8 +180,6 @@ public:
Multiname(const StringAtom &name) : JS2Object(MultinameKind), name(name) { }
Multiname(const StringAtom &name, Namespace *ns) : JS2Object(MultinameKind), name(name) { addNamespace(ns); }
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);
void addNamespace(Context &cxt);
@ -294,38 +292,64 @@ public:
StaticMember *content; // The member to which this qualified name was bound
};
class InstanceMember {
public:
enum InstanceMemberKind { InstanceVariableKind, InstanceMethodKind, InstanceAccessorKind };
InstanceMember(InstanceMemberKind kind, bool final) : kind(kind), final(final) { }
InstanceMemberKind kind;
bool final; // true if this member may not be overridden in subclasses
#ifdef DEBUG
virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function
#endif
};
class InstanceVariable : public InstanceMember {
public:
InstanceVariable(bool immutable, bool final) : InstanceMember(InstanceVariableKind, final), immutable(immutable) { }
JS2Class *type; // Type of values that may be stored in this variable
Invokable *evalInitialValue; // A function that computes this variable's initial value
bool immutable; // true if this variable's value may not be changed once set
bool final;
};
class InstanceMethod : public InstanceMember {
public:
InstanceMethod() : InstanceMember(InstanceMethodKind, false) { }
Signature type; // This method's signature
Invokable *code; // This method itself (a callable object); null if this method is abstract
};
class InstanceAccessor : public InstanceMember {
public:
InstanceAccessor(Invokable *code, bool final) : InstanceMember(InstanceAccessorKind, final), code(code) { }
JS2Class *type; // The type of the value read from the getter or written into the setter
Invokable *code; // A callable object which does the read or write; null if this method is abstract
};
class InstanceBinding {
public:
InstanceBinding(QualifiedName &qname, InstanceMember *content) : qname(qname), content(content) { }
QualifiedName qname; // The qualified name bound by this binding
InstanceMember *content; // The member to which this qualified name was bound
};
// Override status is used to resolve overriden definitions for instance members
class OverrideStatus {
public:
OverrideStatus(InstanceMember *overriddenMember, const StringAtom &name)
: overriddenMember(overriddenMember), potentialConflict(false), multiname(name) { }
InstanceMember *overriddenMember; // NULL for none
bool potentialConflict;
Multiname multiname;
};
typedef std::pair<OverrideStatus *, OverrideStatus *> OverrideStatusPair;
// A StaticBindingMap maps names to a list of StaticBindings. Each StaticBinding in the list
// will have the same QualifiedName.name, but (potentially) different QualifiedName.namespace values
@ -353,9 +377,9 @@ public:
class JS2Class : public Frame {
public:
JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final);
JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final, const StringAtom &name);
StringAtom &getName();
const StringAtom &getName() { return name; }
InstanceBindingMap instanceReadBindings; // Map of qualified names to readable instance members defined in this class
InstanceBindingMap instanceWriteBindings; // Map of qualified names to writable instance members defined in this class
@ -376,6 +400,10 @@ public:
Callor *call; // A procedure to call when this class is used in a call expression
Constructor *construct; // A procedure to call when this class is used in a new expression
uint32 countSlots();
const StringAtom &name;
};
class GlobalObject : public Frame {
@ -397,13 +425,13 @@ public:
// Instances of non-dynamic classes are represented as FIXEDINSTANCE records. These instances can contain only fixed properties.
class FixedInstance : public JS2Object {
public:
FixedInstance() : JS2Object(FixedInstanceKind), typeofString(type->getName()) { }
FixedInstance(JS2Class *type) : JS2Object(FixedInstanceKind), 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
Invokable *construct; // A procedure to call when this instance is used in a new expression
Environment *env; // The environment to pass to the call or construct procedure
StringAtom &typeofString; // A string to return if typeof is invoked on this instance
const StringAtom &typeofString; // A string to return if typeof is invoked on this instance
Slot *slots; // A set of slots that hold this instance's fixed property values
};
@ -416,7 +444,7 @@ public:
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
Environment *env; // The environment to pass to the call or construct procedure
StringAtom &typeofString; // A string to return if typeof is invoked on this instance
const StringAtom &typeofString; // A string to return if typeof is invoked on this instance
Slot *slots; // A set of slots that hold this instance's fixed property values
DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties
};
@ -438,7 +466,8 @@ public:
// Base class for all references (lvalues)
// References are generated during the eval stage (bytecode generation)
// References are generated during the eval stage (bytecode generation), but shouldn't live beyond that
// XXX use an arena new/delete. (N.B. the contained multinames make it into the bytecode stream)
class Reference {
public:
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { ASSERT(false); }
@ -460,10 +489,9 @@ public:
Environment *env; // The environment in which the reference was created.
bool strict; // The strict setting from the context in effect at the point where the reference was created
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); }
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalRead, pos); bCon->addMultiname(variableMultiname); }
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eLexicalWrite, pos); bCon->addMultiname(variableMultiname); }
};
class DotReference : public Reference {
@ -471,13 +499,18 @@ class DotReference : public Reference {
// object with one of a given set of qualified names. DOTREFERENCE tuples arise from evaluating subexpressions such as a.b or
// a.q::b.
public:
js2val base; // The object whose property was referenced (a in the examples above). The
DotReference(const StringAtom &name) : propertyMultiname(new Multiname(name)) { }
DotReference(Multiname *mn) : propertyMultiname(mn) { }
// js2val base; // The object whose property was referenced (a in the examples above). The
// object may be a LIMITEDINSTANCE if a is a super expression, in which case
// the property lookup will be restricted to members defined in proper ancestors
// of base.limit.
Multiname propertyMultiname; // A nonempty set of qualified names to which this reference can refer (b
Multiname *propertyMultiname; // A nonempty set of qualified names to which this reference can refer (b
// qualified with the namespace q or all currently open namespaces in the
// example above)
virtual void emitReadBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotRead, pos); }
virtual void emitWriteBytecode(BytecodeContainer *bCon, size_t pos) { bCon->emitOp(eDotWrite, pos); }
};
@ -646,12 +679,17 @@ public:
void defineHoistedVar(Environment *env, const StringAtom &id, StmtNode *p);
void defineStaticMember(Environment *env, const StringAtom &id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, StaticMember *m, size_t pos);
OverrideStatusPair defineInstanceMember(JS2Class *c, Context *cxt, const StringAtom &id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, InstanceMember *m, size_t pos);
OverrideStatus *resolveOverrides(JS2Class *c, Context *cxt, const StringAtom &id, NamespaceList *namespaces, Access access, bool expectMethod, size_t pos);
OverrideStatus *searchForOverrides(JS2Class *c, const StringAtom &id, NamespaceList *namespaces, Access access, size_t pos);
InstanceMember *findInstanceMember(JS2Class *c, QualifiedName *qname, Access access);
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(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval);
bool readStaticMember(StaticMember *m, Phase phase, js2val *rval);
bool readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval);
bool writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase);
@ -684,6 +722,9 @@ public:
JS2Class *objectClass;
JS2Class *namespaceClass;
JS2Class *classClass;
JS2Class *packageClass;
JS2Class *prototypeClass;
JS2Class *attributeClass;
Parser *mParser; // used for error reporting

View File

@ -31,51 +31,53 @@
* 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);
mn->addNamespace(meta->cxt);
push(OBJECT_TO_JS2VAL(mn));
}
break;
// Get a multiname literal and push the resulting multiname object
case eMultiname:
{
push(OBJECT_TO_JS2VAL(mn));
}
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);
retval = meta->env.lexicalRead(meta, mn, phase);
push(retval);
}
break;
case eDotRead:
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
js2val baseVal = pop();
readProperty
}
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);
meta->env.lexicalWrite(meta, mn, retval, true, phase);
push(retval);
}
break;
// Pop a multiname object and read it's value from the environment on to the stack.
case eLexicalRead:
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
retval = meta->env.lexicalRead(meta, mn, phase);
push(retval);
}
break;
case ePushFrame:
{
Frame *f = bCon->mFrameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
}
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:
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env.lexicalWrite(meta, mn, retval, true, phase);
push(retval);
}
break;
case ePopFrame:
{
}
break;
case ePushFrame:
{
Frame *f = bCon->mFrameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env.addFrame(f);
}
break;
case ePopFrame:
{
meta->env.removeTopFrame();
}
break;

View File

@ -34,7 +34,8 @@
case ePlus: {
case eAdd:
{
js2val a = pop();
js2val b = pop();
a = toPrimitive(a);
@ -55,3 +56,12 @@
}
break;
case eSubtract:
{
js2val a = pop();
js2val b = pop();
float64 anum = toNumber(a);
float64 bnum = toNumber(b);
retval = pushNumber(anum - bnum);
}
break;

View File

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
case eReturn:
{
retval = pop();
return retval;
}
break;
case eReturnVoid:
{
return retval;
}
break;
case eBranchTrue:
{
retval = pop();
ASSERT(JS2VAL_IS_BOOLEAN(retval));
bool b = JS2VAL_TO_BOOLEAN(retval);
if (b) {
int32 offset = BytecodeContainer::getShort(pc);
pc += offset;
}
else
pc += sizeof(int32);
}
break;
case eBranchFalse:
{
retval = pop();
ASSERT(JS2VAL_IS_BOOLEAN(retval));
bool b = JS2VAL_TO_BOOLEAN(retval);
if (!b) {
int32 offset = BytecodeContainer::getShort(pc);
pc += offset;
}
else
pc += sizeof(int32);
}
break;
case eBranch:
{
int32 offset = BytecodeContainer::getShort(pc);
pc += offset;
}
break;

View File

@ -33,18 +33,8 @@
*/
case eReturn: {
retval = pop();
return retval;
}
break;
case eReturnVoid: {
return retval;
}
break;
case eNewObject: {
case eNewObject: // XXX in js2op_literal instead?
{
uint16 argCount = BytecodeContainer::getShort(pc);
pc += sizeof(uint16);
PrototypeInstance *pInst = new PrototypeInstance(NULL); // XXX Object prototype object
@ -57,6 +47,28 @@
const DynamicPropertyMap::value_type e(nameAtom, fieldVal);
pInst->dynamicProperties.insert(e);
}
push(OBJECT_TO_JS2VAL(pInst));
retval = OBJECT_TO_JS2VAL(pInst);
push(retval);
}
break;
case eToBoolean:
{
js2val v = pop();
bool b = toBoolean(v);
retval = BOOLEAN_TO_JS2VAL(b);
push(retval);
}
break;
case eNew:
{
js2val v = top();
ASSERT(JS2VAL_IS_OBJECT(v) && !JS2VAL_IS_NULL(v));
JS2Object *obj = JS2VAL_TO_OBJECT(v);
ASSERT(obj->kind == ClassKind);
JS2Class *c = checked_cast<JS2Class *>(obj);
retval = OBJECT_TO_JS2VAL(c->construct(this));
push(retval);
}
break;