From cf85a416747ca58a436ee4b15b0920edbb8e9a55 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Tue, 16 Oct 2001 18:58:42 +0000 Subject: [PATCH] Fixed length fields for various functions, behavioiur of string functions to match tests. Added missing virtuals to BoundFunction. Fixed eval access to parameters and locals. git-svn-id: svn://10.0.0.236/trunk@105516 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/js2execution.cpp | 44 ++++++--- mozilla/js2/src/js2runtime.cpp | 163 ++++++++++++++++++++++--------- mozilla/js2/src/js2runtime.h | 40 +++++--- mozilla/js2/src/jsmath.cpp | 53 +++++----- mozilla/js2/src/jsstring.cpp | 75 +++++++------- mozilla/js2/src/numerics.cpp | 2 + mozilla/js2/src/property.h | 4 +- 7 files changed, 253 insertions(+), 128 deletions(-) diff --git a/mozilla/js2/src/js2execution.cpp b/mozilla/js2/src/js2execution.cpp index 9741486419e..3fa7755517d 100644 --- a/mozilla/js2/src/js2execution.cpp +++ b/mozilla/js2/src/js2execution.cpp @@ -650,6 +650,8 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) } mScopeChain->addScope(target->getParameterBarrel()); + mScopeChain->addScope(target->getActivation()); + mCurModule = target->getByteCode(); pc = mCurModule->mCodeBase; endPC = mCurModule->mCodeBase + mCurModule->mLength; @@ -799,8 +801,12 @@ JSValue Context::interpret(uint8 *pc, uint8 *endPC) const String &name = *mCurModule->getString(index); PropertyIterator it; if (obj->hasOwnProperty(name, CURRENT_ATTR, Read, &it)) - obj->deleteProperty(name, CURRENT_ATTR); - pushValue(kTrueValue); + if (obj->deleteProperty(name, CURRENT_ATTR)) + pushValue(kTrueValue); + else + pushValue(kFalseValue); + else + pushValue(kTrueValue); } break; case TypeOfOp: @@ -2408,6 +2414,26 @@ JSValue JSValue::valueToInteger(Context *cx, const JSValue& value) return v; } +int32 JSValue::float64ToInt32(float64 d) +{ + d = fd::fmod(d, two32); + d = (d >= 0) ? d : d + two32; + if (d >= two31) + return (int32)(d - two32); + else + return (int32)(d); +} + +uint32 JSValue::float64ToUInt32(float64 d) +{ + bool neg = (d < 0); + d = fd::floor(neg ? -d : d); + d = neg ? -d : d; + d = fd::fmod(d, two32); + d = (d >= 0) ? d : d + two32; + return (uint32)d; +} + JSValue JSValue::valueToInt32(Context *, const JSValue& value) { float64 d; @@ -2433,12 +2459,7 @@ JSValue JSValue::valueToInt32(Context *, const JSValue& value) } if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) ) return JSValue((float64)0); - d = fd::fmod(d, two32); - d = (d >= 0) ? d : d + two32; - if (d >= two31) - return JSValue((float64)(d - two32)); - else - return JSValue((float64)d); + return JSValue((float64)float64ToInt32(d)); } JSValue JSValue::valueToUInt32(Context *, const JSValue& value) @@ -2466,12 +2487,7 @@ JSValue JSValue::valueToUInt32(Context *, const JSValue& value) } if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d)) return JSValue((float64)0); - bool neg = (d < 0); - d = fd::floor(neg ? -d : d); - d = neg ? -d : d; - d = fd::fmod(d, two32); - d = (d >= 0) ? d : d + two32; - return JSValue((float64)d); + return JSValue((float64)float64ToUInt32(d)); } JSValue JSValue::valueToUInt16(Context *, const JSValue& value) diff --git a/mozilla/js2/src/js2runtime.cpp b/mozilla/js2/src/js2runtime.cpp index d8fb6d9ca3d..7c9b14d1763 100644 --- a/mozilla/js2/src/js2runtime.cpp +++ b/mozilla/js2/src/js2runtime.cpp @@ -172,6 +172,16 @@ bool JSObject::hasProperty(const String &name, NamespaceList *names, Access acc, return false; } +bool JSObject::deleteProperty(const String &name, NamespaceList *names) +{ + PropertyIterator i = findNamespacedProperty(name, names); + if ((PROPERTY_ATTR(i) & Property::DontDelete) == 0) { + mProperties.erase(i); + return true; + } + return false; +} + // get a property value JSValue JSObject::getPropertyValue(PropertyIterator &i) @@ -423,6 +433,7 @@ void JSObject::setProperty(Context *cx, const String &name, NamespaceList *names { PropertyIterator i; if (hasProperty(name, names, Write, &i)) { + if (PROPERTY_ATTR(i) & Property::ReadOnly) return; Property *prop = PROPERTY(i); switch (prop->mFlag) { case ValuePointer: @@ -459,6 +470,7 @@ void JSInstance::setProperty(Context *cx, const String &name, NamespaceList *nam { PropertyIterator i; if (hasOwnProperty(name, names, Write, &i)) { + if (PROPERTY_ATTR(i) & Property::ReadOnly) return; Property *prop = PROPERTY(i); switch (prop->mFlag) { case Slot: @@ -536,6 +548,8 @@ void JSArrayInstance::setProperty(Context *cx, const String &name, NamespaceList } } +// get a named property from a string instance, but intercept +// 'length' by returning the known value void JSStringInstance::getProperty(Context *cx, const String &name, NamespaceList *names) { if (name.compare(cx->Length_StringAtom) == 0) { @@ -545,7 +559,9 @@ void JSStringInstance::getProperty(Context *cx, const String &name, NamespaceLis JSInstance::getProperty(cx, name, names); } - +// construct an instance of a type +// - allocate memory for the slots, load the instance variable names into the +// property map. void JSInstance::initInstance(Context *cx, JSType *type) { if (type->mVariableCount) @@ -637,12 +653,18 @@ void ScopeChain::setNameValue(Context *cx, const String& name, AttributeStmtNode { PropertyIterator i; if ((*s)->hasProperty(name, names, Write, &i)) { - if (PROPERTY_KIND(i) == ValuePointer) { + PropertyFlag flag = PROPERTY_KIND(i); + switch (flag) { + case ValuePointer: *PROPERTY_VALUEPOINTER(i) = v; break; - } - else + case Slot: + (*s)->setSlotValue(cx, PROPERTY_INDEX(i), v); + break; + default: ASSERT(false); // what else needs to be implemented ? + } + return; } } cx->getGlobalObject()->defineVariable(cx, name, attr, Object_Type, v); @@ -734,13 +756,49 @@ Reference *ParameterBarrel::genReference(bool /* hasBase */, const String& name, JSValue ParameterBarrel::getSlotValue(Context *cx, uint32 slotIndex) { - // Assume that the appropriate argument chunk is the topmost one + // find the appropriate activation object: + if (cx->mArgumentBase == NULL) {// then must be in eval code, + Activation *prev = cx->mActivationStack.top(); + return prev->mArgumentBase[slotIndex]; + } return cx->mArgumentBase[slotIndex]; } +void ParameterBarrel::setSlotValue(Context *cx, uint32 slotIndex, JSValue &v) +{ + // find the appropriate activation object: + if (cx->mArgumentBase == NULL) {// then must be in eval code, + Activation *prev = cx->mActivationStack.top(); + prev->mArgumentBase[slotIndex] = v; + } + else + cx->mArgumentBase[slotIndex] = v; +} +JSValue Activation::getSlotValue(Context *cx, uint32 slotIndex) +{ + // find the appropriate activation object: + if (cx->mArgumentBase == NULL) {// then must be in eval code, + Activation *prev = cx->mActivationStack.top(); + return prev->mLocals[slotIndex]; + } + return cx->mLocals[slotIndex]; +} + +void Activation::setSlotValue(Context *cx, uint32 slotIndex, JSValue &v) +{ + // find the appropriate activation object: + if (cx->mArgumentBase == NULL) {// then must be in eval code, + Activation *prev = cx->mActivationStack.top(); + prev->mLocals[slotIndex] = v; + } + else + cx->mLocals[slotIndex] =v; +} + + @@ -873,19 +931,19 @@ bool ScopeChain::isPossibleUncheckedFunction(FunctionDefinition *f) { 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; } @@ -1294,15 +1352,9 @@ bool JSType::hasProperty(const String &name, NamespaceList *names, Access acc, P if (hasOwnProperty(name, names, acc, p)) return true; else - -// XXX with this change we get unknown type failure for - if (mSuperType) return mSuperType->hasProperty(name, names, acc, p); else - - - return false; } @@ -1374,9 +1426,9 @@ JSType::JSType(Context *cx, const StringAtom *name, JSType *super, JSObject *pro mPrototypeObject->mPrototype = mSuperType->mPrototypeObject; if (mSuperType) - defineVariable(cx, cx->Prototype_StringAtom, NULL, Object_Type, JSValue(mPrototypeObject)); + defineVariable(cx, cx->Prototype_StringAtom, (NamespaceList *)NULL, Property::ReadOnly | Property::DontDelete, Object_Type, JSValue(mPrototypeObject)); else // must be Object_Type - defineVariable(cx, cx->Prototype_StringAtom, NULL, this, JSValue(mPrototypeObject)); + defineVariable(cx, cx->Prototype_StringAtom, (NamespaceList *)NULL, Property::ReadOnly | Property::DontDelete, this, JSValue(mPrototypeObject)); if (mSuperType) mPrototype = mSuperType->mPrototypeObject; @@ -1849,9 +1901,10 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal } fnc->setArgCounts(cx, reqArgCount, optArgCount, (f->function.restParameter != NULL)); - if (cx->mScopeChain->isPossibleUncheckedFunction(&f->function)) + if (cx->mScopeChain->isPossibleUncheckedFunction(&f->function)) { fnc->setIsPrototype(true); - + fnc->setIsUnchecked(); + } cx->buildRuntimeForFunction(f->function, fnc); ByteCodeGen bcg(cx, cx->mScopeChain); bcg.genCodeForFunction(f->function, f->pos, fnc, false, NULL); @@ -1859,13 +1912,16 @@ static JSValue Function_Constructor(Context *cx, const JSValue& thisValue, JSVal } /***************************************************************/ + JSObject *fncPrototype = Object_Type->newInstance(cx); + fncPrototype->defineVariable(cx, cx->Constructor_StringAtom, (NamespaceList *)NULL, Property::Enumerable, Object_Type, JSValue(fnc)); + fnc->defineVariable(cx, cx->Prototype_StringAtom, (NamespaceList *)NULL, Property::Enumerable, Object_Type, JSValue(fncPrototype)); v = JSValue(fnc); return v; } static JSValue Function_toString(Context *, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { - ASSERT(thisValue.isFunction()); + ASSERT(thisValue.isFunction() || (thisValue.isObject() && (thisValue.object->getType() == Function_Type)) ); return JSValue(new String(widenCString("function () { }"))); } @@ -2085,7 +2141,6 @@ JSFunction::JSFunction(Context *cx, JSType *resultType, ScopeChain *scopeChain) if (Function_Type) // protect against bootstrap mPrototype = Function_Type->mPrototypeObject; mActivation.mContainer = this; - defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Property::NoAttribute, Number_Type, JSValue((float64)0)); } JSFunction::JSFunction(Context *cx, NativeCode *code, JSType *resultType) @@ -2110,7 +2165,6 @@ JSFunction::JSFunction(Context *cx, NativeCode *code, JSType *resultType) if (Function_Type) // protect against bootstrap mPrototype = Function_Type->mPrototypeObject; mActivation.mContainer = this; - defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Property::NoAttribute, Number_Type, JSValue((float64)0)); } JSValue JSFunction::runArgInitializer(Context *cx, uint32 a, const JSValue& thisValue, JSValue *argv, uint32 argc) @@ -2125,7 +2179,7 @@ void JSFunction::setArgCounts(Context *cx, uint32 r, uint32 o, bool hasRest) mRequiredArgs = r; mOptionalArgs = o; mArguments = new ArgumentData[mRequiredArgs + mOptionalArgs + ((hasRest) ? 1 : 0)]; - setProperty(cx, cx->Length_StringAtom, (NamespaceList *)NULL, JSValue((float64)mRequiredArgs)); + defineVariable(cx, cx->Length_StringAtom, (NamespaceList *)NULL, Property::DontDelete | Property::ReadOnly, Number_Type, JSValue((float64)mRequiredArgs)); } @@ -2247,9 +2301,17 @@ void Context::initBuiltins() Function_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[2].name)], Object_Type, funProto); funProto->mType = Function_Type; - Number_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type); + JSObject *numProto = new JSObject(); + Number_Type = new JSType(this, &mWorld.identifiers[widenCString(builtInClasses[3].name)], Object_Type, numProto); + numProto->mType = Number_Type; + numProto->mPrivate = (void *)(new float64(0.0)); + 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); + + JSObject *strProto = new JSStringInstance(this, NULL); + String_Type = new JSStringType(this, &mWorld.identifiers[widenCString(builtInClasses[5].name)], Object_Type, strProto); + strProto->mType = String_Type; + strProto->mPrivate = (void *)(&Empty_StringAtom); JSArrayInstance *arrayProto = new JSArrayInstance(this, NULL); Array_Type = new JSArrayType(this, Object_Type, &mWorld.identifiers[widenCString(builtInClasses[6].name)], Object_Type, arrayProto); @@ -2319,10 +2381,12 @@ void Context::initBuiltins() initClass(Attribute_Type, &builtInClasses[10], NULL); initClass(NamedArgument_Type, &builtInClasses[11], NULL); initClass(Date_Type, &builtInClasses[12], getDateProtos() ); - initClass(Null_Type, &builtInClasses[13], NULL); + initClass(Null_Type, &builtInClasses[13], NULL); Type_Type->defineUnaryOperator(Index, new JSFunction(this, arrayMaker, Type_Type)); + Function_Type->mTypeCast = new JSFunction(this, Function_Constructor, Object_Type); + Array_Type->defineUnaryOperator(Index, new JSFunction(this, Array_GetElement, Object_Type)); Array_Type->defineUnaryOperator(IndexEqual, new JSFunction(this, Array_SetElement, Object_Type)); @@ -2330,6 +2394,8 @@ void Context::initBuiltins() Date_Type->defineStaticMethod(this, widenCString("parse"), NULL, new JSFunction(this, Date_parse, Number_Type)); Date_Type->defineStaticMethod(this, widenCString("UTC"), NULL, new JSFunction(this, Date_UTC, Number_Type)); + String_Type->mTypeCast = new JSFunction(this, String_Constructor, String_Type); + } @@ -2457,17 +2523,18 @@ Context::Context(JSObject **global, World &world, Arena &a, Pragma::Flags flags) initBuiltins(); } + JSType *MathType = new JSType(this, &mWorld.identifiers[widenCString("Math")], Object_Type); + JSObject *mathObj = MathType->newInstance(this); - JSObject *mathObj = Object_Type->newInstance(this); getGlobalObject()->defineVariable(this, Math_StringAtom, (NamespaceList *)(NULL), Property::NoAttribute, 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)); + Number_Type->defineVariable(this, widenCString("MAX_VALUE"), NULL, Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(maxValue)); + Number_Type->defineVariable(this, widenCString("MIN_VALUE"), NULL, Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(minValue)); + Number_Type->defineVariable(this, widenCString("NaN"), NULL, Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(nan)); + Number_Type->defineVariable(this, widenCString("POSITIVE_INFINITY"), NULL, Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(positiveInfinity)); + Number_Type->defineVariable(this, widenCString("NEGATIVE_INFINITY"), NULL, Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(negativeInfinity)); initOperators(); @@ -2628,10 +2695,16 @@ Formatter& operator<<(Formatter& f, const JSValue& value) break; case JSValue::function_tag: if (!value.function->isNative()) { - StringFormatter s; - PrettyPrinter pp(s); - value.function->getFunctionName()->print(pp); - f << "function '" << s.getString() << "'\n" << *value.function->getByteCode(); + FunctionName *fnName = value.function->getFunctionName(); + if (fnName) { + StringFormatter s; + PrettyPrinter pp(s); + fnName->print(pp); + f << "function '" << s.getString() << "'\n" << *value.function->getByteCode(); + } + else { + f << "function anonymous\n" << *value.function->getByteCode(); + } } else f << "function\n"; diff --git a/mozilla/js2/src/js2runtime.h b/mozilla/js2/src/js2runtime.h index b1ab15d65a5..92b6a3f6ae6 100644 --- a/mozilla/js2/src/js2runtime.h +++ b/mozilla/js2/src/js2runtime.h @@ -221,6 +221,8 @@ static const double two31 = 2147483648.0; static float64 float64ToInteger(float64 d); + static int32 float64ToInt32(float64 d); + static uint32 float64ToUInt32(float64 d); int operator==(const JSValue& value) const; @@ -528,16 +530,12 @@ XXX ...couldn't get this to work... // find a property by the given name, and then check to see if there's any // overlap between the supplied attribute list and the property's list. // ***** REWRITE ME -- matching attribute lists for inclusion is a bad idea. - PropertyIterator findNamespacedProperty(const String &name, NamespaceList *names); + virtual PropertyIterator findNamespacedProperty(const String &name, NamespaceList *names); - void deleteProperty(const String &name, NamespaceList *names) - { - PropertyIterator i = findNamespacedProperty(name, names); - mProperties.erase(i); - } + virtual bool deleteProperty(const String &name, NamespaceList *names); // see if the property exists by a specific kind of access - bool hasOwnProperty(const String &name, NamespaceList *names, Access acc, PropertyIterator *p); + virtual bool hasOwnProperty(const String &name, NamespaceList *names, Access acc, PropertyIterator *p); virtual bool hasProperty(const String &name, NamespaceList *names, Access acc, PropertyIterator *p); @@ -602,6 +600,7 @@ XXX ...couldn't get this to work... virtual void defineTempVariable(Context *cx, Reference *&readRef, Reference *&writeRef, JSType *type); virtual JSValue getSlotValue(Context * /*cx*/, uint32 /*slotIndex*/) { ASSERT(false); return kUndefinedValue; } + virtual void setSlotValue(Context * /*cx*/, uint32 /*slotIndex*/, JSValue & /*v*/) { ASSERT(false); } // debug only void printProperties(Formatter &f) const @@ -715,6 +714,10 @@ XXX ...couldn't get this to work... { return JSObject::defineVariable(cx, name, attr, type, v); } + Property *defineVariable(Context *cx, const String &name, NamespaceList *names, PropertyAttribute attrFlags, JSType *type, const JSValue v) + { + return JSObject::defineVariable(cx, name, names, attrFlags, type, v); + } @@ -848,8 +851,8 @@ XXX ...couldn't get this to work... class JSStringType : public JSType { public: - JSStringType(Context *cx, const StringAtom *name, JSType *super) - : JSType(cx, name, super) + JSStringType(Context *cx, const StringAtom *name, JSType *super, JSObject *protoObj = NULL) + : JSType(cx, name, super, protoObj) { } virtual ~JSStringType() { } // keeping gcc happy @@ -886,6 +889,7 @@ XXX ...couldn't get this to work... Reference *genReference(bool hasBase, const String& name, NamespaceList *names, Access acc, uint32 depth); JSValue getSlotValue(Context *cx, uint32 slotIndex); + void setSlotValue(Context *cx, uint32 slotIndex, JSValue &v); }; @@ -971,6 +975,9 @@ XXX ...couldn't get this to work... Reference *genReference(bool hasBase, const String& name, NamespaceList *names, Access acc, uint32 depth); + JSValue getSlotValue(Context *cx, uint32 slotIndex); + void setSlotValue(Context *cx, uint32 slotIndex, JSValue &v); + }; @@ -1083,10 +1090,10 @@ XXX ...couldn't get this to work... } // delete a property from the top object (already know it's there) - void deleteProperty(const String &name, NamespaceList *names) + bool deleteProperty(const String &name, NamespaceList *names) { JSObject *top = mScopeStack.back(); - top->deleteProperty(name, names); + return top->deleteProperty(name, names); } // generate a reference to the given name @@ -1221,11 +1228,12 @@ XXX ...couldn't get this to work... virtual bool isNative() { return (mCode != NULL); } virtual bool isPrototype() { return mIsPrototype; } virtual bool isConstructor() { return mIsConstructor; } - bool isMethod() { return (mClass != NULL); } + virtual bool isMethod() { return (mClass != NULL); } virtual ByteCodeModule *getByteCode() { ASSERT(!isNative()); return mByteCode; } virtual NativeCode *getNativeCode() { ASSERT(isNative()); return mCode; } virtual ParameterBarrel *getParameterBarrel() { return mParameterBarrel; } + virtual Activation *getActivation() { return &mActivation; } virtual JSType *getResultType() { return mResultType; } virtual JSType *getArgType(uint32 a) { ASSERT(mArguments && (a < (mRequiredArgs + mOptionalArgs))); return mArguments[a].mType; } @@ -1284,10 +1292,12 @@ XXX ...couldn't get this to work... bool isNative() { return mFunction->isNative(); } bool isPrototype() { return mFunction->isPrototype(); } bool isConstructor() { return mFunction->isConstructor(); } + bool isMethod() { return mFunction->isMethod(); } ByteCodeModule *getByteCode() { return mFunction->getByteCode(); } NativeCode *getNativeCode() { return mFunction->getNativeCode(); } ParameterBarrel *getParameterBarrel() { return mFunction->mParameterBarrel; } + Activation *getActivation() { return &mFunction->mActivation; } JSType *getResultType() { return mFunction->getResultType(); } JSType *getArgType(uint32 a) { return mFunction->getArgType(a); } bool argHasInitializer(uint32 a){ return mFunction->argHasInitializer(a); } @@ -1316,6 +1326,12 @@ XXX ...couldn't get this to work... { mFunction->setProperty(cx, name, names, v); } bool hasProperty(const String &name, NamespaceList *names, Access acc, PropertyIterator *p) { return mFunction->hasProperty(name, names, acc, p); } + bool hasOwnProperty(const String &name, NamespaceList *names, Access acc, PropertyIterator *p) + { return mFunction->hasOwnProperty(name, names, acc, p); } + PropertyIterator findNamespacedProperty(const String &name, NamespaceList *names) + { return mFunction->findNamespacedProperty(name, names); } + bool deleteProperty(const String &name, NamespaceList *names) + { return mFunction->deleteProperty(name, names); } JSFunction *getFunction() { return mFunction; } diff --git a/mozilla/js2/src/jsmath.cpp b/mozilla/js2/src/jsmath.cpp index 56b1a6e1765..884854002c7 100644 --- a/mozilla/js2/src/jsmath.cpp +++ b/mozilla/js2/src/jsmath.cpp @@ -145,10 +145,12 @@ static JSValue Math_log(Context *cx, const JSValue& /*thisValue*/, JSValue *argv static JSValue Math_max(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) { if (argc == 0) - return kNaNValue; + return kNegativeInfinity; float64 result = argv[0].toNumber(cx).f64; + if (JSDOUBLE_IS_NaN(result)) return kNaNValue; for (uint32 i = 1; i < argc; ++i) { float64 arg = argv[i].toNumber(cx).f64; + if (JSDOUBLE_IS_NaN(arg)) return kNaNValue; if (arg > result) result = arg; } @@ -157,11 +159,13 @@ static JSValue Math_max(Context *cx, const JSValue& /*thisValue*/, JSValue *argv static JSValue Math_min(Context *cx, const JSValue& /*thisValue*/, JSValue *argv, uint32 argc) { if (argc == 0) - return kNaNValue; + return kPositiveInfinity; float64 result = argv[0].toNumber(cx).f64; + if (JSDOUBLE_IS_NaN(result)) return kNaNValue; for (uint32 i = 1; i < argc; ++i) { float64 arg = argv[i].toNumber(cx).f64; - if (arg < result) + if (JSDOUBLE_IS_NaN(arg)) return kNaNValue; + if ((arg < result) || (JSDOUBLE_IS_POSZERO(result) && JSDOUBLE_IS_NEGZERO(arg))) result = arg; } return JSValue(result); @@ -220,25 +224,26 @@ struct { struct MathObjectFunctionDef { char *name; JSFunction::NativeCode *imp; + uint32 length; } MathObjectFunctions[] = { - { "abs", Math_abs }, - { "acos", Math_acos }, - { "asin", Math_asin }, - { "atan", Math_atan }, - { "atan2", Math_atan2 }, - { "ceil", Math_ceil }, - { "cos", Math_cos }, - { "exp", Math_exp }, - { "floor", Math_floor }, - { "log", Math_log }, - { "max", Math_max }, - { "min", Math_min }, - { "pow", Math_pow }, - { "random", Math_random }, - { "round", Math_round }, - { "sin", Math_sin }, - { "sqrt", Math_sqrt }, - { "tan", Math_tan }, + { "abs", Math_abs, 1 }, + { "acos", Math_acos, 1 }, + { "asin", Math_asin, 1 }, + { "atan", Math_atan, 1 }, + { "atan2", Math_atan2, 2 }, + { "ceil", Math_ceil, 1 }, + { "cos", Math_cos, 1 }, + { "exp", Math_exp, 1 }, + { "floor", Math_floor, 1 }, + { "log", Math_log, 1 }, + { "max", Math_max, 2 }, + { "min", Math_min, 2 }, + { "pow", Math_pow, 2 }, + { "random", Math_random, 1 }, + { "round", Math_round, 1 }, + { "sin", Math_sin, 1 }, + { "sqrt", Math_sqrt, 1 }, + { "tan", Math_tan, 1 }, }; void initMathObject(Context *cx, JSObject *mathObj) @@ -246,13 +251,15 @@ void initMathObject(Context *cx, JSObject *mathObj) uint32 i; for (i = 0; i < M_CONSTANTS_COUNT; i++) mathObj->defineVariable(cx, widenCString(MathObjectConstants[i].name), - (NamespaceList *)(NULL), Property::NoAttribute, + (NamespaceList *)(NULL), Property::ReadOnly | Property::DontDelete, Number_Type, JSValue(MathObjectConstants[i].value)); for (i = 0; i < sizeof(MathObjectFunctions) / sizeof(MathObjectFunctionDef); i++) { JSFunction *f = new JSFunction(cx, MathObjectFunctions[i].imp, Number_Type); + f->setArgCounts(cx, MathObjectFunctions[i].length, 0, false); mathObj->defineVariable(cx, widenCString(MathObjectFunctions[i].name), - (NamespaceList *)(NULL), Property::NoAttribute, Number_Type, JSValue(f)); + (NamespaceList *)(NULL), Property::ReadOnly | Property::DontDelete, + Number_Type, JSValue(f)); } } diff --git a/mozilla/js2/src/jsstring.cpp b/mozilla/js2/src/jsstring.cpp index 4c044359288..fd3f60545a3 100644 --- a/mozilla/js2/src/jsstring.cpp +++ b/mozilla/js2/src/jsstring.cpp @@ -124,7 +124,7 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv { ContextStackReplacement csr(cx); - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); JSValue S = thisValue.toString(cx); JSArrayInstance *A = (JSArrayInstance *)Array_Type->newInstance(cx); @@ -147,11 +147,13 @@ static JSValue String_split(Context *cx, const JSValue& thisValue, JSValue *argv if (lim == 0) return JSValue(A); +/* XXX standard requires this, but Monkey doesn't do it and the tests break + if (separatorV.isUndefined()) { A->setProperty(cx, widenCString("0"), NULL, S); return JSValue(A); } - +*/ if (s == 0) { MatchResult z; splitMatch(S.string, 0, R, z); @@ -194,7 +196,7 @@ step11: static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); const String *str = thisValue.toString(cx).string; uint32 pos = 0; @@ -210,7 +212,7 @@ static JSValue String_charAt(Context *cx, const JSValue& thisValue, JSValue *arg static JSValue String_charCodeAt(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); const String *str = thisValue.toString(cx).string; uint32 pos = 0; @@ -225,7 +227,7 @@ static JSValue String_charCodeAt(Context *cx, const JSValue& thisValue, JSValue static JSValue String_concat(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); const String *str = thisValue.toString(cx).string; String *result = new String(*str); @@ -238,7 +240,7 @@ static JSValue String_concat(Context *cx, const JSValue& thisValue, JSValue *arg static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); if (argc == 0) return JSValue(-1.0); @@ -251,10 +253,10 @@ static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *ar if (arg1 < 0) pos = 0; else - if (toUInt32(arg1) >= str->size()) + if (arg1 >= str->size()) pos = str->size(); else - pos = toUInt32(arg1); + pos = arg1; } pos = str->find(*searchStr, pos); if (pos == String::npos) @@ -264,27 +266,26 @@ static JSValue String_indexOf(Context *cx, const JSValue& thisValue, JSValue *ar static JSValue String_lastIndexOf(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); if (argc == 0) return JSValue(-1.0); const String *str = thisValue.toString(cx).string; const String *searchStr = argv[0].toString(cx).string; - uint32 pos = 0; + uint32 pos = str->size(); if (argc > 1) { float64 fpos = argv[1].toNumber(cx).f64; - if (fpos != fpos) + if (JSDOUBLE_IS_NaN(fpos)) pos = str->size(); else { - int32 arg1 = (int32)(fpos); - if (arg1 < 0) + if (fpos < 0) pos = 0; else - if (toUInt32(arg1) >= str->size()) + if (fpos >= str->size()) pos = str->size(); else - pos = toUInt32(arg1); + pos = (int32)(fpos); } } pos = str->rfind(*searchStr, pos); @@ -300,7 +301,7 @@ static JSValue String_localeCompare(Context * /*cx*/, const JSValue& /*thisValue static JSValue String_toLowerCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); JSValue S = thisValue.toString(cx); String *result = new String(*S.string); @@ -312,7 +313,7 @@ static JSValue String_toLowerCase(Context *cx, const JSValue& thisValue, JSValue static JSValue String_toUpperCase(Context *cx, const JSValue& thisValue, JSValue * /*argv*/, uint32 /*argc*/) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); JSValue S = thisValue.toString(cx); String *result = new String(*S.string); @@ -324,7 +325,7 @@ static JSValue String_toUpperCase(Context *cx, const JSValue& thisValue, JSValue static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); const String *sourceString = thisValue.toString(cx).string; uint32 sourceLength = sourceString->size(); @@ -375,34 +376,42 @@ static JSValue String_slice(Context *cx, const JSValue& thisValue, JSValue *argv static JSValue String_substring(Context *cx, const JSValue& thisValue, JSValue *argv, uint32 argc) { - ASSERT(thisValue.isObject()); + ASSERT(thisValue.isObject() || thisValue.isFunction() || thisValue.isType()); const String *sourceString = thisValue.toString(cx).string; uint32 sourceLength = sourceString->size(); uint32 start, end; if (argc > 0) { - int32 arg0 = (int32)(argv[0].toInt32(cx).f64); - if (arg0 < 0) + float64 farg0 = argv[0].toNumber(cx).f64; + if (JSDOUBLE_IS_NaN(farg0) || (farg0 < 0)) start = 0; - else - if (toUInt32(arg0) < sourceLength) - start = toUInt32(arg0); - else + else { + if (!JSDOUBLE_IS_FINITE(farg0)) start = sourceLength; + else { + start = JSValue::float64ToUInt32(farg0); + if (start > sourceLength) + start = sourceLength; + } + } } else start = 0; if (argc > 1) { - int32 arg1 = (int32)(argv[1].toInt32(cx).f64); - if (arg1 < 0) + float64 farg1 = argv[1].toNumber(cx).f64; + if (JSDOUBLE_IS_NaN(farg1) || (farg1 < 0)) end = 0; - else - if (toUInt32(arg1) < sourceLength) - end = toUInt32(arg1); - else + else { + if (!JSDOUBLE_IS_FINITE(farg1)) end = sourceLength; + else { + end = JSValue::float64ToUInt32(farg1); + if (end > sourceLength) + end = sourceLength; + } + } } else end = sourceLength; @@ -427,10 +436,10 @@ Context::PrototypeFunctions *getStringProtos() { "charCodeAt", Number_Type, 1, String_charCodeAt }, { "concat", String_Type, 1, String_concat }, { "indexOf", Number_Type, 1, String_indexOf }, - { "lastIndexOf", Number_Type, 1, String_lastIndexOf }, + { "lastIndexOf", Number_Type, 2, String_lastIndexOf }, // XXX ECMA spec says 1, but tests want 2 XXX { "localeCompare", Number_Type, 1, String_localeCompare }, { "slice", String_Type, 2, String_slice }, - { "split", Array_Type, 2, String_split }, + { "split", Array_Type, 1, String_split }, // XXX ECMA spec says 2, but tests want 1 XXX { "substring", String_Type, 2, String_substring }, { "toSource", String_Type, 0, String_toString }, { "toLocaleUpperCase", String_Type, 0, String_toUpperCase }, // (sic) diff --git a/mozilla/js2/src/numerics.cpp b/mozilla/js2/src/numerics.cpp index 5f67bf89e89..351b3491983 100644 --- a/mozilla/js2/src/numerics.cpp +++ b/mozilla/js2/src/numerics.cpp @@ -1683,6 +1683,8 @@ double JS::stringToDouble(const char16 *str, const char16 *strEnd, const char16 double value = strToDouble(cstr.get(), estr); ptrdiff_t i = estr - cstr.get(); numEnd = i ? str1 + i : str; + if ((value == 0.0) && (i == 0)) + return nan; return value; } diff --git a/mozilla/js2/src/property.h b/mozilla/js2/src/property.h index ef65e783975..c3119dbd696 100644 --- a/mozilla/js2/src/property.h +++ b/mozilla/js2/src/property.h @@ -107,7 +107,9 @@ namespace JS2Runtime { Public = 0x00002000, Private = 0x00004000, Final = 0x00008000, - Const = 0x00010000 + Const = 0x00010000, + DontDelete = 0x00020000, + ReadOnly = 0x00040000 };