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.
This commit is contained in:
rogerl%netscape.com 2001-10-16 18:58:42 +00:00
Родитель 5307a7b0c1
Коммит 5611bff89a
7 изменённых файлов: 253 добавлений и 128 удалений

Просмотреть файл

@ -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)

Просмотреть файл

@ -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";

Просмотреть файл

@ -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; }

Просмотреть файл

@ -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));
}
}

Просмотреть файл

@ -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)

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -107,7 +107,9 @@ namespace JS2Runtime {
Public = 0x00002000,
Private = 0x00004000,
Final = 0x00008000,
Const = 0x00010000
Const = 0x00010000,
DontDelete = 0x00020000,
ReadOnly = 0x00040000
};