Fixes all over for E3 test results - gc + ECMA edge cases.

git-svn-id: svn://10.0.0.236/trunk@140790 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rogerl%netscape.com
2003-04-07 07:24:17 +00:00
parent 7bcfb95f5b
commit f9a7202f3e
13 changed files with 260 additions and 138 deletions

View File

@@ -261,28 +261,30 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint
else
if (JS2VAL_IS_OBJECT(argv[0])) {
JS2Object *fObj = JS2VAL_TO_OBJECT(argv[0]);
if (fObj->kind == SimpleInstanceKind) {
SimpleInstance *s = checked_cast<SimpleInstance *>(fObj);
stdOut << "SimpleInstance\n";
if (JS2VAL_IS_OBJECT(s->super))
printFormat(stdOut, "super = 0x%08X\n", s->super);
else
stdOut << "super = " << *metadata->toString(s->super) << '\n';
stdOut << ((s->sealed) ? "sealed " : "not-sealed ") << '\n';
stdOut << "type = " << *s->type->getName() << '\n';
printLocalBindings(&s->localBindings);
if (meta->objectType(argv[0]) == meta->functionClass) {
FunctionWrapper *fWrap;
fWrap = (checked_cast<SimpleInstance *>(fObj))->fWrap;
if (fWrap->code)
stdOut << "<native code>\n";
switch (fObj->kind) {
case SimpleInstanceKind:
{
SimpleInstance *s = checked_cast<SimpleInstance *>(fObj);
stdOut << "SimpleInstance\n";
if (JS2VAL_IS_OBJECT(s->super))
printFormat(stdOut, "super = 0x%08X\n", s->super);
else
dumpBytecode(fWrap->bCon);
stdOut << "super = " << *metadata->toString(s->super) << '\n';
stdOut << ((s->sealed) ? "sealed " : "not-sealed ") << '\n';
stdOut << "type = " << *s->type->getName() << '\n';
printLocalBindings(&s->localBindings);
if (meta->objectType(argv[0]) == meta->functionClass) {
FunctionWrapper *fWrap;
fWrap = (checked_cast<SimpleInstance *>(fObj))->fWrap;
if (fWrap->code)
stdOut << "<native code>\n";
else
dumpBytecode(fWrap->bCon);
}
}
}
else {
if (fObj->kind == ClassKind) {
break;
case ClassKind:
{
JS2Class *c = checked_cast<JS2Class *>(fObj);
stdOut << "class " << *c->getName();
if (c->super)
@@ -309,6 +311,23 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint
}
}
}
break;
case PackageKind:
{
Package *pkg = checked_cast<Package *>(fObj);
stdOut << "Package\n";
if (JS2VAL_IS_OBJECT(pkg->super))
printFormat(stdOut, "super = 0x%08X\n", pkg->super);
else
stdOut << "super = " << *metadata->toString(pkg->super) << '\n';
stdOut << ((pkg->sealed) ? "sealed " : "not-sealed ") << '\n';
printLocalBindings(&pkg->localBindings);
}
break;
default:
stdOut << "<<unimplemented kind " << (int32)(fObj->kind) << ">>\n";
break;
}
}
}

View File

@@ -258,13 +258,14 @@ static js2val Array_join(JS2Metadata *meta, const js2val thisValue, js2val *argv
JS2Object *thisObj = JS2VAL_TO_OBJECT(thatValue);
uint32 length = getLength(meta, thisObj);
const String *separator;
const String *separator = NULL;
DEFINE_ROOTKEEPER(rk1, separator);
if ((argc == 0) || JS2VAL_IS_UNDEFINED(argv[0]))
separator = new String(widenCString(","));
separator = meta->engine->allocStringPtr(",");
else
separator = meta->toString(argv[0]);
String *S = new String();
String *S = new String(); // not engine allocated, doesn't need rooting
JS2Class *c = meta->objectType(thisObj);
for (uint32 k = 0; k < length; k++) {
@@ -537,7 +538,9 @@ static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg)
}
else {
const String *astr = meta->toString(av);
DEFINE_ROOTKEEPER(rk1, astr);
const String *bstr = meta->toString(bv);
DEFINE_ROOTKEEPER(rk2, bstr);
result = astr->compare(*bstr);
}
return result;

View File

@@ -224,6 +224,12 @@ namespace MetaData {
return new (p) String(*s);
}
String *JS2Engine::allocStringPtr(const String *s, uint32 index, uint32 length)
{
String *p = (String *)(JS2Object::alloc(sizeof(String), false));
return new (p) String(*s, index, length);
}
String *JS2Engine::concatStrings(const String *s1, const String *s2)
{
String *p = (String *)(JS2Object::alloc(sizeof(String), false));
@@ -897,8 +903,12 @@ namespace MetaData {
// reset to previous env.
meta->env = activationStackTop->env;
sp = execStack + activationStackTop->execStackBase;
if (!JS2VAL_IS_VOID(activationStackTop->retval)) // XXX might need an actual 'returnValue' flag instead
retval = activationStackTop->retval;
if (!JS2VAL_IS_VOID(activationStackTop->retval)) // XXX might need an actual 'returnValue' flag instead?
// if the value being returned is a non-object, prefer it to the value
// set in the activation frame. [This is the mechanism used to handle
// the automatic return of a new object from an E3 constructor call]
if (!JS2VAL_IS_OBJECT(retval))
retval = activationStackTop->retval;
}
// GC-mark any JS2Objects in the activation frame stack, the execution stack
@@ -1048,6 +1058,17 @@ namespace MetaData {
nameList[length++] = &lbe->name;
}
}
if (length == 0) {
if (obj->kind == SimpleInstanceKind) {
js2val protoval = (checked_cast<SimpleInstance *>(obj))->super;
if (!JS2VAL_IS_NULL(protoval)) {
if (JS2VAL_IS_OBJECT(protoval)) {
obj = JS2VAL_TO_OBJECT(protoval);
return buildNameList(meta);
}
}
}
}
it = 0;
return (length != 0);
}

View File

@@ -210,8 +210,10 @@ public:
js2val allocString(const String *s) { return STRING_TO_JS2VAL(allocStringPtr(s)); }
js2val allocString(const String &s) { return allocString(&s); }
js2val allocString(const char *s) { return STRING_TO_JS2VAL(allocStringPtr(s)); }
js2val allocString(const String *s, uint32 index, uint32 length) { return STRING_TO_JS2VAL(allocStringPtr(s, index, length)); }
String *allocStringPtr(const String *s);
String *allocStringPtr(const char *s);
String *allocStringPtr(const String *s, uint32 index, uint32 length);
String *concatStrings(const String *s1, const String *s2);
String *numberToString(float64 *number); // non-static since they need access to meta

View File

@@ -270,7 +270,7 @@ namespace MetaData {
DEFINE_ROOTKEEPER(rk, runtimeFrame);
runtimeFrame->instantiate(env);
runtimeFrame->thisObject = thisValue;
runtimeFrame->assignArguments(this, fnObj, argv, argc);
runtimeFrame->assignArguments(this, fnObj, argv, argc, argc);
Frame *oldTopFrame = env->getTopFrame();
env->addFrame(runtimeFrame);
try {
@@ -363,7 +363,7 @@ namespace MetaData {
// if that's not available or returns a non primitive, throw a TypeError
JS2Object *obj = JS2VAL_TO_OBJECT(x);
if (obj->kind != SimpleInstanceKind) // therefore, not an E3 object, so just return
if (obj->kind == ClassKind) // therefore, not an E3 object, so just return
return engine->typeofString(x); // the 'typeof' string
if (hint == StringHint) {
@@ -674,19 +674,24 @@ namespace MetaData {
Member *m = meta->findCommonMember(&base, multiname, WriteAccess, true);
if (m == NULL) {
// XXX E3 compatibility...
JS2Object *baseObj = NULL;
DEFINE_ROOTKEEPER(rk, baseObj);
if (JS2VAL_IS_PRIMITIVE(base)) {
base = meta->toObject(base);
if (meta->cxt.E3compatibility)
baseObj = JS2VAL_TO_OBJECT(meta->toObject(base));
}
else
baseObj = JS2VAL_TO_OBJECT(base);
if (createIfMissing
&& JS2VAL_IS_OBJECT(base)
&& ( ((JS2VAL_TO_OBJECT(base)->kind == SimpleInstanceKind) && !checked_cast<SimpleInstance *>(JS2VAL_TO_OBJECT(base))->sealed)
|| ( (JS2VAL_TO_OBJECT(base)->kind == PackageKind) && !checked_cast<Package *>(JS2VAL_TO_OBJECT(base))->sealed)) ) {
&& baseObj
&& ( ((baseObj->kind == SimpleInstanceKind) && !checked_cast<SimpleInstance *>(baseObj)->sealed)
|| ( (baseObj->kind == PackageKind) && !checked_cast<Package *>(baseObj)->sealed)) ) {
QualifiedName qName = multiname->selectPrimaryName(meta);
Multiname *mn = new Multiname(qName);
DEFINE_ROOTKEEPER(rk, mn);
if ( (meta->findBaseInstanceMember(limit, mn, ReadAccess) == NULL)
&& (meta->findCommonMember(&base, mn, ReadAccess, true) == NULL) ) {
meta->createDynamicProperty(JS2VAL_TO_OBJECT(base), &qName, newValue, ReadWriteAccess, false, true);
meta->createDynamicProperty(baseObj, &qName, newValue, ReadWriteAccess, false, true);
return true;
}
}

View File

@@ -310,7 +310,7 @@ void initMathObject(JS2Metadata *meta)
for (i = 0; i < M_CONSTANTS_COUNT; i++)
{
Variable *v = new Variable(meta->numberClass, meta->engine->allocNumber(MathObjectConstants[i].value), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers[MathObjectConstants[i].name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
meta->defineLocalMember(meta->env, &meta->world.identifiers[MathObjectConstants[i].name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
}
meta->env->removeTopFrame();
@@ -343,7 +343,7 @@ void initMathObject(JS2Metadata *meta)
SimpleInstance *callInst = new SimpleInstance(meta, meta->functionClass->prototype, meta->functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, meta->env);
Variable *v = new Variable(meta->functionClass, OBJECT_TO_JS2VAL(callInst), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
meta->defineLocalMember(meta->env, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
// XXX add 'length' as a dynamic property of the method
meta->createDynamicProperty(callInst, meta->engine->length_StringAtom, INT_TO_JS2VAL(pf->length), ReadAccess, true, false);

View File

@@ -118,7 +118,7 @@ namespace MetaData {
// XXX define a static binding for each parameter
Variable *v = new Variable(objectClass, JS2VAL_UNDEFINED, false);
compileFrame->positional[pCount++] = v;
pb->mn = defineLocalMember(env, pb->name, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, pb->pos);
pb->mn = defineLocalMember(env, pb->name, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, pb->pos, true);
pb = pb->next;
}
}
@@ -372,6 +372,9 @@ namespace MetaData {
break;
case StmtNode::Return:
{
Frame *regionalFrame = *env->getRegionalFrame();
if (regionalFrame->kind != ParameterKind)
reportError(Exception::syntaxError, "Return statement not in function", p->pos);
ExprStmtNode *e = checked_cast<ExprStmtNode *>(p);
if (e->expr) {
ValidateExpression(cxt, env, e->expr);
@@ -441,7 +444,7 @@ namespace MetaData {
}
else {
Variable *v = new Variable(functionClass, OBJECT_TO_JS2VAL(fObj), true);
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos, true);
}
}
}
@@ -463,7 +466,7 @@ namespace MetaData {
ASSERT(!prototype); // XXX right?
FunctionInstance *fObj = validateStaticFunction(&f->function, compileThis, prototype, unchecked, cxt, env);
ConstructorMethod *cm = new ConstructorMethod(OBJECT_TO_JS2VAL(fObj));
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, cm, p->pos);
defineLocalMember(env, f->function.name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, cm, p->pos, true);
}
break;
}
@@ -517,7 +520,7 @@ namespace MetaData {
Variable *v = new Variable(FUTURE_TYPE, immutable ? JS2VAL_FUTUREVALUE : JS2VAL_INACCESSIBLE, immutable);
vb->member = v;
v->vb = vb;
vb->mn = defineLocalMember(env, name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
vb->mn = defineLocalMember(env, name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos, true);
bCon->saveMultiname(vb->mn);
}
break;
@@ -560,7 +563,7 @@ namespace MetaData {
if ( ! ((a->memberMod == Attribute::NoModifier) || ((a->memberMod == Attribute::Static) && (env->getTopFrame()->kind == ClassKind))) )
reportError(Exception::definitionError, "Illegal attribute", p->pos);
Variable *v = new Variable(namespaceClass, OBJECT_TO_JS2VAL(new Namespace(&ns->name)), true);
defineLocalMember(env, &ns->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
defineLocalMember(env, &ns->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos, true);
}
break;
case StmtNode::Use:
@@ -622,7 +625,7 @@ namespace MetaData {
JS2Class *c = new JS2Class(superClass, protoVal, new Namespace(engine->private_StringAtom), (a->dynamic || superClass->dynamic), true, final, engine->allocStringPtr(&classStmt->name));
classStmt->c = c;
Variable *v = new Variable(classClass, OBJECT_TO_JS2VAL(c), true);
defineLocalMember(env, &classStmt->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos);
defineLocalMember(env, &classStmt->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos, true);
if (classStmt->body) {
env->addFrame(c);
ValidateStmtList(cxt, env, pl, classStmt->body->statements);
@@ -2424,7 +2427,7 @@ doUnary:
// Attempt the read in each frame in the current environment, stopping at the
// first succesful effort. If the property can't be found in any frame, it's
// an error.
void Environment::lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval)
void Environment::lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval, js2val *base)
{
LookupKind lookup(true, findThis(meta, false));
FrameListIterator fi = getBegin();
@@ -2455,6 +2458,8 @@ doUnary:
js2val withVal = OBJECT_TO_JS2VAL(wf->obj);
JS2Class *limit = meta->objectType(withVal);
result = limit->read(meta, &withVal, limit, multiname, &lookup, phase, rval);
if (result && base)
*base = withVal;
}
break;
}
@@ -2729,7 +2734,7 @@ doUnary:
//
Multiname *JS2Metadata::defineLocalMember(Environment *env, const String *id, NamespaceList *namespaces,
Attribute::OverrideModifier overrideMod, bool xplicit, Access access,
LocalMember *m, size_t pos)
LocalMember *m, size_t pos, bool enumerable)
{
NonWithFrame *innerFrame = checked_cast<NonWithFrame *>(*(env->getBegin()));
if ((overrideMod != Attribute::NoOverride) || (xplicit && innerFrame->kind != PackageKind))
@@ -2789,7 +2794,7 @@ doUnary:
else
lbe = *lbeP;
for (NamespaceListIterator nli = multiname->nsList->begin(), nlend = multiname->nsList->end(); (nli != nlend); nli++) {
LocalBinding *new_b = new LocalBinding(access, m, true);
LocalBinding *new_b = new LocalBinding(access, m, enumerable);
lbe->bindingList.push_back(LocalBindingEntry::NamespaceBinding(*nli, new_b));
}
// Mark the bindings of multiname as Forbidden in all non-innermost frames in the current
@@ -3034,9 +3039,13 @@ rescan:
static js2val GlobalObject_eval(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint32 argc)
{
if (!JS2VAL_IS_STRING(argv[0]))
return argv[0];
return meta->readEvalString(*meta->toString(argv[0]), widenCString("Eval Source"));
if (argc) {
if (!JS2VAL_IS_STRING(argv[0]))
return argv[0];
return meta->readEvalString(*meta->toString(argv[0]), widenCString("Eval Source"));
}
else
return JS2VAL_UNDEFINED;
}
#define JS7_ISHEX(c) ((c) < 128 && isxdigit(c))
@@ -3214,6 +3223,18 @@ static const uint8 urlCharType[256] =
createDynamicProperty(fInst, engine->length_StringAtom, INT_TO_JS2VAL(length), ReadAccess, true, false);
}
static js2val Object_Constructor(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc)
{
if (argc) {
if (JS2VAL_IS_OBJECT(argv[0]))
return argv[0]; // XXX special handling for host objects?
else
return meta->toObject(argv[0]);
}
else
return OBJECT_TO_JS2VAL(new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass));
}
static js2val Object_toString(JS2Metadata *meta, const js2val thisValue, js2val /* argv */ [], uint32 /* argc */)
{
ASSERT(JS2VAL_IS_OBJECT(thisValue));
@@ -3302,19 +3323,20 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
/*** ECMA 3 Object Class ***/
v = new Variable(classClass, OBJECT_TO_JS2VAL(objectClass), true);
defineLocalMember(env, &world.identifiers["Object"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Object"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
// Function properties of the Object prototype object
objectClass->prototype = OBJECT_TO_JS2VAL(new SimpleInstance(this, NULL, objectClass));
objectClass->construct = Object_Constructor;
// Adding "prototype" as a static member of the class - not a dynamic property
env->addFrame(objectClass);
v = new Variable(objectClass, OBJECT_TO_JS2VAL(objectClass->prototype), true);
defineLocalMember(env, engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
env->removeTopFrame();
/*** ECMA 3 Function Class ***/
// Need this initialized early, as subsequent FunctionInstances need the Function.prototype value
v = new Variable(classClass, OBJECT_TO_JS2VAL(functionClass), true);
defineLocalMember(env, &world.identifiers["Function"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Function"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initFunctionObject(this);
// Adding 'toString' to the Object.prototype XXX Or make this a static class member?
@@ -3326,34 +3348,34 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
/*** ECMA 3 Date Class ***/
MAKEBUILTINCLASS(dateClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["Date"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(dateClass), true);
defineLocalMember(env, &world.identifiers["Date"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Date"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initDateObject(this);
/*** ECMA 3 RegExp Class ***/
MAKEBUILTINCLASS(regexpClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["RegExp"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(regexpClass), true);
defineLocalMember(env, &world.identifiers["RegExp"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["RegExp"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initRegExpObject(this);
/*** ECMA 3 String Class ***/
v = new Variable(classClass, OBJECT_TO_JS2VAL(stringClass), true);
defineLocalMember(env, &world.identifiers["String"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["String"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initStringObject(this);
/*** ECMA 3 Number Class ***/
v = new Variable(classClass, OBJECT_TO_JS2VAL(numberClass), true);
defineLocalMember(env, &world.identifiers["Number"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Number"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initNumberObject(this);
/*** ECMA 3 Boolean Class ***/
v = new Variable(classClass, OBJECT_TO_JS2VAL(booleanClass), true);
defineLocalMember(env, &world.identifiers["Boolean"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Boolean"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initBooleanObject(this);
/*** ECMA 3 Math Class ***/
MAKEBUILTINCLASS(mathClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["Math"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(mathClass), true);
defineLocalMember(env, &world.identifiers["Math"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Math"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initMathObject(this);
/*** ECMA 3 Array Class ***/
@@ -3361,31 +3383,31 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
arrayClass->write = arrayWriteProperty;
arrayClass->writePublic = arrayWritePublic;
v = new Variable(classClass, OBJECT_TO_JS2VAL(arrayClass), true);
defineLocalMember(env, &world.identifiers["Array"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Array"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initArrayObject(this);
/*** ECMA 3 Error Classes ***/
MAKEBUILTINCLASS(errorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["Error"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(errorClass), true);
defineLocalMember(env, &world.identifiers["Error"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["Error"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(evalErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["EvalError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(evalErrorClass), true);
defineLocalMember(env, &world.identifiers["EvalError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["EvalError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(rangeErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["RangeError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(rangeErrorClass), true);
defineLocalMember(env, &world.identifiers["RangeError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["RangeError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(referenceErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["ReferenceError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(referenceErrorClass), true);
defineLocalMember(env, &world.identifiers["ReferenceError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["ReferenceError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(syntaxErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["SyntaxError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(syntaxErrorClass), true);
defineLocalMember(env, &world.identifiers["SyntaxError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["SyntaxError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(typeErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["TypeError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(typeErrorClass), true);
defineLocalMember(env, &world.identifiers["TypeError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["TypeError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
MAKEBUILTINCLASS(uriErrorClass, objectClass, true, true, true, engine->allocStringPtr(&world.identifiers["UriError"]), JS2VAL_NULL);
v = new Variable(classClass, OBJECT_TO_JS2VAL(uriErrorClass), true);
defineLocalMember(env, &world.identifiers["UriError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers["UriError"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, true);
initErrorObject(this);
}
@@ -3449,37 +3471,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
return c->isAncestor(objectType(objVal));
}
/*
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)
// (we already have done the 'ToString(index)' part, so require
//
// ToString(ToUint32(name)) == name
//
// 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 char16 *numEnd;
float64 f = stringToDouble(name->data(), name->data() + name->length(), numEnd);
uint32 index = JS2Engine::float64toUInt32(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);
}
}
*/
InstanceMember *JS2Metadata::findLocalInstanceMember(JS2Class *limit, Multiname *multiname, Access access)
{
InstanceMember *result = NULL;
@@ -3714,6 +3705,13 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
return (findCommonMember(&val, mn, ReadWriteAccess, true) != NULL);
}
void JS2Metadata::createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable)
{
DEFINE_ROOTKEEPER(rk, name);
QualifiedName qName(publicNamespace, name);
createDynamicProperty(obj, &qName, initVal, access, sealed, enumerable);
}
// The caller must make sure that the created property does not already exist and does not conflict with any other property.
void JS2Metadata::createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable)
{
@@ -3851,9 +3849,9 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
env->addFrame(builtinClass);
{
Variable *v = new Variable(builtinClass, OBJECT_TO_JS2VAL(builtinClass->prototype), true);
defineLocalMember(env, engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, engine->prototype_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
v = new Variable(builtinClass, INT_TO_JS2VAL(1), true);
defineLocalMember(env, engine->length_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, engine->length_StringAtom, &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
pf = staticFunctions;
if (pf) {
@@ -3861,7 +3859,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
SimpleInstance *callInst = new SimpleInstance(this, functionClass->prototype, functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, env);
v = new Variable(functionClass, OBJECT_TO_JS2VAL(callInst), true);
defineLocalMember(env, &world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
defineLocalMember(env, &world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
createDynamicProperty(callInst, engine->length_StringAtom, INT_TO_JS2VAL(pf->length), ReadAccess, true, false);
pf++;
}
@@ -3874,7 +3872,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
createDynamicProperty(fInst, engine->length_StringAtom, INT_TO_JS2VAL(1), ReadAccess, true, false);
fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), construct, env);
ASSERT(JS2VAL_IS_OBJECT(builtinClass->prototype));
createDynamicProperty(JS2VAL_TO_OBJECT(builtinClass->prototype), &world.identifiers["constructor"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, true);
createDynamicProperty(JS2VAL_TO_OBJECT(builtinClass->prototype), &world.identifiers["constructor"], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false);
pf = protoFunctions;
if (pf) {
@@ -3882,12 +3880,12 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
SimpleInstance *callInst = new SimpleInstance(this, functionClass->prototype, functionClass);
callInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code, env);
Multiname *mn = new Multiname(&world.identifiers[pf->name], &publicNamespaceList);
InstanceMember *m = new InstanceMethod(mn, callInst, true, true);
InstanceMember *m = new InstanceMethod(mn, callInst, true, false);
defineInstanceMember(builtinClass, &cxt, mn->name, mn->nsList, Attribute::NoOverride, false, m, 0);
FunctionInstance *fInst = new FunctionInstance(this, functionClass->prototype, functionClass);
fInst->fWrap = callInst->fWrap;
createDynamicProperty(JS2VAL_TO_OBJECT(builtinClass->prototype), &world.identifiers[pf->name], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, true);
createDynamicProperty(JS2VAL_TO_OBJECT(builtinClass->prototype), &world.identifiers[pf->name], OBJECT_TO_JS2VAL(fInst), ReadWriteAccess, false, false);
createDynamicProperty(fInst, engine->length_StringAtom, INT_TO_JS2VAL(pf->length), ReadAccess, true, false);
pf++;
}
@@ -4106,6 +4104,20 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
GCMARKOBJECT(type);
}
/************************************************************************************
*
* ArrayInstance
*
************************************************************************************/
ArrayInstance::ArrayInstance(JS2Metadata *meta, js2val parent, JS2Class *type)
: SimpleInstance(meta, parent, type)
{
JS2Object *result = this;
DEFINE_ROOTKEEPER(rk1, result);
meta->createDynamicProperty(this, meta->engine->length_StringAtom, INT_TO_JS2VAL(0), ReadWriteAccess, true, false);
}
/************************************************************************************
*
@@ -4117,7 +4129,13 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
: SimpleInstance(meta, parent, type)
{
// Add prototype property
meta->createDynamicProperty(this, meta->engine->prototype_StringAtom, OBJECT_TO_JS2VAL(parent), ReadWriteAccess, false, true);
JS2Object *result = this;
DEFINE_ROOTKEEPER(rk1, result);
JS2Object *obj = new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass);
DEFINE_ROOTKEEPER(rk2, obj);
meta->createDynamicProperty(this, meta->engine->prototype_StringAtom, OBJECT_TO_JS2VAL(obj), ReadWriteAccess, false, true);
}
@@ -4219,7 +4237,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
// Assume that instantiate has been called, the plural frame will contain
// the cloned Variables assigned into this (singular) frame. Use the
// incoming values to initialize the positionals.
void ParameterFrame::assignArguments(JS2Metadata *meta, JS2Object *fnObj, js2val *argBase, uint32 argCount)
// Pad out to 'length' args with undefined values if argCount is insufficient
void ParameterFrame::assignArguments(JS2Metadata *meta, JS2Object *fnObj, js2val *argBase, uint32 argCount, uint32 length)
{
Multiname *mn = new Multiname(NULL, meta->publicNamespace);
DEFINE_ROOTKEEPER(rk1, mn);
@@ -4228,7 +4247,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
ParameterFrame *plural = checked_cast<ParameterFrame *>(pluralFrame);
ASSERT((plural->positionalCount == 0) || (plural->positional != NULL));
SimpleInstance *argsObj = new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass);;
SimpleInstance *argsObj = new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass);
DEFINE_ROOTKEEPER(rk2, argsObj);
// Add the 'arguments' property
@@ -4245,11 +4264,17 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
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->arrayClass->writePublic(meta, OBJECT_TO_JS2VAL(argsObj), meta->arrayClass, meta->engine->numberToString(i), true, argBase[i]);
}
setLength(meta, argsObj, i);
// mn->name = meta->engine->allocStringPtr(&meta->world.identifiers["callee"]);
while (i++ < length) {
if (i < plural->positionalCount) {
ASSERT(plural->positional[i]->cloneContent);
ASSERT(plural->positional[i]->cloneContent->kind == Member::Variable);
(checked_cast<Variable *>(plural->positional[i]->cloneContent))->value = JS2VAL_UNDEFINED;
}
meta->arrayClass->writePublic(meta, OBJECT_TO_JS2VAL(argsObj), meta->arrayClass, meta->engine->numberToString(i), true, JS2VAL_UNDEFINED);
}
setLength(meta, argsObj, argCount);
meta->arrayClass->writePublic(meta, OBJECT_TO_JS2VAL(argsObj), meta->arrayClass, meta->engine->allocStringPtr("callee"), true, OBJECT_TO_JS2VAL(fnObj));
}

View File

@@ -648,7 +648,7 @@ public:
void removeTopFrame() { frameList.pop_front(); }
js2val findThis(JS2Metadata *meta, bool allowPrototypeThis);
void lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval);
void lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval, js2val *base);
void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing);
void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue);
bool lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase);
@@ -821,8 +821,7 @@ public:
// are added.
class ArrayInstance : public SimpleInstance {
public:
ArrayInstance(JS2Metadata *meta, js2val parent, JS2Class *type) : SimpleInstance(meta, parent, type) { }
ArrayInstance(JS2Metadata *meta, js2val parent, JS2Class *type);
virtual ~ArrayInstance() { }
};
@@ -1067,7 +1066,7 @@ public:
uint32 positionalCount;
virtual void instantiate(Environment *env);
void assignArguments(JS2Metadata *meta, JS2Object *fnObj, js2val *argBase, uint32 argCount);
void assignArguments(JS2Metadata *meta, JS2Object *fnObj, js2val *argBase, uint32 argCount, uint32 length);
virtual void markChildren();
virtual ~ParameterFrame() { }
};
@@ -1201,7 +1200,7 @@ public:
InstanceBinding *resolveInstanceMemberName(JS2Class *js2class, Multiname *multiname, Access access, Phase phase, QualifiedName *qname);
DynamicVariable *defineHoistedVar(Environment *env, const String *id, StmtNode *p, bool isVar);
Multiname *defineLocalMember(Environment *env, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, LocalMember *m, size_t pos);
Multiname *defineLocalMember(Environment *env, const String *id, NamespaceList *namespaces, Attribute::OverrideModifier overrideMod, bool xplicit, Access access, LocalMember *m, size_t pos, bool enumerable);
InstanceMember *defineInstanceMember(JS2Class *c, Context *cxt, const String *id, NamespaceList *namespaces,
Attribute::OverrideModifier overrideMod, bool xplicit,
InstanceMember *m, size_t pos);
@@ -1221,8 +1220,7 @@ public:
js2val invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc);
void createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable);
void createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable)
{ QualifiedName qName(publicNamespace, name); createDynamicProperty(obj, &qName, initVal, access, sealed, enumerable); }
void createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable);

View File

@@ -121,7 +121,7 @@ namespace MetaData {
for (i = 0; i < N_CONSTANTS_COUNT; i++)
{
Variable *v = new Variable(meta->numberClass, meta->engine->allocNumber(NumberObjectConstants[i].value), true);
meta->defineLocalMember(meta->env, &meta->world.identifiers[NumberObjectConstants[i].name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0);
meta->defineLocalMember(meta->env, &meta->world.identifiers[NumberObjectConstants[i].name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
}
meta->env->removeTopFrame();

View File

@@ -99,7 +99,7 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
meta->env->lexicalRead(meta, mn, phase, &a, NULL);
push(a);
}
break;
@@ -142,8 +142,9 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
push(JS2VAL_NULL);
b = JS2VAL_NULL;
meta->env->lexicalRead(meta, mn, phase, &a, &b);
push(b);
push(a);
}
break;

View File

@@ -892,7 +892,7 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
meta->env->lexicalRead(meta, mn, phase, &a, NULL);
if (JS2VAL_IS_LONG(a)) {
int64 i = *JS2VAL_TO_LONG(a);
JSLL_ADD(i, i, 1);
@@ -918,7 +918,7 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
meta->env->lexicalRead(meta, mn, phase, &a, NULL);
float64 num = meta->toFloat64(a);
meta->env->lexicalWrite(meta, mn, allocNumber(num - 1.0), true);
pushNumber(num);
@@ -928,7 +928,7 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
meta->env->lexicalRead(meta, mn, phase, &a, NULL);
float64 num = meta->toFloat64(a);
a = pushNumber(num + 1.0);
meta->env->lexicalWrite(meta, mn, a, true);
@@ -938,7 +938,7 @@
{
Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)];
pc += sizeof(short);
meta->env->lexicalRead(meta, mn, phase, &a);
meta->env->lexicalRead(meta, mn, phase, &a, NULL);
float64 num = meta->toFloat64(a);
a = pushNumber(num - 1.0);
meta->env->lexicalWrite(meta, mn, a, true);

View File

@@ -74,7 +74,12 @@
meta->reportError(Exception::badValueError, "Non-object prototype value", errorPos());
}
uint32 length = getLength(meta, obj);
if (fWrap->code) { // native code, pass pointer to argument base
while (argCount < length) {
push(JS2VAL_UNDEFINED);
argCount++;
}
a = fWrap->code(meta, a, base(argCount), argCount);
pop(argCount + 1);
push(a);
@@ -84,7 +89,7 @@
pFrame->instantiate(meta->env);
baseVal = OBJECT_TO_JS2VAL(new SimpleInstance(meta, protoVal, meta->objectType(protoVal)));
pFrame->thisObject = baseVal;
pFrame->assignArguments(meta, obj, base(argCount), argCount);
pFrame->assignArguments(meta, obj, base(argCount), argCount, length);
jsr(phase, fWrap->bCon, base(argCount + 1) - execStack, baseVal, fWrap->env); // seems out of order, but we need to catch the current top frame
meta->env->addFrame(pFrame);
pFrame = NULL;
@@ -119,18 +124,26 @@
a = OBJECT_TO_JS2VAL(g);
}
}
uint32 length = getLength(meta, fObj);
if (fWrap->code) { // native code
Environment *oldEnv = meta->env;
meta->env = fWrap->env;
while (argCount < length) {
push(JS2VAL_UNDEFINED);
argCount++;
}
a = fWrap->code(meta, a, base(argCount), argCount);
pop(argCount + 2);
push(a);
meta->env = oldEnv;
}
else {
pFrame = new ParameterFrame(fWrap->compileFrame);
pFrame->instantiate(meta->env);
pFrame->thisObject = a;
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
// XXX
pFrame->assignArguments(meta, fObj, base(argCount), argCount);
// XXX (use fWrap->compileFrame->signature)
uint32 i = length;
pFrame->assignArguments(meta, fObj, base(argCount), argCount, length);
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID, fWrap->env); // seems out of order, but we need to catch the current top frame
meta->env->addFrame(pFrame);
pFrame = NULL;
@@ -141,18 +154,25 @@
MethodClosure *mc = checked_cast<MethodClosure *>(fObj);
SimpleInstance *fInst = mc->method->fInst;
FunctionWrapper *fWrap = fInst->fWrap;
uint32 length = getLength(meta, fObj);
if (fWrap->code) {
Environment *oldEnv = meta->env;
meta->env = fWrap->env;
while (argCount < length) {
push(JS2VAL_UNDEFINED);
argCount++;
}
a = fWrap->code(meta, mc->thisObject, base(argCount), argCount);
pop(argCount + 2);
push(a);
meta->env = oldEnv;
}
else {
pFrame = new ParameterFrame(fWrap->compileFrame);
pFrame->instantiate(meta->env);
pFrame->thisObject = mc->thisObject;
// assignArguments(runtimeFrame, fWrap->compileFrame->signature);
pFrame->assignArguments(meta, fObj, base(argCount), argCount);
pFrame->assignArguments(meta, fObj, base(argCount), argCount, length);
jsr(phase, fWrap->bCon, base(argCount + 2) - execStack, JS2VAL_VOID, fWrap->env); // seems out of order, but we need to catch the current top frame
meta->env->addFrame(meta->objectType(mc->thisObject));
meta->env->addFrame(pFrame);

View File

@@ -119,7 +119,11 @@ static js2val String_valueOf(JS2Metadata *meta, const js2val thisValue, js2val *
*/
static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
js2val S = STRING_TO_JS2VAL(meta->toString(thisValue));
const String *str = NULL;
DEFINE_ROOTKEEPER(rk, str);
str = meta->toString(thisValue);
js2val S = STRING_TO_JS2VAL(str);
js2val regexp = argv[0];
@@ -129,7 +133,6 @@ static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *a
}
REState *pState = (checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(regexp)))->mRegExp;
const String *str = JS2VAL_TO_STRING(S);
REMatchState *match = REExecute(pState, str->begin(), 0, (int32)str->length(), false);
if (match)
return meta->engine->allocNumber((float64)(match->startIndex));
@@ -265,6 +268,7 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr,
static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *S = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, S);
js2val searchValue = JS2VAL_UNDEFINED;
js2val replaceValue = JS2VAL_UNDEFINED;
@@ -272,6 +276,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
if (argc > 0) searchValue = argv[0];
if (argc > 1) replaceValue = argv[1];
const String *replaceStr = meta->toString(replaceValue);
DEFINE_ROOTKEEPER(rk2, replaceStr);
if (meta->objectType(searchValue) != meta->regexpClass) {
RegExpInstance *reInst = checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(searchValue));
@@ -280,13 +285,13 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
String newString;
int32 lastIndex = 0;
while (true) {
while (true) {
match = REExecute(pState, S->begin(), lastIndex, toInt32(S->length()), false);
if (match) {
String insertString;
uint32 start = 0;
while (true) {
// look for '$' in the replacement string and interpret it as necessary
// look for '$' in the replacement string and interpret it as necessary
uint32 dollarPos = replaceStr->find('$', start);
if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) {
uint32 skip;
@@ -295,7 +300,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
start = dollarPos + skip;
}
else {
// otherwise, absorb the entire replacement string
// otherwise, absorb the entire replacement string
insertString += replaceStr->substr(start, replaceStr->length() - start);
break;
}
@@ -318,6 +323,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
}
else {
const String *searchStr = meta->toString(searchValue);
DEFINE_ROOTKEEPER(rk3, searchStr);
REMatchState match;
uint32 pos = S->find(*searchStr, 0);
if (pos == String::npos)
@@ -402,10 +408,12 @@ static void regexpSplitMatch(JS2Metadata *meta, const String *S, uint32 q, RESta
static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *S = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk0, S);
js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta, meta->arrayClass->prototype, meta->arrayClass));
ArrayInstance *A = checked_cast<ArrayInstance *>(JS2VAL_TO_OBJECT(result));
DEFINE_ROOTKEEPER(rk, A);
DEFINE_ROOTKEEPER(rk1, A);
setLength(meta, A, 0);
uint32 lim;
js2val separatorV = (argc > 0) ? argv[0] : JS2VAL_UNDEFINED;
@@ -448,11 +456,14 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar
return result;
}
String *T = NULL;
DEFINE_ROOTKEEPER(rk2, T);
while (true) {
uint32 q = p;
step11:
if (q == s) {
js2val v = meta->engine->allocString(new String(*S, p, (s - p)));
js2val v = meta->engine->allocString(S, p, (s - p));
meta->arrayClass->writePublic(meta, OBJECT_TO_JS2VAL(A), meta->arrayClass, meta->engine->numberToString(getLength(meta, A)), true, v);
return result;
}
@@ -470,7 +481,7 @@ step11:
q = q + 1;
goto step11;
}
String *T = meta->engine->allocStringPtr(new String(*S, p, (q - p))); // XXX
T = meta->engine->allocStringPtr(S, p, (q - p)); // XXX
js2val v = STRING_TO_JS2VAL(T);
meta->arrayClass->writePublic(meta, OBJECT_TO_JS2VAL(A), meta->arrayClass, meta->engine->numberToString(getLength(meta, A)), true, v);
if (getLength(meta, A) == lim)
@@ -488,6 +499,7 @@ step11:
static js2val String_charAt(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk, str);
uint32 pos = 0;
if (argc > 0)
@@ -503,6 +515,7 @@ static js2val String_charAt(JS2Metadata *meta, const js2val thisValue, js2val *a
static js2val String_charCodeAt(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk, str);
uint32 pos = 0;
if (argc > 0)
@@ -517,7 +530,9 @@ static js2val String_charCodeAt(JS2Metadata *meta, const js2val thisValue, js2va
static js2val String_concat(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, str);
String *result = meta->engine->allocStringPtr(str);
DEFINE_ROOTKEEPER(rk2, result);
for (uint32 i = 0; i < argc; i++) {
*result += *meta->toString(argv[i]);
@@ -532,7 +547,9 @@ static js2val String_indexOf(JS2Metadata *meta, const js2val thisValue, js2val *
return meta->engine->allocNumber(-1.0);
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, str);
const String *searchStr = meta->toString(argv[0]);
DEFINE_ROOTKEEPER(rk2, searchStr);
uint32 pos = 0;
if (argc > 1) {
@@ -559,7 +576,9 @@ static js2val String_lastIndexOf(JS2Metadata *meta, const js2val thisValue, js2v
return meta->engine->allocNumber(-1.0);
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, str);
const String *searchStr = meta->toString(argv[0]);
DEFINE_ROOTKEEPER(rk2, searchStr);
uint32 pos = str->size();
if (argc > 1) {
@@ -589,9 +608,12 @@ static js2val String_localeCompare(JS2Metadata * /* meta */, const js2val /*this
static js2val String_toLowerCase(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
js2val S = STRING_TO_JS2VAL(meta->toString(thisValue));
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, str);
js2val S = STRING_TO_JS2VAL(str);
String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S));
String *result = meta->engine->allocStringPtr(str);
DEFINE_ROOTKEEPER(rk2, result);
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
*i = toLower(*i);
@@ -600,9 +622,12 @@ static js2val String_toLowerCase(JS2Metadata *meta, const js2val thisValue, js2v
static js2val String_toUpperCase(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/)
{
js2val S = STRING_TO_JS2VAL(meta->toString(thisValue));
const String *str = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, str);
js2val S = STRING_TO_JS2VAL(str);
String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S));
DEFINE_ROOTKEEPER(rk2, result);
for (String::iterator i = result->begin(), end = result->end(); i != end; i++)
*i = toUpper(*i);
@@ -633,6 +658,7 @@ static js2val String_toUpperCase(JS2Metadata *meta, const js2val thisValue, js2v
static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *sourceString = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, sourceString);
uint32 sourceLength = sourceString->size();
uint32 start, end;
@@ -705,6 +731,7 @@ static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *ar
static js2val String_substring(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
const String *sourceString = meta->toString(thisValue);
DEFINE_ROOTKEEPER(rk1, sourceString);
uint32 sourceLength = sourceString->size();
uint32 start, end;
@@ -785,6 +812,7 @@ void initStringObject(JS2Metadata *meta)
};
StringInstance *strInst = new StringInstance(meta, meta->objectClass->prototype, meta->stringClass);
DEFINE_ROOTKEEPER(rk1, strInst);
meta->stringClass->prototype = OBJECT_TO_JS2VAL(strInst);
strInst->mValue = meta->engine->allocStringPtr("");