diff --git a/js2/src/bytecodegen.cpp b/js2/src/bytecodegen.cpp index 03d75fab7337..56071e08e325 100644 --- a/js2/src/bytecodegen.cpp +++ b/js2/src/bytecodegen.cpp @@ -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(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(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(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(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: diff --git a/js2/src/bytecodegen.h b/js2/src/bytecodegen.h index 7093262f3d62..bdd19eb681eb 100644 --- a/js2/src/bytecodegen.h +++ b/js2/src/bytecodegen.h @@ -135,8 +135,9 @@ typedef enum { GetClosureVarOp, // , --> SetClosureVarOp, // , --> // for array elements - GetElementOp, // --> - SetElementOp, // --> + GetElementOp, // ... --> + SetElementOp, // ... --> + DeleteElementOp, // ... --> // for properties GetPropertyOp, // --> GetInvokePropertyOp, // --> @@ -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) { diff --git a/js2/src/js2execution.cpp b/js2/src/js2execution.cpp index bda9f2617781..3fbd9a859632 100644 --- a/js2/src/js2execution.cpp +++ b/js2/src/js2execution.cpp @@ -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")); diff --git a/js2/src/js2runtime.cpp b/js2/src/js2runtime.cpp index 1860f2d774c0..182c4c910913 100644 --- a/js2/src/js2runtime.cpp +++ b/js2/src/js2runtime.cpp @@ -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(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(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(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; diff --git a/js2/src/js2runtime.h b/js2/src/js2runtime.h index f5d404f5b4b1..bf75e523507d 100644 --- a/js2/src/js2runtime.h +++ b/js2/src/js2runtime.h @@ -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()