Fixes; ECMA3 property attributes. Array index handling.

'object' --> 'Object'.
This commit is contained in:
rogerl%netscape.com 2003-02-24 18:07:12 +00:00
Родитель dd7bb3a66f
Коммит 1e15d1cd0f
9 изменённых файлов: 137 добавлений и 66 удалений

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

@ -326,7 +326,7 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint
stdOut << " Dynamic Properties:\n";
for (DynamicPropertyIterator dpi = pInst->dynamicProperties.begin(), dpend = pInst->dynamicProperties.end(); (dpi != dpend); dpi++) {
stdOut << "\t" << dpi->first << " = " << *meta->toString(dpi->second) << "\n";
stdOut << "\t" << dpi->first << " = " << *meta->toString(dpi->second.value) << "\n";
}
}
}

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

@ -74,13 +74,20 @@ js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length)
// Can't call 'writeDynamicProperty' as that'll just cycle back here for
// ArrayInstances.
DynamicPropertyMap *dMap = &checked_cast<PrototypeInstance *>(obj)->dynamicProperties;
DynamicPropertyIterator i = dMap->find(*meta->engine->length_StringAtom);
if (i != dMap->end()) {
i->second.value = result;
return result;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *meta->engine->length_StringAtom) {
i->second = result;
i->second.value = result;
return result;
}
}
const DynamicPropertyMap::value_type e(*meta->engine->length_StringAtom, result);
*/
const DynamicPropertyMap::value_type e(*meta->engine->length_StringAtom, DynamicPropertyValue(result));
checked_cast<PrototypeInstance *>(obj)->dynamicProperties.insert(e);
}
else {
@ -143,7 +150,8 @@ static js2val Array_toString(JS2Metadata *meta, const js2val thisValue, js2val *
for (uint32 i = 0; i < length; i++) {
mn.name = meta->engine->numberToString(i);
if (meta->readDynamicProperty(arrInst, &mn, &lookup, RunPhase, &result)
&& !JS2VAL_IS_UNDEFINED(result))
&& !JS2VAL_IS_UNDEFINED(result)
&& !JS2VAL_IS_NULL(result) )
s->append(*meta->toString(result));
if (i < (length - 1))
s->append(widenCString(","));
@ -849,7 +857,7 @@ void initArrayObject(JS2Metadata *meta)
FunctionInstance *fInst = new FunctionInstance(meta->functionClass->prototype, meta->functionClass);
fInst->fWrap = callInst->fWrap;
meta->writeDynamicProperty(meta->arrayClass->prototype, new Multiname(&meta->world.identifiers[pf->name], meta->publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
meta->writeDynamicProperty(fInst, new Multiname(meta->engine->length_StringAtom, meta->publicNamespace), true, INT_TO_JS2VAL(pf->length), RunPhase);
fInst->writeProperty(meta, meta->engine->length_StringAtom, INT_TO_JS2VAL(pf->length), DynamicPropertyValue::PERMANENT | DynamicPropertyValue::READONLY);
pf++;
}

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

@ -393,7 +393,7 @@ namespace MetaData {
INIT_STRINGATOM(public),
INIT_STRINGATOM(private),
INIT_STRINGATOM(Function),
INIT_STRINGATOM(object),
INIT_STRINGATOM(Object),
Empty_StringAtom(&world.identifiers[""]),
Dollar_StringAtom(&world.identifiers["$"]),
INIT_STRINGATOM(prototype),
@ -890,7 +890,7 @@ namespace MetaData {
JS2Object::mark(public_StringAtom);
JS2Object::mark(private_StringAtom);
JS2Object::mark(Function_StringAtom);
JS2Object::mark(object_StringAtom);
JS2Object::mark(Object_StringAtom);
JS2Object::mark(Empty_StringAtom);
JS2Object::mark(Dollar_StringAtom);
JS2Object::mark(prototype_StringAtom);

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

@ -189,7 +189,8 @@ public:
int64 checkInteger(js2val x);
JS2Metadata *meta;
JS2Metadata *meta; // engine needs access to 'meta' for the string 'world'
// the environment, error reporter and forIterator object
// Current engine execution state
uint8 *pc;
@ -207,7 +208,7 @@ public:
String *allocStringPtr(const String *s);
String *allocStringPtr(const char *s);
String *numberToString(float64 *number);
String *numberToString(float64 *number); // non-static since they need access to meta
String *numberToString(int32 i);
js2val allocFloat(float32 x);
@ -246,7 +247,7 @@ public:
const String *public_StringAtom;
const String *private_StringAtom;
const String *Function_StringAtom;
const String *object_StringAtom;
const String *Object_StringAtom;
const String *Empty_StringAtom;
const String *Dollar_StringAtom;
const String *prototype_StringAtom;

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

@ -119,7 +119,7 @@ namespace MetaData {
pb = pb->next;
}
if (prototype)
writeDynamicProperty(result, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(pCount), RunPhase);
checked_cast<PrototypeInstance *>(result)->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(pCount), DynamicPropertyValue::READONLY);
pb = fnDef->parameters;
compileFrame->positional = new Variable *[pCount];
compileFrame->positionalCount = pCount;
@ -2948,7 +2948,7 @@ doUnary:
// XXX objectType returns the ECMA4 type, not the [[class]] value, so returns class 'Prototype' for ECMA3 objects
// JS2Class *type = meta->objectType(thisValue);
String s = "[" + *meta->engine->object_StringAtom + " " + *type->getName() + "]";
String s = "[object " + *type->getName() + "]";
return STRING_TO_JS2VAL(meta->engine->allocString(s));
}
@ -3136,7 +3136,7 @@ static const uint8 urlCharType[256] =
SimpleInstance *fInst = new SimpleInstance(functionClass);
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), code);
writeDynamicProperty(glob, new Multiname(&world.identifiers[name], publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
writeDynamicProperty(fInst, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(length), RunPhase);
fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(length), DynamicPropertyValue::READONLY);
}
#define MAKEBUILTINCLASS(c, super, dynamic, allowNull, final, name, defaultVal) c = new JS2Class(super, NULL, new Namespace(engine->private_StringAtom), dynamic, allowNull, final, name); c->complete = true; c->defaultValue = defaultVal;
@ -3156,7 +3156,7 @@ static const uint8 urlCharType[256] =
cxt.openNamespaces.clear();
cxt.openNamespaces.push_back(publicNamespace);
MAKEBUILTINCLASS(objectClass, NULL, false, true, false, engine->object_StringAtom, JS2VAL_VOID);
MAKEBUILTINCLASS(objectClass, NULL, false, true, false, engine->Object_StringAtom, JS2VAL_VOID);
MAKEBUILTINCLASS(undefinedClass, objectClass, false, false, true, engine->undefined_StringAtom, JS2VAL_VOID);
MAKEBUILTINCLASS(nullClass, objectClass, false, true, true, engine->null_StringAtom, JS2VAL_NULL);
MAKEBUILTINCLASS(booleanClass, objectClass, false, false, true, engine->allocStringPtr(&world.identifiers["Boolean"]), JS2VAL_FALSE);
@ -3199,7 +3199,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
writeDynamicProperty(glob, new Multiname(engine->undefined_StringAtom, publicNamespace), true, JS2VAL_UNDEFINED, RunPhase);
writeDynamicProperty(glob, new Multiname(&world.identifiers["NaN"], publicNamespace), true, engine->nanValue, RunPhase);
writeDynamicProperty(glob, new Multiname(&world.identifiers["Infinity"], publicNamespace), true, engine->posInfValue, RunPhase);
// XXX add 'version'
// XXX add 'version()'
writeDynamicProperty(glob, new Multiname(&world.identifiers["version"], publicNamespace), true, INT_TO_JS2VAL(0), RunPhase);
// Function properties of the global object
addGlobalObjectFunction("isNaN", GlobalObject_isNaN, 1);
@ -3230,8 +3230,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
// Adding 'toString' to the Object.prototype XXX Or make this a static class member?
FunctionInstance *fInst = new FunctionInstance(functionClass->prototype, functionClass);
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_VOID, true), Object_toString);
writeDynamicProperty(objectClass->prototype, new Multiname(engine->toString_StringAtom, publicNamespace), true, OBJECT_TO_JS2VAL(fInst), RunPhase);
writeDynamicProperty(fInst, new Multiname(engine->length_StringAtom, publicNamespace), true, INT_TO_JS2VAL(0), RunPhase);
objectClass->prototype->writeProperty(this, engine->toString_StringAtom, OBJECT_TO_JS2VAL(fInst), 0);
fInst->writeProperty(this, engine->length_StringAtom, INT_TO_JS2VAL(0), DynamicPropertyValue::READONLY);
/*** ECMA 3 Date Class ***/
MAKEBUILTINCLASS(dateClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["Date"]), JS2VAL_NULL);
@ -3383,11 +3383,16 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
isPrototypeInstance = true;
dMap = &(checked_cast<PrototypeInstance *>(obj))->dynamicProperties;
}
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end())
return obj;
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
return obj;
}
}
*/
if (isPrototypeInstance) {
PrototypeInstance *pInst = checked_cast<PrototypeInstance *>(obj);
if (pInst->parent)
@ -3413,11 +3418,16 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
isPrototypeInstance = true;
dMap = &(checked_cast<PrototypeInstance *>(obj))->dynamicProperties;
}
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end())
return true;
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
return true;
}
}
*/
return false;
}
@ -3446,12 +3456,19 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
}
if (dMap == NULL)
return false; // 'None'
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end()) {
*rval = i->second.value;
return true;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
*rval = i->second;
return true;
}
}
*/
if (isPrototypeInstance) {
PrototypeInstance *pInst = checked_cast<PrototypeInstance *>(container);
if (pInst->parent)
@ -3464,20 +3481,20 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
return false; // 'None'
}
void SimpleInstance::writeProperty(JS2Metadata * /* meta */, const String *name, js2val newValue)
void SimpleInstance::writeProperty(JS2Metadata * /* meta */, const String *name, js2val newValue, uint32 flags)
{
ASSERT(dynamicProperties);
const DynamicPropertyMap::value_type e(*name, newValue);
const DynamicPropertyMap::value_type e(*name, DynamicPropertyValue(newValue, flags));
dynamicProperties->insert(e);
}
void PrototypeInstance::writeProperty(JS2Metadata * /* meta */, const String *name, js2val newValue)
void PrototypeInstance::writeProperty(JS2Metadata * /* meta */, const String *name, js2val newValue, uint32 flags)
{
const DynamicPropertyMap::value_type e(*name, newValue);
const DynamicPropertyMap::value_type e(*name, DynamicPropertyValue(newValue, flags));
dynamicProperties.insert(e);
}
void ArrayInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue)
void ArrayInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue, uint32 flags)
{
// An index has to pass the test that :
// ToString(ToUint32(ToString(index))) == ToString(index)
@ -3485,14 +3502,22 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
//
// ToString(ToUint32(name)) == name
//
const DynamicPropertyMap::value_type e(*name, newValue);
// XXX things would go faster if the index made it here as an int
// (which it more typically is) rather than converted to string
// and back.
const DynamicPropertyMap::value_type e(*name, DynamicPropertyValue(newValue, flags));
dynamicProperties.insert(e);
const char16 *numEnd;
float64 f = stringToDouble(name->data(), name->data() + name->length(), numEnd);
uint32 index = JS2Engine::float64toUInt32(f);
if (index == f) {
char buf[dtosStandardBufferSize];
const char *chrp = doubleToStr(buf, dtosStandardBufferSize, index, dtosStandard, 0);
if (widenCString(chrp) == *name) {
uint32 length = getLength(meta, this);
if (index >= length)
setLength(meta, this, index + 1);
@ -3518,19 +3543,26 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
dMap = &(checked_cast<PrototypeInstance *>(container))->dynamicProperties;
if (dMap == NULL)
return false; // 'None'
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end()) {
i->second.value = newValue;
return true;
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
i->second = newValue;
i->second.value = newValue;
return true;
}
}
*/
if (!createIfMissing)
return false;
if (container->kind == SimpleInstanceKind) {
SimpleInstance *dynInst = checked_cast<SimpleInstance *>(container);
InstanceBinding *ib = resolveInstanceMemberName(dynInst->type, multiname, ReadAccess, phase);
if (ib == NULL) {
dynInst->writeProperty(this, name, newValue);
dynInst->writeProperty(this, name, newValue, 0);
return true;
}
}
@ -3539,14 +3571,14 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
GlobalObject *glob = checked_cast<GlobalObject *>(container);
LocalMember *m = findFlatMember(glob, multiname, ReadAccess, phase);
if (m == NULL) {
const DynamicPropertyMap::value_type e(*name, newValue);
const DynamicPropertyMap::value_type e(*name, DynamicPropertyValue(newValue));
glob->dynamicProperties.insert(e);
return true;
}
}
else {
PrototypeInstance *pInst = checked_cast<PrototypeInstance *>(container);
pInst->writeProperty(this, name, newValue);
pInst->writeProperty(this, name, newValue, 0);
return true;
}
}
@ -3951,6 +3983,15 @@ deleteClassProperty:
else {
dMap = &(checked_cast<PrototypeInstance *>(container))->dynamicProperties;
}
DynamicPropertyIterator i = dMap->find(*name);
if (i != dMap->end()) {
if ((i->second.flags & DynamicPropertyValue::PERMANENT) == 0) {
dMap->erase(i);
*result = true;
return true;
}
}
/*
for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) {
if (i->first == *name) {
dMap->erase(i);
@ -3958,6 +3999,7 @@ deleteClassProperty:
return true;
}
}
*/
return false;
}
@ -4651,7 +4693,7 @@ deleteClassProperty:
}
if (dynamicProperties) {
for (DynamicPropertyIterator i = dynamicProperties->begin(), end = dynamicProperties->end(); (i != end); i++) {
GCMARKVALUE(i->second);
GCMARKVALUE(i->second.value);
}
}
}
@ -4704,7 +4746,7 @@ deleteClassProperty:
{
GCMARKOBJECT(parent)
for (DynamicPropertyIterator i = dynamicProperties.begin(), end = dynamicProperties.end(); (i != end); i++) {
GCMARKVALUE(i->second);
GCMARKVALUE(i->second.value);
}
}
@ -4794,7 +4836,7 @@ deleteClassProperty:
Frame::markChildren();
GCMARKOBJECT(internalNamespace)
for (DynamicPropertyIterator i = dynamicProperties.begin(), end = dynamicProperties.end(); (i != end); i++) {
GCMARKVALUE(i->second);
GCMARKVALUE(i->second.value);
}
}
@ -4836,8 +4878,7 @@ deleteClassProperty:
ASSERT(plural->positional[i]->cloneContent->kind == Member::Variable);
(checked_cast<Variable *>(plural->positional[i]->cloneContent))->value = argBase[i];
mn.name = meta->engine->numberToString(i);
meta->writeDynamicProperty(arrInst, &mn, true, argBase[i], RunPhase);
arrInst->writeProperty(meta, meta->engine->numberToString(i), argBase[i], 0);
}
setLength(meta, arrInst, i);
}

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

@ -188,7 +188,7 @@ public:
static void mark(const void *p) { ((PondScum *)p)[-1].mark(); }
static void markJS2Value(js2val v);
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue) { ASSERT(false); }
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue, uint32 flags) { ASSERT(false); }
};
@ -368,7 +368,17 @@ public:
// A DYNAMICPROPERTY record describes one dynamic property of one (prototype or class) instance.
typedef std::map<String, js2val> DynamicPropertyMap;
class DynamicPropertyValue {
public:
enum Flags { ENUMERATE = 0x1, READONLY = 0x2, PERMANENT = 0x4 };
DynamicPropertyValue(js2val v) : value(v), flags(ENUMERATE) { }
DynamicPropertyValue(js2val v, uint32 f) : value(v), flags(f) { }
js2val value;
uint32 flags;
};
typedef std::map<String, DynamicPropertyValue> DynamicPropertyMap;
typedef DynamicPropertyMap::iterator DynamicPropertyIterator;
@ -559,6 +569,7 @@ public:
// Instances which do not respond to the function call or new operators are represented as SIMPLEINSTANCE records
// XXX SimpleInstance dynamic properties don't need the ECMA3 property attributes
class SimpleInstance : public JS2Object {
public:
SimpleInstance(JS2Class *type);
@ -573,7 +584,7 @@ public:
virtual void markChildren();
virtual ~SimpleInstance() { }
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue);
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue, uint32 flags);
};
@ -593,7 +604,7 @@ public:
virtual void markChildren();
virtual ~PrototypeInstance() { }
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue);
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue, uint32 flags);
};
@ -657,7 +668,7 @@ class ArrayInstance : public PrototypeInstance {
public:
ArrayInstance(JS2Metadata *meta, JS2Object *parent, JS2Class *type) : PrototypeInstance(parent, type) { setLength(meta, this, 0); }
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue);
virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue, uint32 flags);
virtual ~ArrayInstance() { }
};

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

@ -337,29 +337,34 @@
else {
ASSERT(JS2VAL_IS_OBJECT(a));
if (JS2VAL_IS_NULL(a))
a = STRING_TO_JS2VAL(object_StringAtom);
JS2Object *obj = JS2VAL_TO_OBJECT(a);
switch (obj->kind) {
case MultinameKind:
a = allocString("namespace");
break;
case AttributeObjectKind:
a = allocString("attribute");
break;
case ClassKind:
case MethodClosureKind:
a = STRING_TO_JS2VAL(Function_StringAtom);
break;
case PrototypeInstanceKind:
a = STRING_TO_JS2VAL(checked_cast<PrototypeInstance *>(obj)->type->getName());
break;
case PackageKind:
case GlobalObjectKind:
a = STRING_TO_JS2VAL(object_StringAtom);
break;
case SimpleInstanceKind:
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->type->getName());
break;
a = STRING_TO_JS2VAL(Object_StringAtom);
else {
JS2Object *obj = JS2VAL_TO_OBJECT(a);
switch (obj->kind) {
case MultinameKind:
a = allocString("namespace");
break;
case AttributeObjectKind:
a = allocString("attribute");
break;
case ClassKind:
case MethodClosureKind:
a = STRING_TO_JS2VAL(Function_StringAtom);
break;
case PrototypeInstanceKind:
if (checked_cast<PrototypeInstance *>(obj)->type == meta->functionClass)
a = STRING_TO_JS2VAL(Function_StringAtom);
else
a = STRING_TO_JS2VAL(Object_StringAtom);
break;
case PackageKind:
case GlobalObjectKind:
a = STRING_TO_JS2VAL(Object_StringAtom);
break;
case SimpleInstanceKind:
a = STRING_TO_JS2VAL(checked_cast<SimpleInstance *>(obj)->type->getName());
break;
}
}
}
push(a);

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

@ -139,7 +139,7 @@
baseVal = OBJECT_TO_JS2VAL(aInst);
for (uint16 i = 0; i < argCount; i++) {
b = pop();
const DynamicPropertyMap::value_type e(*numberToString((argCount - 1) - i), b);
const DynamicPropertyMap::value_type e(*numberToString((argCount - 1) - i), DynamicPropertyValue(b));
aInst->dynamicProperties.insert(e);
}
setLength(meta, aInst, argCount);

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

@ -82,12 +82,12 @@ static js2val String_Call(JS2Metadata *meta, const js2val thisValue, js2val argv
js2val String_fromCharCode(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc)
{
String *resultStr = meta->engine->allocStringPtr((String *)NULL); // can't use Empty_StringAtom; because we're modifying this below
resultStr->reserve(argc);
String resultStr;
resultStr.reserve(argc);
for (uint32 i = 0; i < argc; i++)
*resultStr += (char16)(JS2Engine::float64toUInt16(argv[i]));
resultStr += (char16)(JS2Engine::float64toUInt16(meta->toFloat64(argv[i])));
return STRING_TO_JS2VAL(resultStr);
return STRING_TO_JS2VAL(meta->engine->allocStringPtr(&resultStr));
}
static js2val String_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
@ -806,6 +806,11 @@ void initStringObject(JS2Metadata *meta)
meta->defineLocalMember(meta->env, meta->engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
v = new Variable(meta->numberClass, INT_TO_JS2VAL(1), true);
meta->defineLocalMember(meta->env, meta->engine->length_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
SimpleInstance *callInst = new SimpleInstance(meta->functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), String_fromCharCode);
v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(callInst), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers["fromCharCode"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
meta->env->removeTopFrame();
PrototypeFunction *pf = &prototypeFunctions[0];