From daf40fb71489ab13e9b93fb342c591ebf7a2a5ee Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Mon, 24 Feb 2003 18:07:12 +0000 Subject: [PATCH] Fixes; ECMA3 property attributes. Array index handling. 'object' --> 'Object'. git-svn-id: svn://10.0.0.236/trunk@138345 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/epimetheus.cpp | 2 +- mozilla/js2/src/js2array.cpp | 16 +++-- mozilla/js2/src/js2engine.cpp | 4 +- mozilla/js2/src/js2engine.h | 7 ++- mozilla/js2/src/js2metadata.cpp | 87 ++++++++++++++++++++-------- mozilla/js2/src/js2metadata.h | 21 +++++-- mozilla/js2/src/js2op_invocation.cpp | 51 ++++++++-------- mozilla/js2/src/js2op_literal.cpp | 2 +- mozilla/js2/src/js2string.cpp | 13 +++-- 9 files changed, 137 insertions(+), 66 deletions(-) diff --git a/mozilla/js2/src/epimetheus.cpp b/mozilla/js2/src/epimetheus.cpp index 91156b1083d..66b93d0b465 100644 --- a/mozilla/js2/src/epimetheus.cpp +++ b/mozilla/js2/src/epimetheus.cpp @@ -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"; } } } diff --git a/mozilla/js2/src/js2array.cpp b/mozilla/js2/src/js2array.cpp index 3aab4dfc9ba..1d6fc0f8004 100644 --- a/mozilla/js2/src/js2array.cpp +++ b/mozilla/js2/src/js2array.cpp @@ -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(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(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++; } diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 035ebde7c51..8267e7da426 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -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); diff --git a/mozilla/js2/src/js2engine.h b/mozilla/js2/src/js2engine.h index 4ca1913f783..2f631918735 100644 --- a/mozilla/js2/src/js2engine.h +++ b/mozilla/js2/src/js2engine.h @@ -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; diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 5b922bc518b..676feab6b3c 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -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(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(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(obj); if (pInst->parent) @@ -3413,11 +3418,16 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... isPrototypeInstance = true; dMap = &(checked_cast(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(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(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(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(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(container); - pInst->writeProperty(this, name, newValue); + pInst->writeProperty(this, name, newValue, 0); return true; } } @@ -3951,6 +3983,15 @@ deleteClassProperty: else { dMap = &(checked_cast(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(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); } diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 9660dc18fe2..608176c1079 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -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 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 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() { } }; diff --git a/mozilla/js2/src/js2op_invocation.cpp b/mozilla/js2/src/js2op_invocation.cpp index ad4c45d6f36..00f1eba2f95 100644 --- a/mozilla/js2/src/js2op_invocation.cpp +++ b/mozilla/js2/src/js2op_invocation.cpp @@ -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(obj)->type->getName()); - break; - case PackageKind: - case GlobalObjectKind: - a = STRING_TO_JS2VAL(object_StringAtom); - break; - case SimpleInstanceKind: - a = STRING_TO_JS2VAL(checked_cast(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(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(obj)->type->getName()); + break; + } } } push(a); diff --git a/mozilla/js2/src/js2op_literal.cpp b/mozilla/js2/src/js2op_literal.cpp index 1e311a6e98b..bf60853cb56 100644 --- a/mozilla/js2/src/js2op_literal.cpp +++ b/mozilla/js2/src/js2op_literal.cpp @@ -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); diff --git a/mozilla/js2/src/js2string.cpp b/mozilla/js2/src/js2string.cpp index 62ca3a38f72..e7610ff9cce 100644 --- a/mozilla/js2/src/js2string.cpp +++ b/mozilla/js2/src/js2string.cpp @@ -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];