Fixed operator overloading for indexing operators.

This commit is contained in:
rogerl%netscape.com 2001-08-10 00:21:32 +00:00
parent d0f11628fb
commit 7251bbcce5
5 changed files with 316 additions and 144 deletions

View File

@ -31,7 +31,6 @@
* file under either the NPL or the GPL.
*/
#ifdef _WIN32
// Turn off warnings about identifiers too long in browser information
#pragma warning(disable: 4786)
@ -259,11 +258,19 @@ void PropertyReference::emitDelete(ByteCodeGen *bcg)
void ElementReference::emitCodeSequence(ByteCodeGen *bcg)
{
if (mAccess == Read)
bcg->addOp(GetElementOp);
bcg->addOpAdjustDepth(GetElementOp, -mDepth);
else
bcg->addOp(SetElementOp);
bcg->addOpAdjustDepth(SetElementOp, -(mDepth + 1));
bcg->addShort(mDepth);
}
void ElementReference::emitDelete(ByteCodeGen *bcg)
{
bcg->addOpAdjustDepth(DeleteElementOp, -mDepth);
bcg->addByte(mDepth);
}
ByteCodeData gByteCodeData[OpCodeCount] = {
{ 1, "LoadConstantUndefined", },
{ 1, "LoadConstantTrue", },
@ -325,8 +332,9 @@ ByteCodeData gByteCodeData[OpCodeCount] = {
{ 0, "SetLocalVar", },
{ 1, "GetClosureVar", },
{ 0, "SetClosureVar", },
{ -1, "GetElement", },
{ -2, "SetElement", },
{ -128, "GetElement", },
{ -128, "SetElement", },
{ -128, "DeleteElement" },
{ 0, "GetProperty", },
{ 1, "GetInvokeProperty", },
{ -1, "SetProperty", },
@ -343,8 +351,9 @@ ByteCodeData gByteCodeData[OpCodeCount] = {
};
ByteCodeModule::ByteCodeModule(ByteCodeGen *bcg)
ByteCodeModule::ByteCodeModule(ByteCodeGen *bcg, JSFunction *f)
{
mFunction = f;
mLength = bcg->mBuffer->size();
mCodeBase = new uint8[mLength];
memcpy(mCodeBase, bcg->mBuffer->begin(), mLength);
@ -569,7 +578,7 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
// otherwise, look for calls to the superclass by name
if (i->op->getKind() == ExprNode::identifier) {
const StringAtom &name = checked_cast<IdentifierExprNode *>(i->op)->name;
if (name == superClass->mClassName)
if (superClass->mClassName->compare(name) == 0)
foundSuperCall = true;
i->isSuperInvoke = true;
}
@ -628,7 +637,6 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
VariableBinding *v = f.parameters;
uint32 index = 0;
while (v) {
if (v->initializer) {
// this code gets executed if the function is called without
// an argument for this parameter.
@ -640,7 +648,7 @@ void ByteCodeGen::genCodeForFunction(FunctionDefinition &f, size_t pos, JSFuncti
v = v->next;
}
ByteCodeModule *bcm = new ByteCodeModule(this);
ByteCodeModule *bcm = new ByteCodeModule(this, fnc);
if (m_cx->mReader)
bcm->setSource(m_cx->mReader->source, m_cx->mReader->sourceLocation);
fnc->setByteCode(bcm);
@ -656,14 +664,14 @@ ByteCodeModule *ByteCodeGen::genCodeForScript(StmtNode *p)
genCodeForStatement(p, NULL, NotALabel);
p = p->next;
}
return new ByteCodeModule(this);
return new ByteCodeModule(this, NULL);
}
ByteCodeModule *ByteCodeGen::genCodeForExpression(ExprNode *p)
{
genExpr(p);
addOp(PopOp);
return new ByteCodeModule(this);
return new ByteCodeModule(this, NULL);
}
@ -693,7 +701,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
// build a function to be invoked
// when the class is loaded
f = new JSFunction(Void_Type, mScopeChain);
ByteCodeModule *bcm = new ByteCodeModule(&static_cg);
ByteCodeModule *bcm = new ByteCodeModule(&static_cg, NULL);
if (m_cx->mReader)
bcm->setSource(m_cx->mReader->source, m_cx->mReader->sourceLocation);
f->setByteCode(bcm);
@ -703,7 +711,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
if (bcg.hasContent()) {
// execute this function now to form the initial instance
f = new JSFunction(Void_Type, mScopeChain);
ByteCodeModule *bcm = new ByteCodeModule(&bcg);
ByteCodeModule *bcm = new ByteCodeModule(&bcg, NULL);
if (m_cx->mReader)
bcm->setSource(m_cx->mReader->source, m_cx->mReader->sourceLocation);
f->setByteCode(bcm);
@ -767,7 +775,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
JSFunction *fnc = f->mFunction;
ASSERT(f->function.name);
if (mScopeChain->topClass() && (mScopeChain->topClass()->mClassName.compare(*f->function.name) == 0))
if (mScopeChain->topClass() && (mScopeChain->topClass()->mClassName->compare(*f->function.name) == 0))
isConstructor = true;
ByteCodeGen bcg(m_cx, mScopeChain);
bcg.genCodeForFunction(f->function, f->pos, fnc, isConstructor, mScopeChain->topClass());
@ -1137,6 +1145,16 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3
ExprStmtNode *e = checked_cast<ExprStmtNode *>(p);
if (e->expr) {
genExpr(e->expr);
JSFunction *container = mScopeChain->getContainerFunction();
if (container) {
if (container->getResultType() != Object_Type) {
addOp(LoadTypeOp);
addPointer(container->getResultType());
addOp(CastOp);
}
}
ASSERT(mStackTop == 1);
addOpSetDepth(ReturnOp, 0);
}
@ -1329,13 +1347,13 @@ Reference *ByteCodeGen::genReference(ExprNode *p, Access acc)
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
genExpr(i->op);
ExprPairList *p = i->pairs;
int32 argCount = 0;
uint16 dimCount = 0;
while (p) {
genExpr(p->value);
argCount++;
dimCount++;
p = p->next;
}
Reference *ref = new ElementReference(acc, argCount);
Reference *ref = new ElementReference(acc, dimCount);
return ref;
}
case ExprNode::identifier:
@ -1430,14 +1448,14 @@ void ByteCodeGen::genReferencePair(ExprNode *p, Reference *&readRef, Reference *
InvokeExprNode *i = checked_cast<InvokeExprNode *>(p);
genExpr(i->op);
ExprPairList *p = i->pairs;
int32 argCount = 0;
uint16 dimCount = 0;
while (p) {
genExpr(p->value);
argCount++;
dimCount++;
p = p->next;
}
readRef = new ElementReference(Read, argCount);
writeRef = new ElementReference(Write, argCount);
readRef = new ElementReference(Read, dimCount);
writeRef = new ElementReference(Write, dimCount);
}
break;
case ExprNode::dot:
@ -1637,12 +1655,11 @@ PreXcrement:
Reference *readRef;
Reference *writeRef;
genReferencePair(u->op, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1674,12 +1691,11 @@ PostXcrement:
Reference *readRef;
Reference *writeRef;
genReferencePair(u->op, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1687,7 +1703,7 @@ PostXcrement:
// duplicate the value and bury it
if (baseDepth > 1) {
addOpAdjustDepth(DupInsertNOp, baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupInsertOp);
@ -1746,12 +1762,11 @@ BinaryOpEquals:
Reference *writeRef;
genReferencePair(b->op1, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOp(DupNOp);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1783,12 +1798,11 @@ BinaryOpEquals:
Reference *writeRef;
genReferencePair(b->op1, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1825,12 +1839,11 @@ BinaryOpEquals:
Reference *writeRef;
genReferencePair(b->op1, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1867,12 +1880,11 @@ BinaryOpEquals:
Reference *writeRef;
genReferencePair(b->op1, readRef, writeRef);
int32 baseDepth = readRef->baseExpressionDepth();
uint16 baseDepth = readRef->baseExpressionDepth();
if (baseDepth) { // duplicate the base expression
ASSERT(baseDepth <= MAX_UINT16);
if (baseDepth > 1) {
addOpAdjustDepth(DupNOp, -baseDepth);
addShort((uint16)baseDepth);
addShort(baseDepth);
}
else
addOp(DupOp);
@ -1978,11 +1990,17 @@ BinaryOpEquals:
}
case ExprNode::This:
{
JSFunction *f = mScopeChain->getContainerFunction();
JSType *theClass = mScopeChain->topClass();
// 'this' is legal in prototype functions
// and at the script top-level
if ( ((f == NULL) && theClass)
|| ((theClass == NULL) && f && !f->isPrototype()) )
m_cx->reportError(Exception::referenceError, "Illegal use of 'this'");
addOp(LoadThisOp);
JSType *theClass = mScopeChain->topClass();
if (theClass)
return theClass;
else // XXX need to be able to detect illegal references to 'this' in non-prototype, non-member functions
else
return Object_Type;
}
case ExprNode::dot:
@ -2142,7 +2160,8 @@ BinaryOpEquals:
addOp(LoadConstantNumberOp);
addNumberRef(index);
genExpr(e->value);
addOp(SetElementOp);
addOpAdjustDepth(SetElementOp, -2);
addShort(1);
addOp(PopOp);
}
index++;
@ -2315,8 +2334,6 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
case DupOp:
case DupInsertOp:
case PopOp:
case GetElementOp:
case SetElementOp:
case LoadGlobalObjectOp:
case NewClosureOp:
case ClassOp:
@ -2324,6 +2341,16 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
case NamedArgOp:
break;
case DeleteElementOp:
case GetElementOp:
case SetElementOp:
{
uint16 u = bcm.getShort(i);
printFormat(f, "%uh", i);
i += 2;
}
break;
case DoUnaryOp:
case DoOperatorOp:
f << bcm.mCodeBase[i];
@ -2332,8 +2359,11 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm)
case DupNOp:
case DupInsertNOp:
f << bcm.getShort(i);
i += 2;
{
uint16 u = bcm.getShort(i);
printFormat(f, "%uh", i);
i += 2;
}
break;
case JumpOp:

View File

@ -135,8 +135,9 @@ typedef enum {
GetClosureVarOp, // <depth>, <index> --> <object>
SetClosureVarOp, // <depth>, <index> <object> --> <object>
// for array elements
GetElementOp, // <base> <index> --> <object>
SetElementOp, // <base> <index> <object> --> <object>
GetElementOp, // <dimcount> <base> <index> ... <index> --> <object>
SetElementOp, // <dimcount> <base> <index> ...<index> <object> --> <object>
DeleteElementOp, // <dimcount> <base> <index> ... <index> --> <boolean>
// for properties
GetPropertyOp, // <poolindex> <base> --> <object>
GetInvokePropertyOp, // <poolindex> <base> --> <base> <object>
@ -169,7 +170,7 @@ extern ByteCodeData gByteCodeData[OpCodeCount];
class ByteCodeModule {
public:
ByteCodeModule(ByteCodeGen *bcg);
ByteCodeModule(ByteCodeGen *bcg, JSFunction *f);
#ifdef DEBUG
void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeModule", s, t); return t; }
@ -188,6 +189,8 @@ extern ByteCodeData gByteCodeData[OpCodeCount];
mSourceLocation = sourceLocation;
}
JSFunction *mFunction;
String mSource;
String mSourceLocation;
@ -337,16 +340,13 @@ extern ByteCodeData gByteCodeData[OpCodeCount];
{ addByte(op); mStackTop = depth; ASSERT(mStackTop >= 0); }
void addByte(uint8 v) { mBuffer->push_back(v); }
void addShort(uint16 v) { mBuffer->push_back((uint8)(v >> 8)); mBuffer->push_back((uint8)(v)); }
void addShort(uint16 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); }
void addPointer(void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); } // XXX Pointer size dependant !!!
void addLong(uint32 v)
{ mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
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; } // XXX
void addLong(uint32 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); }
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; } // XXX dubious pointer usage
void addFixup(uint32 label)
{

View File

@ -215,6 +215,7 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha
return result;
}
// Assumes arguments are on the top of stack.
JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount)
{
JSValue *argBase;
@ -334,7 +335,19 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
mPC = pc;
try {
if (mDebugFlag) {
printFormat(stdOut, " %d ", stackSize());
if (mCurModule->mFunction) {
FunctionName *fnName = mCurModule->mFunction->getFunctionName();
StringFormatter s;
PrettyPrinter pp(s);
fnName->print(pp);
const String &fnStr = s.getString();
std::string str(fnStr.length(), char());
std::transform(fnStr.begin(), fnStr.end(), str.begin(), narrow);
int len = strlen(str.c_str());
printFormat(stdOut, "%.30s+%.4d%*c%d ", str.c_str(), (pc - mCurModule->mCodeBase), (len > 30) ? 0 : (len - 30), ' ', stackSize());
}
else
printFormat(stdOut, "+%.4d%*c%d ", (pc - mCurModule->mCodeBase), 30, ' ', stackSize());
printInstruction(stdOut, toUInt32(pc - mCurModule->mCodeBase), *mCurModule);
}
switch ((ByteCodeOp)(*pc++)) {
@ -473,6 +486,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
uint32 cleanUp = argCount;
pc += sizeof(uint32);
CallFlag callFlags = (CallFlag)(*pc++);
mPC = pc;
JSValue *targetValue = getBase(stackSize() - (argCount + 1));
JSFunction *target;
@ -671,12 +685,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
pc += sizeof(uint32);
const String &name = *mCurModule->getString(index);
PropertyIterator it;
if (!obj->hasOwnProperty(name, CURRENT_ATTR, Read, &it))
pushValue(kTrueValue);
else {
if (obj->hasOwnProperty(name, CURRENT_ATTR, Read, &it))
obj->deleteProperty(name, CURRENT_ATTR);
pushValue(kTrueValue);
}
pushValue(kTrueValue);
}
break;
case TypeOfOp:
@ -803,30 +814,124 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
break;
case GetElementOp:
{
JSValue index = popValue();
JSValue base = popValue();
uint32 dimCount = *((uint16 *)pc);
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 1));
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (!base.isObject() && !base.isType())
obj = base.toObject(this).object;
if (!baseValue->isObject() && !baseValue->isType())
obj = baseValue->toObject(this).object;
else
obj = base.object;
const String *name = index.toString(this).string;
obj->getProperty(this, *name, CURRENT_ATTR);
obj = baseValue->object;
JSFunction *target = obj->getType()->getUnaryOperator(Index);
if (target) {
JSValue result;
if (target->isNative())
result = target->getNativeCode()(this, kNullValue, baseValue, dimCount + 1);
else {
uint32 argCount = dimCount + 1;
JSValue *argBase = buildArgumentBlock(target, argCount);
result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount);
}
resizeStack(stackSize() - (dimCount + 1));
pushValue(result);
}
else { // XXX or should this be implemented in Object_Type as operator "[]" ?
if (dimCount != 1)
reportError(Exception::typeError, "too many indices");
JSValue index = popValue();
popValue(); // discard base
const String *name = index.toString(this).string;
obj->getProperty(this, *name, CURRENT_ATTR);
}
}
break;
case SetElementOp:
{
JSValue v = popValue();
JSValue index = popValue();
JSValue base = popValue();
uint32 dimCount = *((uint16 *)pc);
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 2)); // +1 for assigned value
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (!base.isObject() && !base.isType())
obj = base.toObject(this).object;
if (!baseValue->isObject() && !baseValue->isType())
obj = baseValue->toObject(this).object;
else
obj = base.object;
const String *name = index.toString(this).string;
obj->setProperty(this, *name, CURRENT_ATTR, v);
pushValue(v);
obj = baseValue->object;
JSFunction *target = obj->getType()->getUnaryOperator(IndexEqual);
if (target) {
JSValue v = popValue(); // need to have this sitting right above the base value
insertValue(v, mStackTop - dimCount);
JSValue result;
if (target->isNative())
result = target->getNativeCode()(this, *baseValue, baseValue, (dimCount + 2));
else {
uint32 argCount = dimCount + 2;
JSValue *argBase = buildArgumentBlock(target, argCount);
result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount);
}
resizeStack(stackSize() - (dimCount + 2));
pushValue(result);
}
else { // XXX or should this be implemented in Object_Type as operator "[]=" ?
if (dimCount != 1)
reportError(Exception::typeError, "too many indices");
JSValue v = popValue();
JSValue index = popValue();
popValue(); // discard base
const String *name = index.toString(this).string;
obj->setProperty(this, *name, CURRENT_ATTR, v);
pushValue(v);
}
}
break;
case DeleteElementOp:
{
uint32 dimCount = *((uint16 *)pc);
pc += sizeof(uint16);
mPC = pc;
JSValue *baseValue = getBase(stackSize() - (dimCount + 1));
// Use the type of the base to dispatch on...
JSObject *obj = NULL;
if (!baseValue->isObject() && !baseValue->isType())
obj = baseValue->toObject(this).object;
else
obj = baseValue->object;
JSFunction *target = obj->getType()->getUnaryOperator(DeleteIndex);
if (target) {
JSValue result;
if (target->isNative())
result = target->getNativeCode()(this, kNullValue, baseValue, dimCount + 1);
else {
uint32 argCount = dimCount + 1;
JSValue *argBase = buildArgumentBlock(target, argCount);
result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount);
}
resizeStack(stackSize() - (dimCount + 1));
pushValue(result);
}
else { // XXX or should this be implemented in Object_Type as operator "delete[]" ?
if (dimCount != 1)
reportError(Exception::typeError, "too many indices");
JSValue index = popValue();
popValue(); // discard base
const String *name = index.toString(this).string;
PropertyIterator it;
if (obj->hasOwnProperty(*name, CURRENT_ATTR, Read, &it))
obj->deleteProperty(*name, CURRENT_ATTR);
pushValue(kTrueValue);
}
}
break;
case GetPropertyOp:
@ -839,6 +944,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
obj = base.object;
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
const String &name = *mCurModule->getString(index);
obj->getProperty(this, name, CURRENT_ATTR);
// if the result is a function of some kind, bind
@ -869,6 +975,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
const String &name = *mCurModule->getString(index);
@ -890,6 +997,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
obj = base.object;
uint32 index = *((uint32 *)pc);
pc += sizeof(uint32);
mPC = pc;
const String &name = *mCurModule->getString(index);
obj->setProperty(this, name, CURRENT_ATTR, v);
pushValue(v);
@ -898,6 +1006,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case DoUnaryOp:
{
Operator op = (Operator)(*pc++);
mPC = pc;
JSValue v = topValue();
JSFunction *target;
if (v.isObject() && (target = v.object->getType()->getUnaryOperator(op)) )
@ -936,7 +1045,6 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case Increment: // defined in terms of '+'
{
pushValue(JSValue(1.0));
mPC = pc;
if (executeOperator(Plus, v.getType(), Number_Type)) {
// need to invoke
pc = mCurModule->mCodeBase;
@ -951,7 +1059,6 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case Decrement: // defined in terms of '-'
{
pushValue(JSValue(1.0));
mPC = pc;
if (executeOperator(Minus, v.getType(), Number_Type)) {
// need to invoke
pc = mCurModule->mCodeBase;
@ -993,9 +1100,9 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case DoOperatorOp:
{
Operator op = (Operator)(*pc++);
mPC = pc;
JSValue v1 = getValue(stackSize() - 2);
JSValue v2 = getValue(stackSize() - 1);
mPC = pc;
if (executeOperator(op, v1.getType(), v2.getType())) {
// need to invoke
pc = mCurModule->mCodeBase;
@ -1017,8 +1124,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC)
case NewInstanceOp:
{
uint32 argCount = *((uint32 *)pc);
uint32 cleanUp = argCount;
pc += sizeof(uint32);
uint32 cleanUp = argCount;
JSValue *argBase = getBase(stackSize() - argCount);
bool isPrototypeFunctionCall = false;
@ -1829,7 +1936,7 @@ String *numberToString(float64 number)
JSValue JSValue::valueToString(Context *cx, const JSValue& value)
{
String *strp = NULL;
const String *strp = NULL;
JSObject *obj = NULL;
switch (value.tag) {
case f64_tag:
@ -1848,7 +1955,7 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value)
: new JavaScript::String(widenCString("false"));
break;
case type_tag:
strp = &value.type->mClassName;
strp = value.type->mClassName;
break;
case undefined_tag:
strp = new JavaScript::String(widenCString("undefined"));

View File

@ -284,7 +284,7 @@ Reference *JSObject::genReference(bool hasBase, const String& name, NamespaceLis
if (hasBase)
return new PropertyReference(name, acc, prop->mType, prop->mAttributes);
else
return new NameReference(name, acc);
return new NameReference(name, acc, prop->mType, prop->mAttributes);
case FunctionPair:
if (acc == Read)
return new GetterFunctionReference(prop->mData.fPair.getterF, prop->mAttributes);
@ -705,8 +705,10 @@ JSType *ScopeChain::findType(const StringAtom& typeName, size_t pos)
else {
// Allow finding a function that has the same name as it's containing class
// i.e. the default constructor.
if (v.isFunction() && v.function->getClass()
&& (v.function->getClass()->mClassName.compare(v.function->getFunctionName()) == 0))
FunctionName *fnName = v.function->getFunctionName();
if ((fnName->prefix == FunctionName::normal)
&& v.isFunction() && v.function->getClass()
&& (v.function->getClass()->mClassName->compare(*fnName->name) == 0))
return v.function->getClass();
m_cx->reportError(Exception::semanticError, "Unknown type", pos);
return NULL;
@ -793,16 +795,16 @@ void ScopeChain::collectNames(StmtNode *p)
case StmtNode::Class:
{
ClassStmtNode *classStmt = checked_cast<ClassStmtNode *>(p);
const StringAtom& name = classStmt->name;
const StringAtom *name = &classStmt->name;
JSType *thisClass = new JSType(name, NULL);
m_cx->setAttributeValue(classStmt, 0); // XXX default attribute for a class?
PropertyIterator it;
if (hasProperty(name, NULL, Read, &it))
if (hasProperty(*name, NULL, Read, &it))
m_cx->reportError(Exception::referenceError, "Duplicate class definition", p->pos);
defineVariable(m_cx, name, classStmt, Type_Type, JSValue(thisClass));
defineVariable(m_cx, *name, classStmt, Type_Type, JSValue(thisClass));
classStmt->mType = thisClass;
}
break;
@ -858,6 +860,8 @@ void ScopeChain::collectNames(StmtNode *p)
VariableStmtNode *vs = checked_cast<VariableStmtNode *>(p);
VariableBinding *v = vs->bindings;
m_cx->setAttributeValue(vs, Property::Final);
if (p->getKind() == StmtNode::Const)
vs->attributeValue->mTrueFlags |= Property::Const;
bool isStatic = (vs->attributeValue->mTrueFlags & Property::Static) == Property::Static;
while (v) {
@ -873,7 +877,6 @@ void ScopeChain::collectNames(StmtNode *p)
{
FunctionStmtNode *f = checked_cast<FunctionStmtNode *>(p);
m_cx->setAttributeValue(f, Property::Virtual);
f->attributeValue->mTrueFlags |= Property::Const;
bool isStatic = (f->attributeValue->mTrueFlags & Property::Static) == Property::Static;
bool isConstructor = (f->attributeValue->mTrueFlags & Property::Constructor) == Property::Constructor;
@ -909,6 +912,7 @@ void ScopeChain::collectNames(StmtNode *p)
JSFunction *fnc = new JSFunction(NULL, this);
fnc->setIsPrototype(isPrototype);
fnc->setIsConstructor(isConstructor);
fnc->setFunctionName(&f->function);
f->mFunction = fnc;
uint32 reqArgCount = 0;
@ -930,7 +934,6 @@ void ScopeChain::collectNames(StmtNode *p)
}
else {
const StringAtom& name = *f->function.name;
fnc->setFunctionName(name);
if (topClass())
fnc->setClass(topClass());
@ -940,7 +943,7 @@ void ScopeChain::collectNames(StmtNode *p)
// sort of want to fall into the code below, but use 'extendedClass' instead
// of whatever the topClass will turn out to be.
if (extendedClass->mClassName.compare(name) == 0) {
if (extendedClass->mClassName->compare(name) == 0) {
isConstructor = true; // can you add constructors?
fnc->setIsConstructor(true);
}
@ -961,6 +964,7 @@ void ScopeChain::collectNames(StmtNode *p)
extendedClass->defineSetterMethod(m_cx, name, f, fnc);
break;
case FunctionName::normal:
f->attributeValue->mTrueFlags |= Property::Const;
if (isStatic)
extendedClass->defineStaticMethod(m_cx, name, f, fnc);
else
@ -973,7 +977,7 @@ void ScopeChain::collectNames(StmtNode *p)
}
}
else {
if (topClass() && (topClass()->mClassName.compare(name) == 0)) {
if (topClass() && (topClass()->mClassName->compare(name) == 0)) {
isConstructor = true;
fnc->setIsConstructor(true);
}
@ -995,6 +999,7 @@ void ScopeChain::collectNames(StmtNode *p)
defineSetterMethod(m_cx, name, f, fnc);
break;
case FunctionName::normal:
f->attributeValue->mTrueFlags |= Property::Const;
if (isStatic)
defineStaticMethod(m_cx, name, f, fnc);
else
@ -1030,7 +1035,10 @@ void JSType::completeClass(Context *cx, ScopeChain *scopeChain)
if (getDefaultConstructor() == NULL) {
JSFunction *fnc = new JSFunction(Object_Type, scopeChain);
fnc->setIsConstructor(true);
fnc->setFunctionName(mClassName);
FunctionName *fnName = new FunctionName();
fnName->name = mClassName; //cx->mWorld.identifiers[mClassName];
fnName->prefix = FunctionName::normal;
fnc->setFunctionName(fnName);
fnc->setClass(this);
ByteCodeGen bcg(cx, scopeChain);
@ -1050,12 +1058,12 @@ void JSType::completeClass(Context *cx, ScopeChain *scopeChain)
bcg.addOp(LoadThisOp);
ASSERT(bcg.mStackTop == 1);
bcg.addOpSetDepth(ReturnOp, 0);
ByteCodeModule *bcm = new JS2Runtime::ByteCodeModule(&bcg);
ByteCodeModule *bcm = new JS2Runtime::ByteCodeModule(&bcg, fnc);
if (cx->mReader)
bcm->setSource(cx->mReader->source, cx->mReader->sourceLocation);
fnc->setByteCode(bcm);
scopeChain->defineConstructor(cx, mClassName, NULL, fnc); // XXX attributes?
scopeChain->defineConstructor(cx, *mClassName, NULL, fnc); // XXX attributes?
}
}
@ -1065,7 +1073,7 @@ void JSType::completeClass(Context *cx, ScopeChain *scopeChain)
JSFunction *JSType::getDefaultConstructor()
{
PropertyIterator it;
if (hasOwnProperty(mClassName, NULL, Read, &it)) {
if (hasOwnProperty(*mClassName, NULL, Read, &it)) {
ASSERT(PROPERTY_KIND(it) == ValuePointer);
JSValue c = *PROPERTY_VALUEPOINTER(it);
ASSERT(c.isFunction());
@ -1221,7 +1229,7 @@ Reference *JSType::genReference(bool hasBase, const String& name, NamespaceList
return NULL;
}
JSType::JSType(const String &name, JSType *super)
JSType::JSType(const StringAtom *name, JSType *super)
: JSObject(Type_Type),
mSuperType(super),
mVariableCount(0),
@ -1246,6 +1254,7 @@ JSType::JSType(JSType *xClass) // used for constructing the static component
mSuperType(xClass),
mVariableCount(0),
mInstanceInitializer(NULL),
mClassName(NULL),
mIsDynamic(false),
mUninitializedValue(kNullValue),
mPrototypeObject(NULL)
@ -1308,7 +1317,7 @@ Reference *Activation::genReference(bool /* hasBase */, const String& name, Name
return new LocalVarReference(prop->mData.index, acc, prop->mType, prop->mAttributes);
case ValuePointer:
return new NameReference(name, acc);
return new NameReference(name, acc, prop->mType, prop->mAttributes);
default:
NOT_REACHED("bad genRef call");
@ -1432,10 +1441,10 @@ void Context::buildRuntimeForStmt(StmtNode *p)
fnc->setResultType(resultType);
VariableBinding *v = f->function.parameters;
uint32 index = 0;
uint32 parameterCount = 0;
while (v) {
// XXX if no type is specified for the rest parameter - is it Array?
fnc->setArgument(index++, v->name, mScopeChain->extractType(v->type));
fnc->setArgument(parameterCount++, v->name, mScopeChain->extractType(v->type));
v = v->next;
}
@ -1445,11 +1454,16 @@ void Context::buildRuntimeForStmt(StmtNode *p)
}
ASSERT(f->function.name);
const StringAtom& name = *f->function.name;
Operator op = getOperator(getParameterCount(f->function), name);
Operator op = getOperator(parameterCount, name);
// if it's a unary operator, it just gets added
// as a method with a special name. Binary operators
// get added to the Context's operator table.
if (getParameterCount(f->function) == 1)
// The indexing operators are considered unary since
// they only dispatch on the base type.
if ((parameterCount == 1)
|| (op == Index)
|| (op == IndexEqual)
|| (op == DeleteIndex))
mScopeChain->defineUnaryOperator(op, fnc);
else
defineOperator(op, getParameterType(f->function, 0),
@ -1756,21 +1770,21 @@ void Context::initBuiltins()
{ "NamedArgument", NULL, &kNullValue },
};
Object_Type = new JSType(widenCString(builtInClasses[0].name), NULL);
Object_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL);
Object_Type->mIsDynamic = true;
// XXX aren't all the built-ins thus?
Type_Type = new JSType(widenCString(builtInClasses[1].name), Object_Type);
Function_Type = new JSType(widenCString(builtInClasses[2].name), Object_Type);
Number_Type = new JSType(widenCString(builtInClasses[3].name), Object_Type);
Integer_Type = new JSType(widenCString(builtInClasses[4].name), Object_Type);
String_Type = new JSStringType(widenCString(builtInClasses[5].name), Object_Type);
Array_Type = new JSArrayType(widenCString(builtInClasses[6].name), Object_Type);
Boolean_Type = new JSType(widenCString(builtInClasses[7].name), Object_Type);
Void_Type = new JSType(widenCString(builtInClasses[8].name), Object_Type);
Unit_Type = new JSType(widenCString(builtInClasses[9].name), Object_Type);
Attribute_Type = new JSType(widenCString(builtInClasses[10].name), Object_Type);
NamedArgument_Type = new JSType(widenCString(builtInClasses[11].name), Object_Type);
Type_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[1].name)], Object_Type);
Function_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type);
Number_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type);
Integer_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[4].name)], Object_Type);
String_Type = new JSStringType(&mWorld.identifiers[widenCString(builtInClasses[5].name)], Object_Type);
Array_Type = new JSArrayType(&mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type);
Boolean_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[7].name)], Object_Type);
Void_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[8].name)], Object_Type);
Unit_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[9].name)], Object_Type);
Attribute_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[10].name)], Object_Type);
NamedArgument_Type = new JSType(&mWorld.identifiers[widenCString(builtInClasses[11].name)], Object_Type);
String_Type->defineVariable(this, widenCString("fromCharCode"), NULL, String_Type, JSValue(new JSFunction(String_fromCharCode, String_Type)));
@ -1841,7 +1855,7 @@ struct OperatorInitData {
{ "new", JS2Runtime::New, },
{ "[]", JS2Runtime::Index, },
{ "[]=", JS2Runtime::IndexEqual, },
{ "delete []", JS2Runtime::DeleteIndex, },
{ "delete[]", JS2Runtime::DeleteIndex, },
{ "+", JS2Runtime::Plus, },
{ "-", JS2Runtime::Minus, },
{ "*", JS2Runtime::Multiply, },
@ -2052,8 +2066,12 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
f << "null";
break;
case JSValue::function_tag:
if (!value.function->isNative())
f << "function '" << value.function->getFunctionName() << "'\n" << *value.function->getByteCode();
if (!value.function->isNative()) {
StringFormatter s;
PrettyPrinter pp(s);
value.function->getFunctionName()->print(pp);
f << "function '" << s.getString() << "'\n" << *value.function->getByteCode();
}
else
f << "function\n";
break;

View File

@ -312,7 +312,7 @@ XXX ...couldn't get this to work...
{ throw Exception(Exception::internalError, "gen code for base ref"); }
// returns the amount of stack used by the reference
virtual int32 baseExpressionDepth() { return 0; }
virtual uint16 baseExpressionDepth() { return 0; }
// generate code sequence for typeof operator
virtual void emitTypeOf(ByteCodeGen *bcg);
@ -359,7 +359,7 @@ XXX ...couldn't get this to work...
uint32 mIndex;
void emitCodeSequence(ByteCodeGen *bcg);
void emitImplicitLoad(ByteCodeGen *bcg);
int32 baseExpressionDepth() { return 1; }
uint16 baseExpressionDepth() { return 1; }
};
// a static field
class StaticFieldReference : public Reference {
@ -372,7 +372,7 @@ XXX ...couldn't get this to work...
void emitCodeSequence(ByteCodeGen *bcg);
void emitInvokeSequence(ByteCodeGen *bcg);
void emitImplicitLoad(ByteCodeGen *bcg);
int32 baseExpressionDepth() { return 1; }
uint16 baseExpressionDepth() { return 1; }
};
// a member function in a vtable
class MethodReference : public Reference {
@ -384,7 +384,7 @@ XXX ...couldn't get this to work...
void emitCodeSequence(ByteCodeGen *bcg);
virtual bool needsThis() { return true; }
virtual void emitImplicitLoad(ByteCodeGen *bcg);
virtual int32 baseExpressionDepth() { return 1; }
virtual uint16 baseExpressionDepth() { return 1; }
void emitInvokeSequence(ByteCodeGen *bcg);
};
class GetterMethodReference : public MethodReference {
@ -433,7 +433,7 @@ XXX ...couldn't get this to work...
const String& mName;
void emitCodeSequence(ByteCodeGen *bcg);
void emitInvokeSequence(ByteCodeGen *bcg);
int32 baseExpressionDepth() { return 1; }
uint16 baseExpressionDepth() { return 1; }
bool needsThis() { return true; }
void emitImplicitLoad(ByteCodeGen *bcg);
void emitDelete(ByteCodeGen *bcg);
@ -454,6 +454,8 @@ XXX ...couldn't get this to work...
public:
NameReference(const String& name, Access acc)
: Reference(Object_Type, 0), mAccess(acc), mName(name) { }
NameReference(const String& name, Access acc, JSType *type, PropertyAttribute attr)
: Reference(type, attr), mAccess(acc), mName(name) { }
Access mAccess;
const String& mName;
void emitCodeSequence(ByteCodeGen *bcg);
@ -463,12 +465,13 @@ XXX ...couldn't get this to work...
class ElementReference : public Reference {
public:
ElementReference(Access acc, int32 depth)
ElementReference(Access acc, uint16 depth)
: Reference(Object_Type, 0), mAccess(acc), mDepth(depth) { }
Access mAccess;
int32 mDepth;
uint16 mDepth;
void emitCodeSequence(ByteCodeGen *bcg);
int32 baseExpressionDepth() { return mDepth; }
uint16 baseExpressionDepth() { return mDepth; }
void emitDelete(ByteCodeGen *bcg);
};
@ -571,8 +574,9 @@ XXX ...couldn't get this to work...
virtual Reference *genReference(bool hasBase, const String& name, NamespaceList *names, Access acc, uint32 depth);
virtual JSType *topClass() { return NULL; }
virtual bool isNestedFunction() { return false; }
virtual JSType *topClass() { return NULL; }
virtual bool isNestedFunction() { return false; }
virtual JSFunction *getContainerFunction() { return NULL; }
virtual bool hasLocalVars() { return false; }
virtual uint32 localVarCount() { return 0; }
@ -674,7 +678,7 @@ XXX ...couldn't get this to work...
class JSType : public JSObject {
public:
JSType(const String &name, JSType *super);
JSType(const StringAtom *name, JSType *super);
JSType(JSType *xClass); // used for constructing the static component type
virtual ~JSType() { } // keeping gcc happy
@ -724,12 +728,12 @@ XXX ...couldn't get this to work...
JSFunction *getUnaryOperator(Operator which)
{
return mUnaryOperators[which];
return mUnaryOperators[which]; // XXX Umm, aren't these also getting inherited?
}
void setDefaultConstructor(Context *cx, JSFunction *f)
{
defineConstructor(cx, mClassName, NULL, f); // XXX attr?
defineConstructor(cx, *mClassName, NULL, f); // XXX attr?
}
void addMethod(Context *cx, const String &name, AttributeStmtNode *attr, JSFunction *f);
@ -762,8 +766,8 @@ XXX ...couldn't get this to work...
JSFunction *mInstanceInitializer;
// the 'vtable'
MethodList mMethods;
String mClassName;
MethodList mMethods;
const StringAtom *mClassName;
JSFunction *mUnaryOperators[OperatorCount]; // XXX too wasteful
@ -799,7 +803,7 @@ XXX ...couldn't get this to work...
class JSArrayType : public JSType {
public:
JSArrayType(const String &name, JSType *super)
JSArrayType(const StringAtom *name, JSType *super)
: JSType(name, super)
{
}
@ -833,7 +837,7 @@ XXX ...couldn't get this to work...
class JSStringType : public JSType {
public:
JSStringType(const String &name, JSType *super)
JSStringType(const StringAtom *name, JSType *super)
: JSType(name, super)
{
}
@ -894,7 +898,8 @@ XXX ...couldn't get this to work...
mStack(NULL),
mStackTop(0),
mPC(0),
mModule(NULL) { }
mModule(NULL),
mContainer(NULL) { }
Activation(JSValue *locals,
JSValue *stack, uint32 stackTop,
@ -910,7 +915,8 @@ XXX ...couldn't get this to work...
mArgumentBase(argBase),
mThis(curThis),
mPC(pc),
mModule(module) { }
mModule(module),
mContainer(NULL) { }
virtual ~Activation() { } // keeping gcc happy
@ -938,6 +944,9 @@ XXX ...couldn't get this to work...
JSValue mThis;
uint8 *mPC;
ByteCodeModule *mModule;
JSFunction *mContainer;
virtual JSFunction *getContainerFunction() { return mContainer; }
bool hasLocalVars() { return true; }
@ -1067,6 +1076,12 @@ XXX ...couldn't get this to work...
return obj->topClass();
}
JSFunction *getContainerFunction()
{
JSObject *obj = mScopeStack.back();
return (obj->getContainerFunction());
}
// return 'true' if the current top of scope stack is an
// activation - which would make any function declarations
// be local declarations.
@ -1130,7 +1145,7 @@ XXX ...couldn't get this to work...
class JSFunction : public JSObject {
protected:
JSFunction() : JSObject(Function_Type), mActivation() { mPrototype = Function_Type->mPrototypeObject; } // for JSBoundFunction (XXX ask Patrick about this structure)
JSFunction() : JSObject(Function_Type), mActivation() { mActivation.mContainer = this; mPrototype = Function_Type->mPrototypeObject; } // for JSBoundFunction (XXX ask Patrick about this structure)
public:
class ArgumentData {
@ -1168,6 +1183,7 @@ XXX ...couldn't get this to work...
mScopeChain = new ScopeChain(*scopeChain);
}
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
}
JSFunction(NativeCode *code, JSType *resultType)
@ -1189,6 +1205,7 @@ XXX ...couldn't get this to work...
mClass(NULL)
{
mPrototype = Function_Type->mPrototypeObject;
mActivation.mContainer = this;
}
~JSFunction() { } // keeping gcc happy
@ -1209,7 +1226,7 @@ XXX ...couldn't get this to work...
void setIsPrototype(bool i) { mIsPrototype = i; }
void setIsConstructor(bool i) { mIsConstructor = i; }
void setIsUnchecked() { mIsChecked = false; }
void setFunctionName(const String &n) { mFunctionName = n; }
void setFunctionName(FunctionName *n) { mFunctionName = n; }
void setClass(JSType *c) { mClass = c; }
virtual bool hasBoundThis() { return false; }
@ -1226,7 +1243,7 @@ XXX ...couldn't get this to work...
virtual ScopeChain *getScopeChain() { return mScopeChain; }
virtual JSValue getThisValue() { return kNullValue; }
virtual JSType *getClass() { return mClass; }
virtual String &getFunctionName() { return mFunctionName; }
virtual FunctionName *getFunctionName() { return mFunctionName; }
virtual uint32 findParameterName(const String *name);
virtual uint32 getRequiredArgumentCount()
{ return mRequiredArgs; }
@ -1259,7 +1276,7 @@ XXX ...couldn't get this to work...
bool mHasRestParameter;
const String *mRestParameterName;
JSType *mClass; // pointer to owning class if this function is a method
String mFunctionName;
FunctionName *mFunctionName;
};
class JSBoundFunction : public JSFunction {
@ -1287,7 +1304,7 @@ XXX ...couldn't get this to work...
ScopeChain *getScopeChain() { return mFunction->getScopeChain(); }
JSValue getThisValue() { return (mThis) ? JSValue(mThis) : kNullValue; }
JSType *getClass() { return mFunction->getClass(); }
String &getFunctionName() { return mFunction->getFunctionName(); }
FunctionName *getFunctionName() { return mFunction->getFunctionName(); }
uint32 findParameterName(const String *name)
{ return mFunction->findParameterName(name); }
uint32 getRequiredArgumentCount()