mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Fixed operator overloading for indexing operators.
This commit is contained in:
parent
d0f11628fb
commit
7251bbcce5
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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"));
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user