зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
5307a7b0c1
Коммит
5611bff89a
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче