From 4119277f1d7be2c2bd174aba7dae86a2a54a3d8e Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Thu, 20 Sep 2001 01:35:42 +0000 Subject: [PATCH] Fixes for missing global object properties, various bug fixes. git-svn-id: svn://10.0.0.236/trunk@103256 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/bytecodegen.cpp | 72 +++-- mozilla/js2/src/bytecodegen.h | 18 +- mozilla/js2/src/js2execution.cpp | 482 ++++++++++++++++++------------- mozilla/js2/src/js2runtime.cpp | 416 ++++++++++++++++++++------ mozilla/js2/src/js2runtime.h | 93 ++++-- mozilla/js2/src/jsarray.cpp | 117 ++++++-- mozilla/js2/src/jsarray.h | 4 +- mozilla/js2/src/jsdate.cpp | 12 +- mozilla/js2/src/jsstring.cpp | 38 +-- mozilla/js2/src/numerics.cpp | 29 +- mozilla/js2/src/numerics.h | 2 + mozilla/js2/src/property.h | 2 +- 12 files changed, 881 insertions(+), 404 deletions(-) diff --git a/mozilla/js2/src/bytecodegen.cpp b/mozilla/js2/src/bytecodegen.cpp index 0f3119c2a98..014ea40f401 100644 --- a/mozilla/js2/src/bytecodegen.cpp +++ b/mozilla/js2/src/bytecodegen.cpp @@ -224,7 +224,7 @@ void NameReference::emitTypeOf(ByteCodeGen *bcg) void NameReference::emitDelete(ByteCodeGen *bcg) { - bcg->addOp(DeleteOp); + bcg->addOp(DeleteNameOp); bcg->addStringRef(mName); } @@ -266,7 +266,7 @@ void ElementReference::emitCodeSequence(ByteCodeGen *bcg) void ElementReference::emitDelete(ByteCodeGen *bcg) { - bcg->addOpAdjustDepth(DeleteElementOp, -mDepth); + bcg->addOpAdjustDepth(DeleteElementOp, -(mDepth - 1)); bcg->addShort(mDepth); } @@ -299,6 +299,7 @@ ByteCodeData gByteCodeData[OpCodeCount] = { { -1, "NewThis", }, { -128, "NewInstance", }, { 0, "Delete", }, +{ 1, "DeleteName", }, { 0, "TypeOf", }, { -1, "InstanceOf", }, { -1, "As", }, @@ -362,23 +363,16 @@ ByteCodeModule::ByteCodeModule(ByteCodeGen *bcg, JSFunction *f) mCodeMap = new PC_Position[mCodeMapLength]; memcpy(mCodeMap, bcg->mPC_Map->begin(), mCodeMapLength * sizeof(PC_Position)); - mStringPoolContents = new String[bcg->mStringPoolContents.size()]; - - int index = 0; - for (std::vector::iterator s_i = bcg->mStringPoolContents.begin(), - s_end = bcg->mStringPoolContents.end(); (s_i != s_end); s_i++, index++) - mStringPoolContents[index] = *s_i; - - mNumberPoolContents = new float64[bcg->mNumberPoolContents.size()]; - index = 0; - for (std::vector::iterator f_i = bcg->mNumberPoolContents.begin(), - f_end = bcg->mNumberPoolContents.end(); (f_i != f_end); f_i++, index++) - mNumberPoolContents[index] = *f_i; - mLocalsCount = bcg->mScopeChain->countVars(); mStackDepth = toUInt32(bcg->mStackMax); } +ByteCodeModule::~ByteCodeModule() +{ + delete mCodeBase; + delete mCodeMap; +} + size_t ByteCodeModule::getPositionForPC(uint32 pc) { if (mCodeMapLength == 0) @@ -461,6 +455,8 @@ void ByteCodeGen::addOp(uint8 op) void ByteCodeGen::addNumberRef(float64 f) { + addFloat64(f); +/* NumberPool::iterator i = mNumberPool.find(f); if (i != mNumberPool.end()) addLong(i->second); @@ -469,10 +465,15 @@ void ByteCodeGen::addNumberRef(float64 f) mNumberPool[f] = mNumberPoolContents.size(); mNumberPoolContents.push_back(f); } +*/ } void ByteCodeGen::addStringRef(const String &str) { + const StringAtom &s = m_cx->mWorld.identifiers[str]; + addPointer((void *)(&s)); + +/* StringPool::iterator i = mStringPool.find(str); if (i != mStringPool.end()) addLong(i->second); @@ -481,6 +482,7 @@ void ByteCodeGen::addStringRef(const String &str) mStringPool[str] = mStringPoolContents.size(); mStringPoolContents.push_back(str); } +*/ } @@ -889,7 +891,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3 objectWriteRef->emitCodeSequence(this); addOp(GetInvokePropertyOp); // addIdentifierRef(widenCString("Iterator"), widenCString("forin")); - addStringRef(widenCString("forin")); + addStringRef(m_cx->Forin_StringAtom); addOpAdjustDepth(InvokeOp, -1); addLong(0); addByte(Explicit); @@ -902,7 +904,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3 setLabel(labelAtTopOfBlock); iteratorReadRef->emitCodeSequence(this); addOp(GetPropertyOp); - addStringRef(widenCString("value")); + addStringRef(m_cx->Value_StringAtom); value->emitCodeSequence(this); addOp(PopOp); @@ -915,7 +917,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3 setLabel(labelAtIncrement); objectReadRef->emitCodeSequence(this); addOp(GetInvokePropertyOp); - addStringRef(widenCString("next")); + addStringRef(m_cx->Next_StringAtom); iteratorReadRef->emitCodeSequence(this); addOpAdjustDepth(InvokeOp, -2); addLong(1); @@ -936,7 +938,7 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3 setLabel(breakLabel); objectReadRef->emitCodeSequence(this); addOp(GetInvokePropertyOp); - addStringRef(widenCString("done")); + addStringRef(m_cx->Done_StringAtom); iteratorReadRef->emitCodeSequence(this); addOpAdjustDepth(InvokeOp, -2); addLong(1); @@ -1348,6 +1350,11 @@ bool ByteCodeGen::genCodeForStatement(StmtNode *p, ByteCodeGen *static_cg, uint3 Reference *ByteCodeGen::genReference(ExprNode *p, Access acc) { switch (p->getKind()) { + case ExprNode::parentheses: + { + UnaryExprNode *u = checked_cast(p); + return genReference(u->op, acc); + } case ExprNode::index: { InvokeExprNode *i = checked_cast(p); @@ -2085,6 +2092,8 @@ BinaryOpEquals: { InvokeExprNode *i = checked_cast(p); Reference *ref = genReference(i->op, Read); + if (ref == NULL) + m_cx->reportError(Exception::referenceError, "Unrecogizable call target", p->pos); ref->emitInvokeSequence(this); @@ -2250,8 +2259,8 @@ BinaryOpEquals: } fnc->setArgCounts(reqArgCount, optArgCount, (f->function.restParameter != NULL)); - if (mScopeChain->isPossibleUncheckedFunction(&f->function)) - fnc->setIsPrototype(true); + if (mScopeChain->isPossibleUncheckedFunction(&f->function)) + fnc->setIsPrototype(true); m_cx->buildRuntimeForFunction(f->function, fnc); ByteCodeGen bcg(m_cx, mScopeChain); @@ -2311,6 +2320,22 @@ BinaryOpEquals: addOp(JuxtaposeOp); } break; + case ExprNode::comma: + { + BinaryExprNode *c = checked_cast(p); + genExpr(c->op1); + return genExpr(c->op2); + } + break; + case ExprNode::Void: + { + UnaryExprNode *v = checked_cast(p); + genExpr(v->op); + addOp(PopOp); + addOp(LoadConstantUndefinedOp); + return Object_Type; + } + break; default: NOT_REACHED("Not Implemented Yet"); } @@ -2428,13 +2453,14 @@ uint32 printInstruction(Formatter &f, uint32 i, const ByteCodeModule& bcm) case SetPropertyOp: case LoadConstantStringOp: case DeleteOp: + case DeleteNameOp: f << *bcm.getString(bcm.getLong(i)); i += 4; break; case LoadConstantNumberOp: - f << bcm.getNumber(bcm.getLong(i)); - i += 4; + f << bcm.getNumber(&bcm.mCodeBase[i]); + i += 8; break; case LoadTypeOp: diff --git a/mozilla/js2/src/bytecodegen.h b/mozilla/js2/src/bytecodegen.h index bdd19eb681e..2d3d2aa17b1 100644 --- a/mozilla/js2/src/bytecodegen.h +++ b/mozilla/js2/src/bytecodegen.h @@ -95,7 +95,8 @@ typedef enum { NewObjectOp, // --> NewThisOp, // --> NewInstanceOp, // --> - DeleteOp, // --> + DeleteOp, // --> + DeleteNameOp, // --> TypeOfOp, // --> InstanceOfOp, // --> AsOp, // --> @@ -171,6 +172,7 @@ extern ByteCodeData gByteCodeData[OpCodeCount]; public: ByteCodeModule(ByteCodeGen *bcg, JSFunction *f); + ~ByteCodeModule(); #ifdef DEBUG void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeModule", s, t); return t; } @@ -180,8 +182,8 @@ extern ByteCodeData gByteCodeData[OpCodeCount]; uint32 getLong(uint32 index) const { return *((uint32 *)&mCodeBase[index]); } uint16 getShort(uint32 index) const { return *((uint16 *)&mCodeBase[index]); } int32 getOffset(uint32 index) const { return *((int32 *)&mCodeBase[index]); } - const String *getString(uint32 index) const { return &mStringPoolContents[index]; } - float64 getNumber(uint32 index) const { return mNumberPoolContents[index]; } + const String *getString(uint32 index) const { return (const String *)(index); } + float64 getNumber(uint8 *p) const { return *((float64 *)p); } void setSource(const String &source, const String &sourceLocation) { @@ -200,9 +202,6 @@ extern ByteCodeData gByteCodeData[OpCodeCount]; uint8 *mCodeBase; uint32 mLength; - String *mStringPoolContents; - float64 *mNumberPoolContents; - PC_Position *mCodeMap; uint32 mCodeMapLength; @@ -259,6 +258,12 @@ extern ByteCodeData gByteCodeData[OpCodeCount]; mStackMax(0) { } + ByteCodeGen::~ByteCodeGen() + { + delete mBuffer; + delete mPC_Map; + } + #ifdef DEBUG void* operator new(size_t s) { void *t = STD::malloc(s); trace_alloc("ByteCodeGen", s, t); return t; } void operator delete(void* t) { trace_release("ByteCodeGen", t); STD::free(t); } @@ -344,6 +349,7 @@ extern ByteCodeData gByteCodeData[OpCodeCount]; void addPointer(void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); } // XXX Pointer size dependant !!! + void addFloat64(float64 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); } 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 diff --git a/mozilla/js2/src/js2execution.cpp b/mozilla/js2/src/js2execution.cpp index 9efa1cd591c..5105f6b3bfd 100644 --- a/mozilla/js2/src/js2execution.cpp +++ b/mozilla/js2/src/js2execution.cpp @@ -67,6 +67,39 @@ namespace JS2Runtime { inline char narrow(char16 ch) { return char(ch); } +JSValue Context::readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue) +{ + JSValue result = kUndefinedValue; + + Arena a; + Parser p(mWorld, a, mFlags, str, fileName); + mReader = &p.lexer.reader; + StmtNode *parsedStatements = p.parseProgram(); + ASSERT(p.lexer.peek(true).hasKind(Token::end)); + if (mDebugFlag) + { + PrettyPrinter f(stdOut, 30); + { + PrettyPrinter::Block b(f, 2); + f << "Program ="; + f.linearBreak(1); + StmtNode::printStatements(f, parsedStatements); + } + f.end(); + stdOut << '\n'; + } + + buildRuntime(parsedStatements); + JS2Runtime::ByteCodeModule* bcm = genCode(parsedStatements, fileName); + if (bcm) { + setReader(NULL); + bcm->setSource(str, fileName); + result = interpret(bcm, 0, scopeChain, thisValue, NULL, 0); + delete bcm; + } + return result; +} + JSValue Context::readEvalFile(const String& fileName) { String buffer; @@ -81,33 +114,7 @@ JSValue Context::readEvalFile(const String& fileName) while ((ch = getc(f)) != EOF) buffer += static_cast(ch); fclose(f); - - Arena a; - Parser p(mWorld, a, mFlags, buffer, fileName); - mReader = &p.lexer.reader; - StmtNode *parsedStatements = p.parseProgram(); - ASSERT(p.lexer.peek(true).hasKind(Token::end)); - if (mDebugFlag) - { - PrettyPrinter f(stdOut, 30); - { - PrettyPrinter::Block b(f, 2); - f << "Program ="; - f.linearBreak(1); - StmtNode::printStatements(f, parsedStatements); - } - f.end(); - stdOut << '\n'; - } - - buildRuntime(parsedStatements); - JS2Runtime::ByteCodeModule* bcm = genCode(parsedStatements, fileName); - if (bcm) { - setReader(NULL); - bcm->setSource(buffer, fileName); - result = interpret(bcm, 0, NULL, JSValue(getGlobalObject()), NULL, 0); - delete bcm; - } + result = readEvalString(buffer, fileName, NULL, JSValue(getGlobalObject())); } return result; } @@ -188,6 +195,7 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha if (mThis.isObject()) mScopeChain->addScope(mThis.object); // mScopeChain->addScope(mActivationStack.top()); + mCurModule = bcm; uint8 *pc = mCurModule->mCodeBase + offset; uint8 *endPC = mCurModule->mCodeBase + mCurModule->mLength; @@ -202,6 +210,15 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha Activation *prev = mActivationStack.top(); mActivationStack.pop(); + // the following (delete's) are a bit iffy - depends on whether + // a closure capturing the contents has come along... + if (mThis.isObject()) + mScopeChain->popScope(); + delete[] mStack; + delete[] mLocals; + if (scopeChain == NULL) + delete mScopeChain; + mCurModule = prev->mModule; mStack = prev->mStack; mStackTop = prev->mStackTop; @@ -211,7 +228,7 @@ JSValue Context::interpret(JS2Runtime::ByteCodeModule *bcm, int offset, ScopeCha mArgumentBase = prev->mArgumentBase; mThis = prev->mThis; mScopeChain = prev->mScopeChain; - + delete prev; return result; } @@ -229,7 +246,7 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount) } uint32 i; - uint32 argBlockSize = maxExpectedArgCount + (target->hasRestParameter() ? 1 : 0); + uint32 argBlockSize = max(argCount, maxExpectedArgCount) + (target->hasRestParameter() ? 1 : 0); // room for all required & optional arguments // plus the rest parameter if it exists. argBase = new JSValue[argBlockSize]; @@ -319,8 +336,19 @@ JSValue *Context::buildArgumentBlock(JSFunction *target, uint32 &argCount) restArgument.object->setProperty(this, *id, (NamespaceList *)(NULL), v); } } - else - reportError(Exception::referenceError, "Extra argument, no rest argument"); + else { + if (target->isChecked()) + reportError(Exception::referenceError, "Extra argument, no rest argument"); + else { + JSValue v = getValue(i + argStart); + if (v.isObject() && (v.object->mType == NamedArgument_Type)) { + NamedArgument *arg = static_cast(v.object); + argBase[i] = arg->mValue; + } + else + argBase[i] = v; + } + } } } } @@ -505,32 +533,34 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) if (!targetValue->isFunction()) { if (targetValue->isType()) { -/* - // " Type() " - // - it's a cast expression, we call the - // default constructor, overriding the supplied 'this'. - // - - // XXX Note that this is different behaviour from JS1.5, where - // (e.g.) Array(2) is an invocation of the constructor. - - if ((argCount != 0) || ((callFlags & ThisFlags) != NoThis)) - reportError(Exception::referenceError, "Type cast can only take one argument"); - JSValue v = popValue(); - popValue(); // don't need the target anymore - pushValue(mapValueToType(v, targetValue->type)); - break; // all done -*/ - // how to distinguish between a cast and an invocation of // the superclass constructor from a constructor???? - // XXX help - target = targetValue->type->getDefaultConstructor(); + if ((callFlags & SuperInvoke) == SuperInvoke) { + // in this case, calling the constructor requires passing the 'this' value + // through. + target = targetValue->type->getDefaultConstructor(); + mThis = oldThis; + } + else { + // " Type() " + // - it's a cast expression, we call the + // default constructor, overriding the supplied 'this'. + // + + // XXX Note that this is different behaviour from JS1.5, where + // (e.g.) Array(2) is an invocation of the constructor. - // in this case, calling the constructor requires passing the 'this' value - // through. - mThis = oldThis; + if ((argCount > 1) || ((callFlags & ThisFlags) != NoThis)) + reportError(Exception::referenceError, "Type cast can only take one argument"); + JSValue v; + if (argCount > 0) + v = popValue(); + popValue(); // don't need the target anymore + pushValue(mapValueToType(v, targetValue->type)); + mThis = oldThis; + break; // all done + } } else reportError(Exception::referenceError, "Not a function"); @@ -564,6 +594,14 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) mScopeChain = target->getScopeChain(); if (mThis.isObject()) mScopeChain->addScope(mThis.object); + + if (!target->isChecked()) { + JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this); + for (uint32 i = 0; i < argCount; i++) + args->setProperty(this, *numberToString(i), NULL, argBase[i]); + mScopeChain->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args)); + } + // mScopeChain->addScope(mActivationStack.top()); mCurModule = target->getByteCode(); pc = mCurModule->mCodeBase; @@ -575,7 +613,17 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) mStackTop = 0; } else { + // native functions may still need access to information + // about the currently executing function. + mActivationStack.push(new Activation(mLocals, mStack, mStackTop - (cleanUp + 1), + mScopeChain, + mArgumentBase, oldThis, + pc, mCurModule)); JSValue result = (target->getNativeCode())(this, mThis, argBase, argCount); + Activation *prev = mActivationStack.top(); + delete prev; + mActivationStack.pop(); + mThis = oldThis; resizeStack(stackSize() - (cleanUp + 1)); pushValue(result); @@ -584,14 +632,18 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) } break; case ReturnVoidOp: - { + { if (mActivationStack.empty()) return result; Activation *prev = mActivationStack.top(); - if (prev->mPC == NULL) // NULL is used to indicate that we want the loop to exit - return result; // (even though there is more activation stack to go - // - used to implement Xetters from XProperty ops. e.g.) + if (prev->mPC == NULL) { // NULL is used to indicate that we want the loop to exit + // (even though there is more activation stack to go + return result; // - used to implement Xetters from XProperty ops. e.g.) + + } mActivationStack.pop(); + delete[] mLocals; + delete[] mStack; mCurModule = prev->mModule; pc = prev->mPC; @@ -602,20 +654,22 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) mLocals = prev->mLocals; mArgumentBase = prev->mArgumentBase; mThis = prev->mThis; - mScopeChain = prev->mScopeChain; + mScopeChain = prev->mScopeChain; + delete prev; } break; case ReturnOp: { - JSValue result = popValue(); - + JSValue result = popValue(); if (mActivationStack.empty()) - return result; + return result; Activation *prev = mActivationStack.top(); - if (prev->mPC == NULL) + if (prev->mPC == NULL) { return result; - + } mActivationStack.pop(); + delete[] mLocals; + delete[] mStack; mCurModule = prev->mModule; pc = prev->mPC; @@ -628,6 +682,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) mThis = prev->mThis; mScopeChain = prev->mScopeChain; pushValue(result); + delete prev; } break; case LoadTypeOp: @@ -653,9 +708,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) break; case LoadConstantNumberOp: { - uint32 index = *((uint32 *)pc); - pc += sizeof(uint32); - pushValue(JSValue(mCurModule->getNumber(index))); + pushValue(JSValue(mCurModule->getNumber(pc))); + pc += sizeof(float64); } break; case LoadConstantUndefinedOp: @@ -673,6 +727,17 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) case LoadConstantZeroOp: pushValue(kPositiveZero); break; + case DeleteNameOp: + { + uint32 index = *((uint32 *)pc); + pc += sizeof(uint32); + const String &name = *mCurModule->getString(index); + PropertyIterator it; + if (mScopeChain->hasOwnProperty(name, CURRENT_ATTR, Read, &it)) + mScopeChain->deleteProperty(name, CURRENT_ATTR); + pushValue(kTrueValue); + } + break; case DeleteOp: { JSValue base = popValue(); @@ -694,24 +759,24 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) { JSValue v = popValue(); if (v.isUndefined()) - pushValue(JSValue(new String(widenCString("undefined")))); + pushValue(JSValue(&Undefined_StringAtom)); else if (v.isNull()) - pushValue(JSValue(new String(widenCString("object")))); + pushValue(JSValue(&Object_StringAtom)); else if (v.isBool()) - pushValue(JSValue(new String(widenCString("boolean")))); + pushValue(JSValue(&Boolean_StringAtom)); else if (v.isNumber()) - pushValue(JSValue(new String(widenCString("number")))); + pushValue(JSValue(&Number_StringAtom)); else if (v.isString()) - pushValue(JSValue(new String(widenCString("string")))); + pushValue(JSValue(&String_StringAtom)); else if (v.isFunction()) - pushValue(JSValue(new String(widenCString("function")))); + pushValue(JSValue(&Function_StringAtom)); else - pushValue(JSValue(new String(widenCString("object")))); + pushValue(JSValue(&Object_StringAtom)); } break; case AsOp: @@ -770,7 +835,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) JSFunction *obj = t.function; PropertyIterator i; JSFunction *target = NULL; - if (obj->hasProperty(widenCString("hasInstance"), CURRENT_ATTR, Read, &i)) { + if (obj->hasProperty(HasInstance_StringAtom, CURRENT_ATTR, Read, &i)) { JSValue hi = obj->getPropertyValue(i); if (hi.isFunction()) target = hi.function; @@ -822,22 +887,36 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) // Use the type of the base to dispatch on... JSObject *obj = NULL; - if (!baseValue->isObject() && !baseValue->isType()) - obj = baseValue->toObject(this).object; - else + if (baseValue->isType()) + obj = baseValue->type; + else + if (baseValue->isFunction()) + obj = baseValue->function; + else + if (baseValue->isObject()) obj = baseValue->object; + else + obj = baseValue->toObject(this).object; + JSFunction *target = obj->getType()->getUnaryOperator(Index); if (target) { JSValue result; - if (target->isNative()) - result = target->getNativeCode()(this, kNullValue, baseValue, dimCount + 1); + if (target->isNative()) { + JSValue *argBase = new JSValue[dimCount + 1]; + for (int i = 0; i < (dimCount + 1); i++) + argBase[i] = baseValue[i]; + resizeStack(stackSize() - (dimCount + 1)); + result = target->getNativeCode()(this, argBase[0], argBase, dimCount + 1); + delete[] argBase; + } else { uint32 argCount = dimCount + 1; JSValue *argBase = buildArgumentBlock(target, argCount); - result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount); + resizeStack(stackSize() - (dimCount + 1)); + result = interpret(target->getByteCode(), 0, target->getScopeChain(), argBase[0], argBase, argCount); + delete[] argBase; } - resizeStack(stackSize() - (dimCount + 1)); pushValue(result); } else { // XXX or should this be implemented in Object_Type as operator "[]" ? @@ -871,14 +950,21 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) insertValue(v, mStackTop - dimCount); JSValue result; - if (target->isNative()) + if (target->isNative()) { + JSValue *argBase = new JSValue[dimCount + 2]; + for (int i = 0; i < (dimCount + 2); i++) + argBase[i] = baseValue[i]; + resizeStack(stackSize() - (dimCount + 2)); result = target->getNativeCode()(this, *baseValue, baseValue, (dimCount + 2)); + delete[] argBase; + } else { uint32 argCount = dimCount + 2; JSValue *argBase = buildArgumentBlock(target, argCount); + resizeStack(stackSize() - (dimCount + 2)); result = interpret(target->getByteCode(), 0, target->getScopeChain(), *baseValue, argBase, argCount); + delete[] argBase; } - resizeStack(stackSize() - (dimCount + 2)); pushValue(result); } else { // XXX or should this be implemented in Object_Type as operator "[]=" ? @@ -911,14 +997,21 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) if (target) { JSValue result; - if (target->isNative()) - result = target->getNativeCode()(this, kNullValue, baseValue, dimCount + 1); + if (target->isNative()) { + JSValue *argBase = new JSValue[dimCount + 1]; + for (int i = 0; i < (dimCount + 1); i++) + argBase[i] = baseValue[i]; + resizeStack(stackSize() - (dimCount + 1)); + result = target->getNativeCode()(this, argBase[0], argBase, dimCount + 1); + delete[] argBase; + } else { uint32 argCount = dimCount + 1; JSValue *argBase = buildArgumentBlock(target, argCount); + resizeStack(stackSize() - (dimCount + 1)); result = interpret(target->getByteCode(), 0, target->getScopeChain(), kNullValue, argBase, argCount); + delete[] argBase; } - resizeStack(stackSize() - (dimCount + 1)); pushValue(result); } else { // XXX or should this be implemented in Object_Type as operator "delete[]" ? @@ -1110,7 +1203,7 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) target = typeValue->function; newThis = Object_Type->newInstance(this); PropertyIterator i; - if (target->hasProperty(widenCString("prototype"), CURRENT_ATTR, Read, &i)) { + if (target->hasProperty(Prototype_StringAtom, CURRENT_ATTR, Read, &i)) { JSValue v = target->getPropertyValue(i); newThis.object->mPrototype = v.toObject(this).object; } @@ -1133,17 +1226,33 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) ASSERT(target); JSValue result; - if (target->isNative()) - result = target->getNativeCode()(this, newThis, argBase, argCount); + if (target->isNative()) { + JSValue *tArgBase = new JSValue[argCount]; + for (int i = 0; i < argCount; i++) + tArgBase[i] = argBase[i]; + resizeStack(stackSize() - cleanUp); + result = target->getNativeCode()(this, newThis, tArgBase, argCount); + } else { argBase = buildArgumentBlock(target, argCount); + resizeStack(stackSize() - cleanUp); + if (!target->isChecked()) { + JSArrayInstance *args = (JSArrayInstance *)Array_Type->newInstance(this); + for (uint32 i = 0; i < argCount; i++) + args->setProperty(this, *numberToString(i), NULL, argBase[i]); + mScopeChain->defineVariable(this, Arguments_StringAtom, NULL, Array_Type, JSValue(args)); + } result = interpret(target->getByteCode(), 0, target->getScopeChain(), newThis, argBase, argCount); } - resizeStack(stackSize() - cleanUp); - if (!isPrototypeFunctionCall) - // If it's a prototype function, we don't care what it returns, - // we have the 'this' already + if (isPrototypeFunctionCall) { + // If it's a prototype function, the return value is only + // interesting if it's not a primitive, in which case it + // overrides the newly constructed object. Weird, huh. + if (!result.isPrimitive()) + newThis = result; + } + else // otherwise, constructor has potentially made the 'this', so retain it newThis = result; @@ -1438,10 +1547,6 @@ static JSValue objectPlus(Context *cx, const JSValue& /*thisValue*/, JSValue *ar JSValue &r1 = argv[0]; JSValue &r2 = argv[1]; if (r1.isNumber() && r2.isNumber()) { - // this is the ECMA3 implementation. Suppose somebody has - // added (can they?) an operator "+" for Numbers - we should - // oughta dispatch to that function here. (And all other - // cases below, arrgh - how deep does this go? my brain hurts) return JSValue(r1.toNumber(cx).f64 + r2.toNumber(cx).f64); } @@ -1507,11 +1612,11 @@ static JSValue integerMultiply(Context * /*cx*/, const JSValue& /*thisValue*/, J return JSValue(r1.f64 * r2.f64); } -static JSValue objectMultiply(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/) +static JSValue objectMultiply(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/) { JSValue &r1 = argv[0]; JSValue &r2 = argv[1]; - return JSValue(r1.f64 * r2.f64); + return JSValue(r1.toNumber(cx).f64 * r2.toNumber(cx).f64); } @@ -1551,7 +1656,17 @@ static JSValue objectRemainder(Context *cx, const JSValue& /*thisValue*/, JSValu { JSValue &r1 = argv[0]; JSValue &r2 = argv[1]; - return JSValue(fd::fmod(r1.toNumber(cx).f64, r2.toNumber(cx).f64)); + + float64 f1 = r1.toNumber(cx).f64; + float64 f2 = r2.toNumber(cx).f64; + +#ifdef XP_PC + /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ + if (JSDOUBLE_IS_FINITE(f1) && JSDOUBLE_IS_INFINITE(f2)) + return JSValue(f1); +#endif + + return JSValue(fd::fmod(f1, f2)); } @@ -1689,7 +1804,7 @@ static JSValue objectLessEqual(Context *cx, const JSValue& /*thisValue*/, JSValu JSValue &r1 = argv[0]; JSValue &r2 = argv[1]; JSValue result = objectCompare(cx, r2, r1); - if (result.isTrue() || result.isUndefined()) + if (result.isUndefined() || result.isTrue()) return kFalseValue; else return kTrueValue; @@ -1876,7 +1991,14 @@ JSValue JSValue::valueToObject(Context *cx, const JSValue& value) float64 stringToNumber(const String *string) { const char16 *numEnd; - return stringToDouble(string->begin(), string->end(), numEnd); + const char16 *sBegin = string->begin(); + if (sBegin) + if ((sBegin[0] == '0') && ((sBegin[1] & ~0x20) == 'X')) + return stringToInteger(sBegin, string->end(), numEnd, 16); + else + return stringToDouble(sBegin, string->end(), numEnd); + else + return 0.0; } JSValue JSValue::valueToNumber(Context *cx, const JSValue& value) @@ -1893,6 +2015,8 @@ JSValue JSValue::valueToNumber(Context *cx, const JSValue& value) return JSValue((value.boolean) ? 1.0 : 0.0); case undefined_tag: return kNaNValue; + case null_tag: + return kPositiveZero; default: NOT_REACHED("Bad tag"); return kUndefinedValue; @@ -1922,18 +2046,16 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value) case string_tag: return value; case boolean_tag: - strp = (value.boolean) - ? new JavaScript::String(widenCString("true")) - : new JavaScript::String(widenCString("false")); + strp = (value.boolean) ? &cx->True_StringAtom : &cx->False_StringAtom; break; case type_tag: strp = value.type->mClassName; break; case undefined_tag: - strp = new JavaScript::String(widenCString("undefined")); + strp = &cx->Undefined_StringAtom; break; case null_tag: - strp = new JavaScript::String(widenCString("null")); + strp = &cx->Null_StringAtom; break; default: NOT_REACHED("Bad tag"); @@ -1941,26 +2063,20 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value) if (obj) { JSFunction *target = NULL; PropertyIterator i; - if (obj->hasProperty(widenCString("toString"), CURRENT_ATTR, Read, &i)) { + if (obj->hasProperty(cx->ToString_StringAtom, CURRENT_ATTR, Read, &i)) { JSValue v = obj->getPropertyValue(i); if (v.isFunction()) target = v.function; } if (target == NULL) { - if (obj->hasProperty(widenCString("valueOf"), CURRENT_ATTR, Read, &i)) { + if (obj->hasProperty(cx->ValueOf_StringAtom, CURRENT_ATTR, Read, &i)) { JSValue v = obj->getPropertyValue(i); if (v.isFunction()) target = v.function; } } - if (target) { - if (!target->isNative()) { - // here we need to get the interpreter to do the job - ASSERT(false); - } - else - return (target->getNativeCode())(cx, value, NULL, 0); - } + if (target) + return cx->invokeFunction(target, value, NULL, 0); throw new Exception(Exception::runtimeError, "toString"); // XXX return kUndefinedValue; // keep compilers happy } @@ -1969,7 +2085,7 @@ JSValue JSValue::valueToString(Context *cx, const JSValue& value) } -JSValue JSValue::toPrimitive(Context *, Hint) const +JSValue JSValue::toPrimitive(Context *cx, Hint hint) const { JSObject *obj; switch (tag) { @@ -1990,74 +2106,47 @@ JSValue JSValue::toPrimitive(Context *, Hint) const NOT_REACHED("Bad tag"); return kUndefinedValue; } -/* - JSFunction *target = NULL; - JSValue result; - JSValues argv(1); - argv[0] = *this; // The following is [[DefaultValue]] // - if ((hint == NumberHint) || (hint == NoHint)) { - const JSValue &valueOf = obj->getProperty(widenCString("valueOf")); - if (valueOf.isFunction()) { - target = valueOf.function; - if (target->isNative()) { - result = static_cast(target)->mCode(cx, argv); - } - else { - Context new_cx(cx); - result = new_cx.interpret(target->getICode(), argv); - } - if (result.isPrimitive()) - return result; - } - const JSValue &toString = obj->getProperty(widenCString("toString")); - if (toString.isFunction()) { - target = toString.function; - if (target->isNative()) { - result = static_cast(target)->mCode(cx, argv); - } - else { - Context new_cx(cx); - result = new_cx.interpret(target->getICode(), argv); - } - if (result.isPrimitive()) - return result; - } - } - else { - const JSValue &toString = obj->getProperty(widenCString("toString")); - if (toString.isFunction()) { - target = toString.function; - if (target->isNative()) { - result = static_cast(target)->mCode(cx, argv); - } - else { - Context new_cx(cx); - result = new_cx.interpret(target->getICode(), argv); - } - if (result.isPrimitive()) - return result; - } - const JSValue &valueOf = obj->getProperty(widenCString("valueOf")); - if (valueOf.isFunction()) { - target = valueOf.function; - if (target->isNative()) { - result = static_cast(target)->mCode(cx, argv); - } - else { - Context new_cx(cx); - result = new_cx.interpret(target->getICode(), argv); - } - if (result.isPrimitive()) - return result; - } - } - throw Exception(Exception::runtimeError, "toPrimitive"); // XXX -*/ + ASSERT(obj); + JSFunction *target = NULL; + JSValue result; + PropertyIterator i; + + StringAtom *first = &cx->ValueOf_StringAtom; + StringAtom *second = &cx->ToString_StringAtom; + + if (hint == StringHint) { + first = &cx->ToString_StringAtom; + second = &cx->ValueOf_StringAtom; + } + + + if (obj->hasProperty(*first, CURRENT_ATTR, Read, &i)) { + JSValue v = obj->getPropertyValue(i); + if (v.isFunction()) { + target = v.function; + if (target) { + result = cx->invokeFunction(target, *this, NULL, 0); + if (result.isPrimitive()) + return result; + } + } + } + if (obj->hasProperty(*second, CURRENT_ATTR, Read, &i)) { + JSValue v = obj->getPropertyValue(i); + if (v.isFunction()) { + target = v.function; + if (target) { + result = cx->invokeFunction(target, *this, NULL, 0); + if (result.isPrimitive()) + return result; + } + } + } + throw new Exception(Exception::runtimeError, "toPrimitive"); // XXX return kUndefinedValue; - } int JSValue::operator==(const JSValue& value) const @@ -2197,16 +2286,18 @@ JSValue JSValue::valueToBoolean(Context *cx, const JSValue& value) JSObject *obj = NULL; switch (value.tag) { case f64_tag: - return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64)); + if (JSDOUBLE_IS_NaN(value.f64)) + return kFalseValue; + if (value.f64 == 0.0) + return kFalseValue; + return kTrueValue; case string_tag: return JSValue(value.string->length() != 0); case boolean_tag: return value; case object_tag: - obj = value.object; - break; case function_tag: - obj = value.function; + return kTrueValue; break; case undefined_tag: return kFalseValue; @@ -2214,25 +2305,6 @@ JSValue JSValue::valueToBoolean(Context *cx, const JSValue& value) NOT_REACHED("Bad tag"); return kUndefinedValue; } - ASSERT(obj); - JSFunction *target = NULL; - PropertyIterator i; - if (obj->hasProperty(widenCString("toBoolean"), CURRENT_ATTR, Read, &i)) { - JSValue v = obj->getPropertyValue(i); - if (v.isFunction()) - target = v.function; - } - if (target) { - if (!target->isNative()) { - // here we need to get the interpreter to do the job - ASSERT(false); - } - else { - JSValue args = value; - return (target->getNativeCode())(cx, value, &args, 1); - } - } - throw new Exception(Exception::runtimeError, "toBoolean"); // XXX } diff --git a/mozilla/js2/src/js2runtime.cpp b/mozilla/js2/src/js2runtime.cpp index 0b116e76438..7ab38eff060 100644 --- a/mozilla/js2/src/js2runtime.cpp +++ b/mozilla/js2/src/js2runtime.cpp @@ -180,6 +180,13 @@ JSValue JSObject::getPropertyValue(PropertyIterator &i) return *prop->mData.vp; } +Property *JSObject::insertNewProperty(const String &name, NamespaceList *names, PropertyAttribute attrFlags, JSType *type, const JSValue &v) +{ + Property *prop = new Property(new JSValue(v), type, attrFlags); + const PropertyMap::value_type e(name, new NamespacedProperty(prop, names)); + mProperties.insert(e); + return prop; +} void JSObject::defineGetterMethod(Context * /*cx*/, const String &name, AttributeStmtNode *attr, JSFunction *f) { @@ -264,7 +271,7 @@ Property *JSObject::defineVariable(Context *cx, const String &name, NamespaceLis } // add a property (with a value) -Property *JSObject::defineVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type, JSValue v) +Property *JSObject::defineVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type, const JSValue v) { NamespaceList *names = (attr) ? attr->attributeValue->mNamespaceList : NULL; PropertyAttribute attrFlags = (attr) ? attr->attributeValue->mTrueFlags : 0; @@ -278,6 +285,11 @@ Property *JSObject::defineVariable(Context *cx, const String &name, AttributeStm else cx->reportError(Exception::typeError, "Duplicate definition '{0}'", name); } + else { + // override the existing value + PROPERTY_VALUEPOINTER(it) = new JSValue(v); + return PROPERTY(it); + } } Property *prop = new Property(new JSValue(v), type, attrFlags); @@ -285,7 +297,7 @@ Property *JSObject::defineVariable(Context *cx, const String &name, AttributeStm mProperties.insert(e); return prop; } -Property *JSObject::defineVariable(Context *cx, const String &name, NamespaceList *names, JSType *type, JSValue v) +Property *JSObject::defineVariable(Context *cx, const String &name, NamespaceList *names, JSType *type, const JSValue v) { PropertyIterator it; if (hasOwnProperty(name, names, Read, &it)) { @@ -483,7 +495,7 @@ void JSInstance::setProperty(Context *cx, const String &name, NamespaceList *nam void JSArrayInstance::getProperty(Context *cx, const String &name, NamespaceList *names) { - if (name.compare(widenCString("length")) == 0) + if (name.compare(cx->Length_StringAtom) == 0) cx->pushValue(JSValue((float64)mLength)); else JSInstance::getProperty(cx, name, names); @@ -491,7 +503,7 @@ void JSArrayInstance::getProperty(Context *cx, const String &name, NamespaceList void JSArrayInstance::setProperty(Context *cx, const String &name, NamespaceList *names, const JSValue &v) { - if (name.compare(widenCString("length")) == 0) { + if (name.compare(cx->Length_StringAtom) == 0) { uint32 newLength = (uint32)(v.toUInt32(cx).f64); if (newLength != v.toNumber(cx).f64) cx->reportError(Exception::rangeError, "out of range value for length"); @@ -506,10 +518,14 @@ void JSArrayInstance::setProperty(Context *cx, const String &name, NamespaceList mLength = newLength; } else { - if (findNamespacedProperty(name, names) == mProperties.end()) - defineVariable(cx, name, names, Object_Type, v); - else - JSInstance::setProperty(cx, name, names, v); + PropertyIterator it = findNamespacedProperty(name, names); + if (it == mProperties.end()) + insertNewProperty(name, names, 0, Object_Type, v); + else { + Property *prop = PROPERTY(it); + ASSERT(prop->mFlag == ValuePointer); + *prop->mData.vp = v; + } JSValue v = JSValue(&name); JSValue v_int = v.toUInt32(cx); if ((v_int.f64 != two32minus1) && (v_int.toString(cx).string->compare(name) == 0)) { @@ -521,7 +537,7 @@ void JSArrayInstance::setProperty(Context *cx, const String &name, NamespaceList void JSStringInstance::getProperty(Context *cx, const String &name, NamespaceList *names) { - if (name.compare(widenCString("length")) == 0) { + if (name.compare(cx->Length_StringAtom) == 0) { cx->pushValue(JSValue((float64)mLength)); } else @@ -622,6 +638,7 @@ void ScopeChain::setNameValue(Context *cx, const String& name, AttributeStmtNode if ((*s)->hasProperty(name, names, Write, &i)) { if (PROPERTY_KIND(i) == ValuePointer) { *PROPERTY_VALUEPOINTER(i) = v; + break; } else ASSERT(false); // what else needs to be implemented ? @@ -832,7 +849,7 @@ void Context::buildRuntime(StmtNode *p) } // Generate bytecode for the linked list of statements in p -JS2Runtime::ByteCodeModule *Context::genCode(StmtNode *p, String /*sourceName*/) +JS2Runtime::ByteCodeModule *Context::genCode(StmtNode *p, const String &/*sourceName*/) { mScopeChain->addScope(getGlobalObject()); JS2Runtime::ByteCodeGen bcg(this, mScopeChain); @@ -850,23 +867,23 @@ JS2Runtime::ByteCodeModule *Context::genCode(StmtNode *p, String /*sourceName*/) */ bool ScopeChain::isPossibleUncheckedFunction(FunctionDefinition *f) { - bool result = false; + bool result = false; if ((f->resultType == NULL) - && (f->restParameter == NULL) - && (f->optParameters == NULL) - && (f->prefix == FunctionName::normal) - && (topClass() == NULL)) { - result = true; - VariableBinding *b = f->parameters; - while (b) { - if (b->type != NULL) { - result = false; - break; - } - b = b->next; - } + && (f->restParameter == NULL) + && (f->optParameters == NULL) + && (f->prefix == FunctionName::normal) + && (topClass() == NULL)) { + result = true; + VariableBinding *b = f->parameters; + while (b) { + if (b->type != NULL) { + result = false; + break; + } + b = b->next; } - return result; + } + return result; } // The first pass over the tree - it just installs the names of each declaration @@ -935,6 +952,7 @@ void ScopeChain::collectNames(StmtNode *p) { ForStmtNode *f = checked_cast(p); if (f->initializer) collectNames(f->initializer); + collectNames(f->stmt); } break; case StmtNode::Const: @@ -972,6 +990,8 @@ void ScopeChain::collectNames(StmtNode *p) bool isOperator = (f->attributeValue->mTrueFlags & Property::Operator) == Property::Operator; bool isPrototype = (f->attributeValue->mTrueFlags & Property::Prototype) == Property::Prototype; + JSFunction *fnc = new JSFunction(NULL, this); + /* Determine whether a function is unchecked, which is the case if - XXX strict mode is disabled at the point of the function definition; the function is not a class or interface member; @@ -982,11 +1002,11 @@ void ScopeChain::collectNames(StmtNode *p) */ if (!isPrototype && (!isOperator) - && isPossibleUncheckedFunction(&f->function)) { + && isPossibleUncheckedFunction(&f->function)) { isPrototype = true; + fnc->setIsUnchecked(); } - JSFunction *fnc = new JSFunction(NULL, this); fnc->setIsPrototype(isPrototype); fnc->setIsConstructor(isConstructor); fnc->setFunctionName(&f->function); @@ -1081,7 +1101,11 @@ void ScopeChain::collectNames(StmtNode *p) defineSetterMethod(m_cx, name, f, fnc); break; case FunctionName::normal: - f->attributeValue->mTrueFlags |= Property::Const; + // make a function into a const declaration, but only if any types + // have been specified - otherwise it's a 1.5 atyle definition and + // duplicates are allowed + if (!isPossibleUncheckedFunction(&f->function)) + f->attributeValue->mTrueFlags |= Property::Const; if (isStatic) defineStaticMethod(m_cx, name, f, fnc); else @@ -1313,7 +1337,7 @@ Reference *JSType::genReference(bool hasBase, const String& name, NamespaceList return NULL; } -JSType::JSType(Context *cx, const StringAtom *name, JSType *super) +JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj) : JSObject(Type_Type), mSuperType(super), mVariableCount(0), @@ -1333,10 +1357,15 @@ JSType::JSType(Context *cx, const StringAtom *name, JSType *super) mUnaryOperators[i] = NULL; // every class gets a prototype object - mPrototypeObject = new JSObject(); + if (protoObj) + mPrototypeObject = protoObj; + else + mPrototypeObject = new JSObject(); // and that object is prototype-linked to the super-type's prototype object if (mSuperType) mPrototypeObject->mPrototype = mSuperType->mPrototypeObject; + +// defineVariable(cx, cx->Prototype_StringAtom, NULL, Object_Type, JSValue(mPrototypeObject)); } JSType::JSType(JSType *xClass) // used for constructing the static component type @@ -1355,6 +1384,8 @@ JSType::JSType(JSType *xClass) // used for constructing the static component mUnaryOperators[i] = NULL; } +// Establish the super class - connects the prototype's prototype +// and accounts for the super class's instance fields & methods void JSType::setSuperType(JSType *super) { mSuperType = super; @@ -1424,9 +1455,10 @@ Reference *Activation::genReference(bool /* hasBase */, const String& name, Name - - - +/* +Process the statements in the function body, handling parameters and local +variables to collect names & types. +*/ void Context::buildRuntimeForFunction(FunctionDefinition &f, JSFunction *fnc) { fnc->mParameterBarrel = new ParameterBarrel(); @@ -1448,6 +1480,10 @@ void Context::buildRuntimeForFunction(FunctionDefinition &f, JSFunction *fnc) mScopeChain->popScope(); } +/* +The incoming AttributeStmtNode has a list of attributes - evaluate those and return +the resultant Attribute value. If there are no attributes, return the default value. +*/ void Context::setAttributeValue(AttributeStmtNode *s, PropertyAttribute defaultValue) { Attribute *attributeValue = NULL; @@ -1508,6 +1544,7 @@ void Context::buildRuntimeForStmt(StmtNode *p) { ForStmtNode *f = checked_cast(p); if (f->initializer) buildRuntimeForStmt(f->initializer); + buildRuntimeForStmt(f->stmt); } break; case StmtNode::Var: @@ -1696,13 +1733,67 @@ static JSValue Object_done(Context *, const JSValue& /*thisValue*/, JSValue * /* -static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { JSValue v = thisValue; if (v.isNull()) v = Function_Type->newInstance(cx); - // XXX use the arguments to compile a string into a function ASSERT(v.isObject()); + + String s; + if (argc == 0) + s = widenCString("() { }"); + else { + if (argc == 1) + s = widenCString("() {") + *argv[0].toString(cx).string + "}"; + else { + s = widenCString("("); // ')' + for (int i = 0; i < (argc - 1); i++) { + s += *argv[i].toString(cx).string; + if (i < (argc - 2)) + s += widenCString(", "); + } +/* ( */ s += ") {" + *argv[argc - 1].toString(cx).string + "}"; + } + } + + JSFunction *fnc = NULL; + /***************************************************************/ + { + Arena a; + Parser p(cx->mWorld, a, cx->mFlags, s, widenCString("function constructor")); + cx->mReader = &p.lexer.reader; + + FunctionExprNode *f = p.parseFunctionExpression(0); + if (!p.lexer.peek(true).hasKind(Token::end)) + cx->reportError(Exception::syntaxError, "Unexpected stuff after the function body"); + + fnc = new JSFunction(NULL, cx->mScopeChain); + + uint32 reqArgCount = 0; + uint32 optArgCount = 0; + + VariableBinding *b = f->function.parameters; + while ((b != f->function.optParameters) && (b != f->function.restParameter)) { + reqArgCount++; + b = b->next; + } + while (b != f->function.restParameter) { + optArgCount++; + b = b->next; + } + fnc->setArgCounts(reqArgCount, optArgCount, (f->function.restParameter != NULL)); + + if (cx->mScopeChain->isPossibleUncheckedFunction(&f->function)) + fnc->setIsPrototype(true); + + cx->buildRuntimeForFunction(f->function, fnc); + ByteCodeGen bcg(cx, cx->mScopeChain); + bcg.genCodeForFunction(f->function, f->pos, fnc, false, NULL); + } + /***************************************************************/ + + v = JSValue(fnc); return v; } @@ -1720,7 +1811,7 @@ static JSValue Function_hasInstance(Context *cx, const JSValue& thisValue, JSVal return kFalseValue; ASSERT(thisValue.isFunction()); - thisValue.function->getProperty(cx, widenCString("prototype"), CURRENT_ATTR); + thisValue.function->getProperty(cx, cx->Prototype_StringAtom, CURRENT_ATTR); JSValue p = cx->popValue(); if (!p.isObject()) @@ -1749,14 +1840,23 @@ static JSValue Number_Constructor(Context *cx, const JSValue& thisValue, JSValue return v; } -static JSValue Number_toString(Context *, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +static JSValue Number_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { ASSERT(thisValue.isObject()); + if (thisValue.getType() != Number_Type) + cx->reportError(Exception::typeError, "Number.toString called on something other than a Number object"); JSObject *thisObj = thisValue.object; return JSValue(numberToString(*((double *)(thisObj->mPrivate)))); } - +static JSValue Number_valueOf(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +{ + ASSERT(thisValue.isObject()); + if (thisValue.getType() != Number_Type) + cx->reportError(Exception::typeError, "Number.valueOf called on something other than a Number object"); + JSObject *thisObj = thisValue.object; + return JSValue(*((double *)(thisObj->mPrivate))); +} static JSValue Integer_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { @@ -1800,15 +1900,26 @@ static JSValue Boolean_Constructor(Context *cx, const JSValue& thisValue, JSValu return v; } -static JSValue Boolean_toString(Context *, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +static JSValue Boolean_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; if (thisObj->mPrivate != 0) - return JSValue(new String(widenCString("true"))); + return JSValue(&cx->True_StringAtom); else - return JSValue(new String(widenCString("false"))); + return JSValue(&cx->False_StringAtom); +} + +static JSValue Boolean_valueOf(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +{ + ASSERT(thisValue.isObject()); + JSObject *thisObj = thisValue.object; + + if (thisObj->mPrivate != 0) + return kTrueValue; //JSValue(1.0); + else + return kFalseValue; //kPositiveZero; } static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) @@ -1821,6 +1932,50 @@ static JSValue ExtendAttribute_Invoke(Context * /*cx*/, const JSValue& /*thisVal return JSValue(x); } + +static JSValue GlobalObject_Eval(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 /*argc*/) +{ + if (!argv[0].isString()) + return argv[0]; + const String *sourceStr = argv[0].toString(cx).string; + + Activation *prev = cx->mActivationStack.top(); + + return cx->readEvalString(*sourceStr, widenCString("eval source"), cx->mScopeChain, prev->mThis); +} + +static JSValue GlobalObject_ParseInt(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) +{ + ASSERT(argc >= 1); + int radix = 0; // default for stringToInteger + if (argc == 2) + radix = argv[1].toInt32(cx).f64; + if ((radix < 0) || (radix > 36)) + return kNaNValue; + + const String *string = argv[0].toString(cx).string; + const char16 *numEnd; + const char16 *sBegin = string->begin(); + float64 f = 0.0; + if (sBegin) + f = stringToInteger(sBegin, string->end(), numEnd, radix); + return JSValue(f); +} + +static JSValue GlobalObject_ParseFloat(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) +{ + ASSERT(argc == 1); + + const String *string = argv[0].toString(cx).string; + const char16 *numEnd; + const char16 *sBegin = string->begin(); + float64 f = 0.0; + if (sBegin) + f = stringToDouble(sBegin, string->end(), numEnd); + return JSValue(f); +} + + JSValue JSFunction::runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc) { @@ -1884,7 +2039,7 @@ void Context::initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef) FunctionName *fnName = new FunctionName(); fun->setFunctionName(fnName); fun->setArgCounts(pdef->mDef[i].length, 0, false); - type->mPrototypeObject->defineVariable(this, *name, //widenCString(pdef->mDef[i].name), + type->mPrototypeObject->defineVariable(this, *name, (NamespaceList *)(NULL), pdef->mDef[i].result, JSValue(fun)); @@ -1901,36 +2056,40 @@ void Context::initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef) static JSValue arrayMaker(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) { ASSERT(argc == 2); - ASSERT(argv[0].isType() && argv[1].isType()); - + ASSERT(argv[0].isType()); JSType *baseType = argv[0].type; - ASSERT(baseType == Array_Type); - JSType *elementType = argv[1].type; + if ((baseType == Array_Type) && argv[1].isType()) { + JSType *elementType = argv[1].type; + JSType *result = new JSArrayType(cx, elementType, NULL, Object_Type); + result->setDefaultConstructor(cx, Array_Type->getDefaultConstructor()); + return JSValue(result); + } + else { + // then it's just [] - an element reference + argv[0].type->getProperty(cx, *argv[1].toString(cx).string, NULL); + return cx->popValue(); + } - JSType *result = new JSArrayType(cx, elementType, NULL, Object_Type); - result->setDefaultConstructor(cx, Array_Type->getDefaultConstructor()); - - return JSValue(result); } void Context::initBuiltins() { ClassDef builtInClasses[] = { - { "Object", Object_Constructor, &kNullValue }, - { "Type", NULL, &kNullValue }, - { "Function", Function_Constructor, &kNullValue }, - { "Number", Number_Constructor, &kPositiveZero }, - { "Integer", Integer_Constructor, &kPositiveZero }, - { "String", String_Constructor, &kNullValue }, - { "Array", Array_Constructor, &kNullValue }, - { "Boolean", Boolean_Constructor, &kFalseValue }, - { "Void", NULL, &kNullValue }, - { "Unit", NULL, &kNullValue }, - { "Attribute", NULL, &kNullValue }, - { "NamedArgument", NULL, &kNullValue }, - { "Date", Date_Constructor, &kPositiveZero }, + { "Object", Object_Constructor, &kUndefinedValue }, + { "Type", NULL, &kNullValue }, + { "Function", Function_Constructor, &kNullValue }, + { "Number", Number_Constructor, &kPositiveZero }, + { "Integer", Integer_Constructor, &kPositiveZero }, + { "String", String_Constructor, &kNullValue }, + { "Array", Array_Constructor, &kNullValue }, + { "Boolean", Boolean_Constructor, &kFalseValue }, + { "Void", NULL, &kNullValue }, + { "Unit", NULL, &kNullValue }, + { "Attribute", NULL, &kNullValue }, + { "NamedArgument", NULL, &kNullValue }, + { "Date", Date_Constructor, &kPositiveZero }, }; Object_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[0].name)], NULL); @@ -1938,20 +2097,43 @@ void Context::initBuiltins() // XXX aren't all the built-ins thus? Type_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[1].name)], Object_Type); - Function_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type); + Object_Type->mType = Type_Type; + + // + // ECMA 1.5 says Function.prototype is a Function object, it's [[class]] property is "Function" + // ECMA 2.0 says Function.prototype is an Object NOT an instance of the class + // here we sort of manage that by having a JSFunction object as the prototype object, not a JSFunctionInstance + // (which we don't actually have, hmm). + // For String, etc. this same issue needs to be finessed + + JSFunction *funProto = new JSFunction(Object_Type, NULL); + Function_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type, funProto); + Function_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(funProto)); + Number_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type); + Number_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Number_Type->mPrototypeObject)); + Integer_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[4].name)], Object_Type); + String_Type = new JSStringType(this, &mWorld.identifiers[widenCString(builtInClasses[5].name)], Object_Type); + String_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(String_Type->mPrototypeObject)); + Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type); + Array_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Array_Type->mPrototypeObject)); + Boolean_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[7].name)], Object_Type); + Boolean_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Boolean_Type->mPrototypeObject)); + Void_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[8].name)], Object_Type); Unit_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[9].name)], Object_Type); Attribute_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[10].name)], Object_Type); NamedArgument_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[11].name)], Object_Type); + Date_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[12].name)], Object_Type); + Date_Type->defineVariable(this, Prototype_StringAtom, NULL, Object_Type, JSValue(Date_Type->mPrototypeObject)); - String_Type->defineVariable(this, widenCString("fromCharCode"), NULL, String_Type, JSValue(new JSFunction(String_fromCharCode, String_Type))); + String_Type->defineVariable(this, FromCharCode_StringAtom, NULL, String_Type, JSValue(new JSFunction(String_fromCharCode, String_Type))); ProtoFunDef objectProtos[] = @@ -1974,6 +2156,7 @@ void Context::initBuiltins() { { "toString", String_Type, 0, Number_toString }, { "toSource", String_Type, 0, Number_toString }, + { "valueOf", Number_Type, 0, Number_valueOf }, { NULL } }; ProtoFunDef integerProtos[] = @@ -1986,12 +2169,13 @@ void Context::initBuiltins() { { "toString", String_Type, 0, Boolean_toString }, { "toSource", String_Type, 0, Boolean_toString }, + { "valueOf", Number_Type, 0, Boolean_valueOf }, { NULL } }; ASSERT(mGlobal); *mGlobal = Object_Type->newInstance(this); - initClass(Object_Type, &builtInClasses[0], new PrototypeFunctions(&objectProtos[0]) ); + initClass(Object_Type, &builtInClasses[0], new PrototypeFunctions(&objectProtos[0]) ); initClass(Type_Type, &builtInClasses[1], NULL ); initClass(Function_Type, &builtInClasses[2], new PrototypeFunctions(&functionProtos[0]) ); @@ -2008,6 +2192,9 @@ void Context::initBuiltins() Type_Type->defineUnaryOperator(Index, new JSFunction(arrayMaker, Type_Type)); + Array_Type->defineUnaryOperator(Index, new JSFunction(Array_GetElement, Object_Type)); + Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(Array_SetElement, Object_Type)); + } @@ -2076,13 +2263,38 @@ JS2Runtime::Operator Context::getOperator(uint32 parameterCount, const String &n Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags) - : VirtualKeyWord(world.identifiers["virtual"]), - ConstructorKeyWord(world.identifiers["constructor"]), - OperatorKeyWord(world.identifiers["operator"]), - FixedKeyWord(world.identifiers["fixed"]), - DynamicKeyWord(world.identifiers["dynamic"]), - ExtendKeyWord(world.identifiers["extend"]), - PrototypeKeyWord(world.identifiers["prototype"]), + + : Virtual_StringAtom (world.identifiers["virtual"]), + Constructor_StringAtom (world.identifiers["constructor"]), + Operator_StringAtom (world.identifiers["operator"]), + Fixed_StringAtom (world.identifiers["fixed"]), + Dynamic_StringAtom (world.identifiers["dynamic"]), + Extend_StringAtom (world.identifiers["extend"]), + Prototype_StringAtom (world.identifiers["prototype"]), + Forin_StringAtom (world.identifiers["forin"]), + Value_StringAtom (world.identifiers["value"]), + Next_StringAtom (world.identifiers["next"]), + Done_StringAtom (world.identifiers["done"]), + Undefined_StringAtom (world.identifiers["undefined"]), + Object_StringAtom (world.identifiers["object"]), + Boolean_StringAtom (world.identifiers["boolean"]), + Number_StringAtom (world.identifiers["number"]), + String_StringAtom (world.identifiers["string"]), + Function_StringAtom (world.identifiers["function"]), + HasInstance_StringAtom (world.identifiers["hasInstance"]), + True_StringAtom (world.identifiers["true"]), + False_StringAtom (world.identifiers["false"]), + Null_StringAtom (world.identifiers["null"]), + ToString_StringAtom (world.identifiers["toString"]), + ValueOf_StringAtom (world.identifiers["valueOf"]), + Length_StringAtom (world.identifiers["length"]), + FromCharCode_StringAtom (world.identifiers["fromCharCode"]), + Math_StringAtom (world.identifiers["Math"]), + NaN_StringAtom (world.identifiers["NaN"]), + Eval_StringAtom (world.identifiers["eval"]), + Infinity_StringAtom (world.identifiers["Infinity"]), + Empty_StringAtom (world.identifiers[""]), + Arguments_StringAtom (world.identifiers["arguments"]), mWorld(world), mScopeChain(NULL), @@ -2101,19 +2313,27 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags) mGlobal(global) { + uint32 i; + initOperatorTable(); mScopeChain = new ScopeChain(this, mWorld); if (Object_Type == NULL) { initBuiltins(); - JSObject *mathObj = Object_Type->newInstance(this); - getGlobalObject()->defineVariable(this, widenCString("Math"), (NamespaceList *)(NULL), Object_Type, JSValue(mathObj)); - initMathObject(this, mathObj); - getGlobalObject()->defineVariable(this, widenCString("undefined"), (NamespaceList *)(NULL), Void_Type, kUndefinedValue); - getGlobalObject()->defineVariable(this, widenCString("NaN"), (NamespaceList *)(NULL), Void_Type, kNaNValue); - getGlobalObject()->defineVariable(this, widenCString("Infinity"), (NamespaceList *)(NULL), Void_Type, kPositiveInfinity); - initDateObject(this); } + + + JSObject *mathObj = Object_Type->newInstance(this); + getGlobalObject()->defineVariable(this, Math_StringAtom, (NamespaceList *)(NULL), Object_Type, JSValue(mathObj)); + initMathObject(this, mathObj); + initDateObject(this); + + Number_Type->defineVariable(this, widenCString("MAX_VALUE"), NULL, Number_Type, JSValue(maxValue)); + Number_Type->defineVariable(this, widenCString("MIN_VALUE"), NULL, Number_Type, JSValue(minValue)); + Number_Type->defineVariable(this, widenCString("NaN"), NULL, Number_Type, JSValue(nan)); + Number_Type->defineVariable(this, widenCString("POSITIVE_INFINITY"), NULL, Number_Type, JSValue(positiveInfinity)); + Number_Type->defineVariable(this, widenCString("NEGATIVE_INFINITY"), NULL, Number_Type, JSValue(negativeInfinity)); + initOperators(); struct Attribute_Init { @@ -2144,13 +2364,45 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags) { "const", Property::Const, 0 }, }; - for (uint32 i = 0; i < (sizeof(attribute_init) / sizeof(Attribute_Init)); i++) { + for (i = 0; i < (sizeof(attribute_init) / sizeof(Attribute_Init)); i++) { Attribute *attr = new Attribute(attribute_init[i].trueFlags, attribute_init[i].falseFlags); getGlobalObject()->defineVariable(this, widenCString(attribute_init[i].name), (NamespaceList *)(NULL), Attribute_Type, JSValue(attr)); } JSFunction *x = new JSFunction(ExtendAttribute_Invoke, Attribute_Type); - getGlobalObject()->defineVariable(this, widenCString("extend"), (NamespaceList *)(NULL), Attribute_Type, JSValue(x)); + getGlobalObject()->defineVariable(this, Extend_StringAtom, (NamespaceList *)(NULL), Attribute_Type, JSValue(x)); + + + + + ProtoFunDef globalObjectFunctions[] = { + { "eval", Object_Type, 1, GlobalObject_Eval }, + { "parseInt", Number_Type, 2, GlobalObject_ParseInt }, + { "parseFloat", Number_Type, 2, GlobalObject_ParseFloat }, + }; + + for (i = 0; i < (sizeof(globalObjectFunctions) / sizeof(ProtoFunDef)); i++) { + x = new JSFunction(globalObjectFunctions[i].imp, globalObjectFunctions[i].result); + x->setArgCounts(globalObjectFunctions[i].length, 0, false); + x->setIsPrototype(true); + getGlobalObject()->defineVariable(this, widenCString(globalObjectFunctions[i].name), (NamespaceList *)(NULL), globalObjectFunctions[i].result, JSValue(x)); + } + +/* + x = new JSFunction(GlobalObject_Eval, Object_Type); + x->setArgCounts(1, 0, false); + x->setIsPrototype(true); + getGlobalObject()->defineVariable(this, Eval_StringAtom, (NamespaceList *)(NULL), Object_Type, JSValue(x)); + + x = new JSFunction(GlobalObject_ParseInt, Number_Type); + x->setArgCounts(2, 0, false); + x->setIsPrototype(true); + getGlobalObject()->defineVariable(this, widenCString("parseInt"), (NamespaceList *)(NULL), Object_Type, JSValue(x)); +*/ + + getGlobalObject()->defineVariable(this, Undefined_StringAtom, (NamespaceList *)(NULL), Void_Type, kUndefinedValue); + getGlobalObject()->defineVariable(this, NaN_StringAtom, (NamespaceList *)(NULL), Void_Type, kNaNValue); + getGlobalObject()->defineVariable(this, Infinity_StringAtom, (NamespaceList *)(NULL), Void_Type, kPositiveInfinity); } diff --git a/mozilla/js2/src/js2runtime.h b/mozilla/js2/src/js2runtime.h index 6a12fe224c4..4e9d07fbbc8 100644 --- a/mozilla/js2/src/js2runtime.h +++ b/mozilla/js2/src/js2runtime.h @@ -174,6 +174,7 @@ static const double two31 = 2147483648.0; bool isType() const { return (tag == type_tag); } bool isFunction() const { return (tag == function_tag); } bool isString() const { return (tag == string_tag); } + bool isPrimitive() const { return (tag != object_tag) && (tag != type_tag) && (tag != function_tag); } bool isUndefined() const { return (tag == undefined_tag); } bool isNull() const { return (tag == null_tag); } @@ -221,15 +222,15 @@ static const double two31 = 2147483648.0; }; Formatter& operator<<(Formatter& f, const JSValue& value); - extern const JSValue kUndefinedValue; - extern const JSValue kNaNValue; - extern const JSValue kTrueValue; - extern const JSValue kFalseValue; - extern const JSValue kNullValue; - extern const JSValue kNegativeZero; - extern const JSValue kPositiveZero; - extern const JSValue kNegativeInfinity; - extern const JSValue kPositiveInfinity; + extern JSValue kUndefinedValue; + extern JSValue kNaNValue; + extern JSValue kTrueValue; + extern JSValue kFalseValue; + extern JSValue kNullValue; + extern JSValue kNegativeZero; + extern JSValue kPositiveZero; + extern JSValue kNegativeInfinity; + extern JSValue kPositiveInfinity; @@ -546,6 +547,10 @@ XXX ...couldn't get this to work... virtual Property *defineVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type); virtual Property *defineVariable(Context *cx, const String &name, NamespaceList *names, JSType *type); + // add a property/value into the map + // - assumes the map doesn't already have this property + Property *insertNewProperty(const String &name, NamespaceList *names, PropertyAttribute attrFlags, JSType *type, const JSValue &v); + virtual Property *defineStaticVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type) { return JSObject::defineVariable(cx, name, attr, type); @@ -576,8 +581,8 @@ XXX ...couldn't get this to work... virtual void defineGetterMethod(Context *cx, const String &name, AttributeStmtNode *attr, JSFunction *f); virtual void defineSetterMethod(Context *cx, const String &name, AttributeStmtNode *attr, JSFunction *f); - virtual Property *defineVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type, JSValue v); - virtual Property *defineVariable(Context *cx, const String &name, NamespaceList *names, JSType *type, JSValue v); + virtual Property *defineVariable(Context *cx, const String &name, AttributeStmtNode *attr, JSType *type, const JSValue v); + virtual Property *defineVariable(Context *cx, const String &name, NamespaceList *names, JSType *type, const JSValue v); virtual Reference *genReference(bool hasBase, const String& name, NamespaceList *names, Access acc, uint32 depth); @@ -687,7 +692,7 @@ XXX ...couldn't get this to work... class JSType : public JSObject { public: - JSType(Context *cx, const StringAtom *name, JSType *super); + JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL); JSType(JSType *xClass); // used for constructing the static component type virtual ~JSType() { } // keeping gcc happy @@ -1075,6 +1080,19 @@ XXX ...couldn't get this to work... return top->hasProperty(name, names, acc, p); } + bool hasOwnProperty(const String& name, NamespaceList *names, Access acc, PropertyIterator *p) + { + JSObject *top = mScopeStack.back(); + return top->hasOwnProperty(name, names, acc, p); + } + + // delete a property from the top object (already know it's there) + void deleteProperty(const String &name, NamespaceList *names) + { + JSObject *top = mScopeStack.back(); + top->deleteProperty(name, names); + } + // generate a reference to the given name Reference *getName(const String& name, NamespaceList *names, Access acc); @@ -1197,7 +1215,8 @@ XXX ...couldn't get this to work... if (scopeChain) { mScopeChain = new ScopeChain(*scopeChain); } - mPrototype = Function_Type->mPrototypeObject; + if (Function_Type) // protect against bootstrap + mPrototype = Function_Type->mPrototypeObject; mActivation.mContainer = this; } @@ -1219,7 +1238,8 @@ XXX ...couldn't get this to work... mRestParameterName(NULL), mClass(NULL) { - mPrototype = Function_Type->mPrototypeObject; + if (Function_Type) // protect against bootstrap + mPrototype = Function_Type->mPrototypeObject; mActivation.mContainer = this; } @@ -1420,13 +1440,37 @@ XXX ...couldn't get this to work... void operator delete(void* t) { trace_release("Context", t); STD::free(t); } #endif - StringAtom& VirtualKeyWord; - StringAtom& ConstructorKeyWord; - StringAtom& OperatorKeyWord; - StringAtom& FixedKeyWord; - StringAtom& DynamicKeyWord; - StringAtom& ExtendKeyWord; - StringAtom& PrototypeKeyWord; + StringAtom& Virtual_StringAtom; + StringAtom& Constructor_StringAtom; + StringAtom& Operator_StringAtom; + StringAtom& Fixed_StringAtom; + StringAtom& Dynamic_StringAtom; + StringAtom& Extend_StringAtom; + StringAtom& Prototype_StringAtom; + StringAtom& Forin_StringAtom; + StringAtom& Value_StringAtom; + StringAtom& Next_StringAtom; + StringAtom& Done_StringAtom; + StringAtom& Undefined_StringAtom; + StringAtom& Object_StringAtom; + StringAtom& Boolean_StringAtom; + StringAtom& Number_StringAtom; + StringAtom& String_StringAtom; + StringAtom& Function_StringAtom; + StringAtom& HasInstance_StringAtom; + StringAtom& True_StringAtom; + StringAtom& False_StringAtom; + StringAtom& Null_StringAtom; + StringAtom& ToString_StringAtom; + StringAtom& ValueOf_StringAtom; + StringAtom& Length_StringAtom; + StringAtom& FromCharCode_StringAtom; + StringAtom& Math_StringAtom; + StringAtom& NaN_StringAtom; + StringAtom& Eval_StringAtom; + StringAtom& Infinity_StringAtom; + StringAtom& Empty_StringAtom; + StringAtom& Arguments_StringAtom; void initBuiltins(); void initClass(JSType *type, ClassDef *cdef, PrototypeFunctions *pdef); @@ -1479,7 +1523,7 @@ XXX ...couldn't get this to work... uint32 mStackTop; uint32 mStackMax; - void pushValue(JSValue v) + void pushValue(JSValue &v) { ASSERT(mStackTop < mStackMax); mStack[mStackTop++] = v; @@ -1516,7 +1560,7 @@ XXX ...couldn't get this to work... // put the value in at 'index', lifting everything above that up by one void insertValue(JSValue v, uint32 index) { - ASSERT((mStackTop + 1) < mStackMax); + ASSERT(mStackTop < mStackMax); // we're effectively pushing one entry for (uint32 i = mStackTop - 1; i >= index; i--) mStack[i + 1] = mStack[i]; mStack[index] = v; @@ -1565,11 +1609,12 @@ XXX ...couldn't get this to work... JSValue readEvalFile(const String& fileName); + JSValue readEvalString(const String &str, const String& fileName, ScopeChain *scopeChain, const JSValue& thisValue); void buildRuntime(StmtNode *p); void buildRuntimeForFunction(FunctionDefinition &f, JSFunction *fnc); void buildRuntimeForStmt(StmtNode *p); - ByteCodeModule *genCode(StmtNode *p, String sourceName); + ByteCodeModule *genCode(StmtNode *p, const String &sourceName); JSValue interpret(ByteCodeModule *bcm, int offset, ScopeChain *scopeChain, const JSValue& thisValue, JSValue *argv, uint32 argc); JSValue interpret(uint8 *pc, uint8 *endPC); diff --git a/mozilla/js2/src/jsarray.cpp b/mozilla/js2/src/jsarray.cpp index 4535ed23b5f..54f7bb37b57 100644 --- a/mozilla/js2/src/jsarray.cpp +++ b/mozilla/js2/src/jsarray.cpp @@ -59,8 +59,7 @@ JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, thatValue = Array_Type->newInstance(cx); ASSERT(thatValue.isObject()); JSObject *thisObj = thatValue.object; - ASSERT(dynamic_cast(thisObj)); - JSArrayInstance *arrInst = (JSArrayInstance *)thisObj; + JSArrayInstance *arrInst = checked_cast(thisObj); if (argc > 0) { if (argc == 1) { arrInst->mLength = (uint32)(argv[0].toNumber(cx).f64); @@ -82,13 +81,12 @@ static JSValue Array_toString(Context *cx, const JSValue& thisValue, JSValue * / { ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - ASSERT(dynamic_cast(thisObj)); - JSArrayInstance *arrInst = (JSArrayInstance *)thisObj; + JSArrayInstance *arrInst = checked_cast(thisObj); ContextStackReplacement csr(cx); if (arrInst->mLength == 0) - return JSValue(new String(widenCString(""))); + return JSValue(&cx->Empty_StringAtom); else { String *s = new String(); for (uint32 i = 0; i < arrInst->mLength; i++) { @@ -108,8 +106,7 @@ static JSValue Array_toSource(Context *cx, const JSValue& thisValue, JSValue * / { ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - ASSERT(dynamic_cast(thisObj)); - JSArrayInstance *arrInst = (JSArrayInstance *)thisObj; + JSArrayInstance *arrInst = checked_cast(thisObj); ContextStackReplacement csr(cx); @@ -136,8 +133,7 @@ static JSValue Array_push(Context *cx, const JSValue& thisValue, JSValue *argv, { ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - ASSERT(dynamic_cast(thisObj)); - JSArrayInstance *arrInst = (JSArrayInstance *)thisObj; + JSArrayInstance *arrInst = checked_cast(thisObj); for (uint32 i = 0; i < argc; i++) { const String *id = numberToString(i + arrInst->mLength); @@ -152,8 +148,7 @@ static JSValue Array_pop(Context *cx, const JSValue& thisValue, JSValue * /*argv { ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - ASSERT(dynamic_cast(thisObj)); - JSArrayInstance *arrInst = (JSArrayInstance *)thisObj; + JSArrayInstance *arrInst = checked_cast(thisObj); ContextStackReplacement csr(cx); @@ -186,8 +181,8 @@ JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint3 A->setProperty(cx, *id, CURRENT_ATTR, E); } else { - ASSERT(E.isObject() && dynamic_cast(E.object)); - JSArrayInstance *arrInst = (JSArrayInstance *)(E.object); + ASSERT(E.isObject()); + JSArrayInstance *arrInst = checked_cast(E.object); for (uint32 k = 0; k < arrInst->mLength; k++) { const String *id = numberToString(k); arrInst->getProperty(cx, *id, NULL); @@ -209,7 +204,7 @@ static JSValue Array_join(Context *cx, const JSValue& thisValue, JSValue *argv, ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); @@ -244,7 +239,7 @@ static JSValue Array_reverse(Context *cx, const JSValue& thisValue, JSValue * /* ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); @@ -291,12 +286,12 @@ static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*ar ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); if (length == 0) { - thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, result); + thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, result); return kUndefinedValue; } @@ -317,7 +312,7 @@ static JSValue Array_shift(Context *cx, const JSValue& thisValue, JSValue * /*ar } thisObj->deleteProperty(*numberToString(length - 1), CURRENT_ATTR); - thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length - 1)) ); + thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length - 1)) ); return result; } @@ -331,7 +326,7 @@ static JSValue Array_slice(Context *cx, const JSValue& thisValue, JSValue *argv, JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx); - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); @@ -386,7 +381,7 @@ static JSValue Array_slice(Context *cx, const JSValue& thisValue, JSValue *argv, n++; start++; } - A->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)n) ); + A->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)n) ); return JSValue(A); } @@ -403,7 +398,7 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); @@ -444,7 +439,7 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv A->setProperty(cx, *id2, CURRENT_ATTR, cx->popValue()); } } - A->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)deleteCount) ); + A->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)deleteCount) ); uint32 newItemCount = argc - 2; if (newItemCount < deleteCount) { @@ -484,7 +479,7 @@ static JSValue Array_splice(Context *cx, const JSValue& thisValue, JSValue *argv const String *id1 = numberToString(k++); thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[i]); } - thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length - deleteCount + newItemCount)) ); + thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length - deleteCount + newItemCount)) ); return JSValue(A); } @@ -497,7 +492,7 @@ static JSValue Array_unshift(Context *cx, const JSValue& thisValue, JSValue *arg ASSERT(thisValue.isObject()); JSObject *thisObj = thisValue.object; - thisObj->getProperty(cx, widenCString("length"), CURRENT_ATTR); + thisObj->getProperty(cx, cx->Length_StringAtom, CURRENT_ATTR); JSValue result = cx->popValue(); uint32 length = (uint32)(result.toUInt32(cx).f64); uint32 k; @@ -518,11 +513,83 @@ static JSValue Array_unshift(Context *cx, const JSValue& thisValue, JSValue *arg const String *id1 = numberToString(k); thisObj->setProperty(cx, *id1, CURRENT_ATTR, argv[k]); } - thisObj->setProperty(cx, widenCString("length"), CURRENT_ATTR, JSValue((float64)(length + argc)) ); + thisObj->setProperty(cx, cx->Length_StringAtom, CURRENT_ATTR, JSValue((float64)(length + argc)) ); return thisValue; } +// An index has to pass the test that : +// ToString(ToUint32(ToString(index))) == ToString(index) +// +// the 'ToString(index)' operation is the default behaviour of '[]' +// +// isArrayIndex() is called when we know that index is a Number +// +static bool isArrayIndex(Context *cx, JSValue &index, uint32 &intIndex) +{ + ASSERT(index.isNumber()); + JSValue v = index.toUInt32(cx); + if ((v.f64 == index.f64) && (v.f64 < two32minus1)) { + intIndex = (uint32)v.f64; + return true; + } + return false; +} + +JSValue Array_GetElement(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) +{ + // the 'this' value is the first argument, then the index + if (argc != 2) + cx->reportError(Exception::referenceError, "[] only supports single dimension"); + + ASSERT(thisValue.isObject()); + JSObject *thisObj = thisValue.object; + JSArrayInstance *arrInst = checked_cast(thisObj); + ASSERT(thisObj->mType == Array_Type); + + JSValue index = argv[1]; + const String *name = index.toString(cx).string; + + arrInst->getProperty(cx, *name, NULL); + return cx->popValue(); +} + +JSValue Array_SetElement(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) +{ + // the 'this' value is the first argument, then the rValue, and finally the index + if (argc != 3) + cx->reportError(Exception::referenceError, "[]= only supports single dimension"); + + ASSERT(thisValue.isObject()); + JSObject *thisObj = thisValue.object; + JSArrayInstance *arrInst = checked_cast(thisObj); + ASSERT(thisObj->mType == Array_Type); + + JSValue index = argv[2]; + const String *name = index.toString(cx).string; + + if (index.isNumber()) { + uint32 intIndex; + if (isArrayIndex(cx, index, intIndex)) { + PropertyIterator it = thisObj->findNamespacedProperty(*name, NULL); + if (it == thisObj->mProperties.end()) + thisObj->insertNewProperty(*name, NULL, 0, Object_Type, argv[1]); + else { + Property *prop = PROPERTY(it); + ASSERT(prop->mFlag == ValuePointer); + *prop->mData.vp = argv[1]; + } + if (intIndex >= arrInst->mLength) + arrInst->mLength = intIndex + 1; + } + } + else { + arrInst->setProperty(cx, *name, NULL, argv[1]); + } + return argv[0]; +} + + Context::PrototypeFunctions *getArrayProtos() { diff --git a/mozilla/js2/src/jsarray.h b/mozilla/js2/src/jsarray.h index eecf3246b67..b574b1d03b3 100644 --- a/mozilla/js2/src/jsarray.h +++ b/mozilla/js2/src/jsarray.h @@ -35,13 +35,13 @@ namespace JavaScript { namespace JS2Runtime { - extern JSValue Array_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc); extern JSValue Array_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc); Context::PrototypeFunctions *getArrayProtos(); - + extern JSValue Array_GetElement(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc); + extern JSValue Array_SetElement(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc); } diff --git a/mozilla/js2/src/jsdate.cpp b/mozilla/js2/src/jsdate.cpp index 7d030053ee2..55235b30d5c 100644 --- a/mozilla/js2/src/jsdate.cpp +++ b/mozilla/js2/src/jsdate.cpp @@ -97,7 +97,7 @@ static float64 firstDayOfMonth[2][12] = { #define Day(t) floor((t) / msPerDay) #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ && !((d < 0 ? -d : d) > HalfTimeDomain)) \ - ? JSValue::float64ToInteger(d + (+0.)) : kNaNValue.f64) + ? JSValue::float64ToInteger(d + (+0.)) : nan) #define LocalTime(t) ((t) + LocalTZA + DaylightSavingTA(t)) #define DayFromMonth(m, leap) firstDayOfMonth[leap][(int32)m]; #define DayFromYear(y) (365 * ((y)-1970) + fd::floor(((y)-1969)/4.0) \ @@ -368,7 +368,7 @@ static JSValue Date_makeTime(Context *cx, const JSValue& thisValue, JSValue *arg for (i = 0; i < argc; i++) { argv[i] = argv[i].toNumber(cx); if (JSDOUBLE_IS_NaN(argv[i])) { - *date = kNaNValue.f64; + *date = nan; return kNaNValue; } args[i] = argv[i].toInteger(cx).f64; @@ -604,7 +604,7 @@ static float64 date_parseString(const String &s) syntax: /* syntax error */ - return kNaNValue.f64; + return nan; } #define MAXARGS 7 @@ -673,7 +673,7 @@ JSValue Date_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, u /* if any arg is NaN, make a NaN date object and return */ if (!JSDOUBLE_IS_FINITE(double_arg)) { - *((float64 *)(thisObj->mPrivate)) = kNaNValue.f64; + *((float64 *)(thisObj->mPrivate)) = nan; return thatValue; } array[loop] = JSValue::float64ToInteger(double_arg); @@ -1189,7 +1189,7 @@ static JSValue Date_setYear(Context *cx, const JSValue& thisValue, JSValue *argv result = *date; year = argv[0].toNumber(cx).f64; if (!JSDOUBLE_IS_FINITE(year)) { - *date = kNaNValue.f64; + *date = nan; return JSValue(*date); } @@ -1293,7 +1293,7 @@ static JSValue Date_valueOf(Context *cx, const JSValue& thisValue, JSValue *argv /* Convert to number only if the hint was given, otherwise favor string. */ if (argc == 1) { const String *str = argv[0].toString(cx).string; - if (str->compare(widenCString("number")) == 0) + if (str->compare(&cx->Number_StringAtom) == 0) return Date_getTime(cx, thisValue, argv, argc); } return Date_toString(cx, thisValue, argv, argc); diff --git a/mozilla/js2/src/jsstring.cpp b/mozilla/js2/src/jsstring.cpp index 9d89fab9ca1..4c044359288 100644 --- a/mozilla/js2/src/jsstring.cpp +++ b/mozilla/js2/src/jsstring.cpp @@ -57,20 +57,19 @@ JSValue String_Constructor(Context *cx, const JSValue& thisValue, JSValue *argv, thatValue = String_Type->newInstance(cx); ASSERT(thatValue.isObject()); JSObject *thisObj = thatValue.object; - ASSERT(dynamic_cast(thisObj)); - JSStringInstance *strInst = (JSStringInstance *)thisObj; + JSStringInstance *strInst = checked_cast(thisObj); if (argc > 0) thisObj->mPrivate = (void *)(new String(*argv[0].toString(cx).string)); else - thisObj->mPrivate = (void *)(new String(widenCString(""))); + thisObj->mPrivate = (void *)(&cx->Empty_StringAtom); strInst->mLength = ((String *)(thisObj->mPrivate))->size(); return thatValue; } JSValue String_fromCharCode(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) { - String *resultStr = new String(); + String *resultStr = new String(); // can't use cx->mEmptyString because we're modifying this below resultStr->reserve(argc); for (uint32 i = 0; i < argc; i++) *resultStr += (char16)(argv[i].toUInt16(cx).f64); @@ -78,13 +77,26 @@ JSValue String_fromCharCode(Context *cx, const JSValue& /*thisValue*/, JSValue * return JSValue(resultStr); } -static JSValue String_toString(Context * /*cx*/, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +static JSValue String_toString(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { ASSERT(thisValue.isObject()); + if (thisValue.getType() != String_Type) + cx->reportError(Exception::typeError, "String.toString called on something other than a string thing"); JSObject *thisObj = thisValue.object; return JSValue((String *)thisObj->mPrivate); } +static JSValue String_valueOf(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) +{ + ASSERT(thisValue.isObject()); + if (thisValue.getType() != String_Type) + cx->reportError(Exception::typeError, "String.valueOf called on something other than a string thing"); + JSObject *thisObj = thisValue.object; + return JSValue((String *)thisObj->mPrivate); +} + + + struct MatchResult { bool failure; uint32 endIndex; @@ -180,16 +192,6 @@ step11: } -static JSValue String_valueOf(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) -{ - ASSERT(thisValue.isObject()); - if (thisValue.isString()) - return thisValue; - else - cx->reportError(Exception::typeError, "String.valueOf called on something other than a string thing"); - return kUndefinedValue; -} - static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { ASSERT(thisValue.isObject()); @@ -200,7 +202,7 @@ static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *arg pos = (uint32)(argv[0].toInt32(cx).f64); if ((pos < 0) || (pos >= str->size())) - return JSValue(new String()); // have an empty string kValue somewhere? + return JSValue(&cx->Empty_StringAtom); else return JSValue(new String(1, (*str)[pos])); @@ -367,7 +369,7 @@ static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv end = sourceLength; if (start > end) - return JSValue(new String()); + return JSValue(&cx->Empty_StringAtom); return JSValue(new String(sourceString->substr(start, end - start))); } @@ -420,7 +422,7 @@ Context::PrototypeFunctions *getStringProtos() Context::ProtoFunDef stringProtos[] = { { "toString", String_Type, 0, String_toString }, - { "valueof", String_Type, 0, String_valueOf }, + { "valueOf", String_Type, 0, String_valueOf }, { "charAt", String_Type, 1, String_charAt }, { "charCodeAt", Number_Type, 1, String_charCodeAt }, { "concat", String_Type, 1, String_concat }, diff --git a/mozilla/js2/src/numerics.cpp b/mozilla/js2/src/numerics.cpp index 166a41d3bd2..5f67bf89e89 100644 --- a/mozilla/js2/src/numerics.cpp +++ b/mozilla/js2/src/numerics.cpp @@ -225,9 +225,11 @@ static PRLock *freelist_lock; // -double JS::positiveInfinity; -double JS::negativeInfinity; -double JS::nan; + double JS::positiveInfinity; + double JS::negativeInfinity; + double JS::nan; + double JS::minValue; + double JS::maxValue; struct InitNumerics {InitNumerics();}; @@ -241,21 +243,24 @@ InitNumerics::InitNumerics() word1(JS::negativeInfinity) = 0; word0(JS::nan) = 0x7FFFFFFF; word1(JS::nan) = 0xFFFFFFFF; + word0(JS::minValue) = 0; + word1(JS::minValue) = 1; + JS::maxValue = 1.7976931348623157E+308; } // had to move these here since they depend upon the values // initialized above, and we can't guarantee order other than // lexically in a single file. -const JSValue JS::JS2Runtime::kUndefinedValue; -const JSValue JS::JS2Runtime::kNaNValue = JSValue(nan); -const JSValue JS::JS2Runtime::kTrueValue = JSValue(true); -const JSValue JS::JS2Runtime::kFalseValue = JSValue(false); -const JSValue JS::JS2Runtime::kNullValue = JSValue(JSValue::null_tag); -const JSValue JS::JS2Runtime::kNegativeZero = JSValue(-0.0); -const JSValue JS::JS2Runtime::kPositiveZero = JSValue(0.0); -const JSValue JS::JS2Runtime::kNegativeInfinity = JSValue(negativeInfinity); -const JSValue JS::JS2Runtime::kPositiveInfinity = JSValue(positiveInfinity); +JSValue JS::JS2Runtime::kUndefinedValue; +JSValue JS::JS2Runtime::kNaNValue = JSValue(nan); +JSValue JS::JS2Runtime::kTrueValue = JSValue(true); +JSValue JS::JS2Runtime::kFalseValue = JSValue(false); +JSValue JS::JS2Runtime::kNullValue = JSValue(JSValue::null_tag); +JSValue JS::JS2Runtime::kNegativeZero = JSValue(-0.0); +JSValue JS::JS2Runtime::kPositiveZero = JSValue(0.0); +JSValue JS::JS2Runtime::kNegativeInfinity = JSValue(negativeInfinity); +JSValue JS::JS2Runtime::kPositiveInfinity = JSValue(positiveInfinity); // // Portable double-precision floating point to string and back conversions diff --git a/mozilla/js2/src/numerics.h b/mozilla/js2/src/numerics.h index 5c72c4e0fa7..c2bc5ecb368 100644 --- a/mozilla/js2/src/numerics.h +++ b/mozilla/js2/src/numerics.h @@ -66,6 +66,8 @@ namespace JavaScript { extern double positiveInfinity; extern double negativeInfinity; extern double nan; + extern double minValue; + extern double maxValue; // // Portable double-precision floating point to string and back conversions diff --git a/mozilla/js2/src/property.h b/mozilla/js2/src/property.h index 0fe7fbae7fe..ef65e783975 100644 --- a/mozilla/js2/src/property.h +++ b/mozilla/js2/src/property.h @@ -137,7 +137,7 @@ namespace JS2Runtime { NamespaceList *mNext; }; - typedef std::pair NamespacedProperty; + typedef std::pair NamespacedProperty; typedef std::multimap > PropertyMap; typedef PropertyMap::iterator PropertyIterator;