diff --git a/mozilla/js2/src/bytecodecontainer.cpp b/mozilla/js2/src/bytecodecontainer.cpp index 0c82f2caf28..323cc952de3 100644 --- a/mozilla/js2/src/bytecodecontainer.cpp +++ b/mozilla/js2/src/bytecodecontainer.cpp @@ -155,6 +155,9 @@ namespace MetaData { for (std::vector::iterator fi = mFrameList.begin(), fend = mFrameList.end(); (fi != fend); fi++) { GCMARKOBJECT(*fi); } + for (std::vector::iterator ri = mRegExpList.begin(), rend = mRegExpList.end(); (ri != rend); ri++) { + GCMARKOBJECT(*ri); + } } } diff --git a/mozilla/js2/src/bytecodecontainer.h b/mozilla/js2/src/bytecodecontainer.h index c3a36253608..c3711604137 100644 --- a/mozilla/js2/src/bytecodecontainer.h +++ b/mozilla/js2/src/bytecodecontainer.h @@ -148,12 +148,13 @@ public: // XXX We lose StringAtom here (and is it safe to stash the address of a StringAtom?) // - is there any way of keeping StringAtoms themselves in a bytecodeContainer? - void addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); addPointer(x); } + void addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); mRegExpList.push_back(x); addShort(mRegExpList.size() - 1); } typedef std::vector CodeBuffer; CodeBuffer mBuffer; + std::vector mRegExpList; // gc tracking std::vector mMultinameList; // gc tracking std::vector mFrameList; // gc tracking diff --git a/mozilla/js2/src/epimetheus.cpp b/mozilla/js2/src/epimetheus.cpp index 72838be2118..3b2857c618f 100644 --- a/mozilla/js2/src/epimetheus.cpp +++ b/mozilla/js2/src/epimetheus.cpp @@ -146,7 +146,7 @@ static int readEvalPrint(FILE *in) metadata->ValidateStmtList(parsedStatements); js2val rval = metadata->ExecuteStmtList(RunPhase, parsedStatements); if (!JS2VAL_IS_VOID(rval)) - stdOut << *metadata->engine->toString(rval) << '\n'; + stdOut << *metadata->toString(rval) << '\n'; } } clear(buffer); @@ -204,7 +204,7 @@ using namespace MetaData; js2val print(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc) { for (uint32 i = 0; i < argc; i++) { - stdOut << *metadata->engine->toString(argv[i]) << '\n'; + stdOut << *metadata->toString(argv[i]) << '\n'; } return JS2VAL_UNDEFINED; } @@ -212,7 +212,7 @@ js2val print(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 ar js2val load(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 argc) { if (argc) - return meta->readEvalFile(*meta->engine->toString(argv[0])); + return meta->readEvalFile(*meta->toString(argv[0])); else return JS2VAL_UNDEFINED; } diff --git a/mozilla/js2/src/js2array.cpp b/mozilla/js2/src/js2array.cpp new file mode 100644 index 00000000000..3e09239f5f1 --- /dev/null +++ b/mozilla/js2/src/js2array.cpp @@ -0,0 +1,852 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the JavaScript 2 Prototype. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ + +#ifdef _WIN32 + // Turn off warnings about identifiers too long in browser information +#pragma warning(disable: 4786) +#pragma warning(disable: 4711) +#pragma warning(disable: 4710) +#endif + +#include +#include +#include + +#include "world.h" +#include "utilities.h" +#include "js2value.h" +#include "numerics.h" +#include "reader.h" +#include "parser.h" +#include "regexp.h" +#include "js2engine.h" +#include "bytecodecontainer.h" +#include "js2metadata.h" + +namespace JavaScript { +namespace MetaData { + +uint32 getLength(JS2Metadata *meta, JS2Object *obj) +{ + Multiname mn(meta->engine->length_StringAtom, meta->publicNamespace); + LookupKind lookup(false, NULL); + uint32 length = 0; + js2val result; + if (meta->readDynamicProperty(obj, &mn, &lookup, RunPhase, &result)) + length = toUInt32(meta->toInteger(result)); + return length; +} + +js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length) +{ + Multiname mn(meta->engine->length_StringAtom, meta->publicNamespace); + js2val result = meta->engine->allocNumber(length); + meta->writeDynamicProperty(obj, &mn, true, result, RunPhase); + return result; +} + +js2val Array_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) +{ + js2val thatValue = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass)); + ArrayInstance *arrInst = checked_cast(JS2VAL_TO_OBJECT(thatValue)); + if (argc > 0) { + if (argc == 1) { + if (JS2VAL_IS_NUMBER(argv[0])) { + uint32 i = (uint32)(meta->toFloat64(argv[0])); + if (i == meta->toFloat64(argv[0])) + setLength(meta, arrInst, i); + else + meta->reportError(Exception::rangeError, "Array length too large", meta->engine->errorPos()); + } + else { + setLength(meta, arrInst, 1); + Multiname mn(meta->toString((int32)0), meta->publicNamespace); + meta->writeDynamicProperty(arrInst, &mn, true, argv[0], RunPhase); + delete mn.name; + } + } + else { + Multiname mn(NULL, meta->publicNamespace); + setLength(meta, arrInst, argc); + for (uint32 i = 0; i < argc; i++) { + mn.name = meta->toString(i); + meta->writeDynamicProperty(arrInst, &mn, true, argv[i], RunPhase); + delete mn.name; + } + } + } + return thatValue; +} + +static js2val Array_toString(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) +{ + if (meta->objectType(thisValue) != meta->arrayClass) + meta->reportError(Exception::typeError, "Array.prototype.toString called on a non Array", meta->engine->errorPos()); + + ArrayInstance *arrInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); + uint32 length = getLength(meta, arrInst); + + if (length == 0) + return STRING_TO_JS2VAL(meta->engine->allocString(meta->engine->Empty_StringAtom)); + else { + Multiname mn(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + js2val result; + String *s = new String(); + for (uint32 i = 0; i < length; i++) { + mn.name = meta->toString(i); + if (meta->readDynamicProperty(arrInst, &mn, &lookup, RunPhase, &result) + && !JS2VAL_IS_UNDEFINED(result)) + s->append(*meta->toString(result)); + if (i < (length - 1)) + s->append(widenCString(",")); + delete mn.name; + } + result = meta->engine->allocString(s); + delete s; + return result; + } + +} + +static js2val Array_toSource(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) +{ + if (meta->objectType(thisValue) != meta->arrayClass) + meta->reportError(Exception::typeError, "Array.prototype.toString called on a non Array", meta->engine->errorPos()); + + ArrayInstance *arrInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); + uint32 length = getLength(meta, arrInst); + + if (length == 0) + return meta->engine->allocString("[]"); + else { + Multiname mn(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + js2val result; + String *s = new String(); + for (uint32 i = 0; i < length; i++) { + mn.name = meta->toString(i); + if (meta->readDynamicProperty(arrInst, &mn, &lookup, RunPhase, &result) + && !JS2VAL_IS_UNDEFINED(result)) + s->append(*meta->toString(result)); + if (i < (length - 1)) + s->append(widenCString(",")); + delete mn.name; + } + s->append(widenCString("]")); + result = meta->engine->allocString(s); + delete s; + return result; + } + +} + +static js2val Array_push(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + Multiname mn(NULL, meta->publicNamespace); + for (uint32 i = 0; i < argc; i++) { + mn.name = meta->toString(i); + meta->writeDynamicProperty(thisObj, &mn, true, argv[i], RunPhase); + delete mn.name; + } + return setLength(meta, thisObj, length + argc); +} + +static js2val Array_pop(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + if (length > 0) { + Multiname mn(meta->toString(length - 1), meta->publicNamespace); + LookupKind lookup(false, NULL); + const String *id = meta->toString(length - 1); + js2val result = JS2VAL_UNDEFINED; + bool deleteResult; + meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &result); + meta->deleteProperty(thisValue, &mn, &lookup, RunPhase, &deleteResult); + setLength(meta, thisObj, length - 1); + delete mn.name; + return result; + } + else + return JS2VAL_UNDEFINED; +} + +js2val Array_concat(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + js2val E = thisValue; + + js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass)); + ArrayInstance *A = checked_cast(JS2VAL_TO_OBJECT(result)); + uint32 n = 0; + uint32 i = 0; + Multiname mn(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + + do { + if (meta->objectType(E) != meta->arrayClass) { + mn.name = meta->toString(n++); + meta->writeDynamicProperty(A, &mn, true, E, RunPhase); + delete mn.name; + } + else { + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *arrObj = JS2VAL_TO_OBJECT(E); + uint32 length = getLength(meta, arrObj); + for (uint32 k = 0; k < length; k++) { + mn.name = meta->toString(k); + js2val rval = JS2VAL_UNDEFINED; + meta->readDynamicProperty(arrObj, &mn, &lookup, RunPhase, &rval); + delete mn.name; + mn.name = meta->toString(n++); + meta->writeDynamicProperty(A, &mn, true, rval, RunPhase); + delete mn.name; + } + } + E = argv[i++]; + } while (i <= argc); + + return result; +} + +static js2val Array_join(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + const String *separator; + if ((argc == 0) || JS2VAL_IS_UNDEFINED(argv[0])) + separator = new String(widenCString(",")); + else + separator = meta->toString(argv[0]); + + String *S = new String(); + Multiname mn(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + + for (uint32 k = 0; k < length; k++) { + js2val result = JS2VAL_UNDEFINED; + mn.name = meta->toString(k); + meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &result); + if (!JS2VAL_IS_UNDEFINED(result) && !JS2VAL_IS_NULL(result)) + *S += *meta->toString(result); + + if (k < (length - 1)) + *S += *separator; + delete mn.name; + } + + return meta->engine->allocString(S); +} + +static js2val Array_reverse(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + Multiname mn1(NULL, meta->publicNamespace); + Multiname mn2(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + + uint32 halfway = length / 2; + + for (uint32 k = 0; k < halfway; k++) { + bool deleteResult; + js2val result1 = JS2VAL_UNDEFINED; + js2val result2 = JS2VAL_UNDEFINED; + mn1.name = meta->toString(k); + mn2.name = meta->toString(length - k - 1); + + if (meta->hasOwnProperty(thisObj, mn1.name)) { + if (meta->hasOwnProperty(thisObj, mn2.name)) { + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result1); + meta->readDynamicProperty(thisObj, &mn2, &lookup, RunPhase, &result2); + meta->writeDynamicProperty(thisObj, &mn1, true, result2, RunPhase); + meta->writeDynamicProperty(thisObj, &mn2, true, result1, RunPhase); + } + else { + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result1); + meta->writeDynamicProperty(thisObj, &mn2, true, result1, RunPhase); + meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult); + } + } + else { + if (meta->hasOwnProperty(thisObj, mn2.name)) { + meta->readDynamicProperty(thisObj, &mn2, &lookup, RunPhase, &result2); + meta->writeDynamicProperty(thisObj, &mn1, true, result2, RunPhase); + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + } + else { + meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult); + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + } + } + delete mn1.name; + delete mn2.name; + } + + return thisValue; +} + +static js2val Array_shift(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + if (length == 0) { + setLength(meta, thisObj, 0); + return JS2VAL_UNDEFINED; + } + + Multiname mn1(NULL, meta->publicNamespace); + Multiname mn2(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + js2val result; + bool deleteResult; + mn1.name = meta->toString((int32)0); + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result); + delete mn1.name; + + for (uint32 k = 1; k < length; k++) { + mn1.name = meta->toString(k); + mn2.name = meta->toString(k - 1); + + if (meta->hasOwnProperty(thisObj, mn1.name)) { + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &result); + meta->writeDynamicProperty(thisObj, &mn2, true, result, RunPhase); + } + else + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + delete mn1.name; + delete mn2.name; + } + + mn1.name = meta->toString(length - 1); + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + delete mn1.name; + setLength(meta, thisObj, length - 1); + return result; +} + +static js2val Array_slice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + + js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass)); + ArrayInstance *A = checked_cast(JS2VAL_TO_OBJECT(result)); + + uint32 length = getLength(meta, thisObj); + + uint32 start, end; + if (argc < 1) + start = 0; + else { + int32 arg0 = meta->toInteger(argv[0]); + if (arg0 < 0) { + arg0 += length; + if (arg0 < 0) + start = 0; + else + start = toUInt32(arg0); + } + else { + if (toUInt32(arg0) >= length) // cast ok since > 0 + start = length; + else + start = toUInt32(arg0); + } + } + + if (argc < 2) + end = length; + else { + int32 arg1 = meta->toInteger(argv[1]); + if (arg1 < 0) { + arg1 += length; + if (arg1 < 0) + end = 0; + else + end = toUInt32(arg1); + } + else { + if (toUInt32(arg1) >= length) + end = length; + else + end = toUInt32(arg1); + } + } + + Multiname mn1(NULL, meta->publicNamespace); + Multiname mn2(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + uint32 n = 0; + while (start < end) { + mn1.name = meta->toString(start); + if (meta->hasOwnProperty(thisObj, mn1.name)) { + js2val rval; + mn2.name = meta->toString(n); + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval); + meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase); + delete mn2.name; + } + n++; + start++; + delete mn1.name; + } + setLength(meta, A, n); + return result; +} + +typedef struct CompareArgs { + JS2Metadata *meta; + JS2Object *target; +} CompareArgs; + +typedef struct QSortArgs { + js2val *vec; + js2val *pivot; + CompareArgs *arg; +} QSortArgs; + +static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg); + +static void +js_qsort_r(QSortArgs *qa, int lo, int hi) +{ + js2val *pivot, *vec, *a, *b; + int i, j, lohi, hilo; + + CompareArgs *arg; + + pivot = qa->pivot; + vec = qa->vec; + arg = qa->arg; + + while (lo < hi) { + i = lo; + j = hi; + a = vec + i; + *pivot = *a; + while (i < j) { + b = vec + j; + if (sort_compare(b, pivot, arg) >= 0) { + j--; + continue; + } + *a = *b; + while (sort_compare(a, pivot, arg) <= 0) { + i++; + a = vec + i; + if (i == j) + goto store_pivot; + } + *b = *a; + } + if (i > lo) { + store_pivot: + *a = *pivot; + } + if (i - lo < hi - i) { + lohi = i - 1; + if (lo < lohi) + js_qsort_r(qa, lo, lohi); + lo = i + 1; + } else { + hilo = i + 1; + if (hilo < hi) + js_qsort_r(qa, hilo, hi); + hi = i - 1; + } + } +} + +static void js_qsort(js2val *vec, size_t nel, CompareArgs *arg) +{ + js2val *pivot; + QSortArgs qa; + + pivot = (js2val *)STD::malloc(nel); + qa.vec = vec; + qa.pivot = pivot; + qa.arg = arg; + js_qsort_r(&qa, 0, (int)(nel - 1)); + STD::free(pivot); +} + +static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg) +{ + js2val av = *(const js2val *)a; + js2val bv = *(const js2val *)b; + CompareArgs *ca = (CompareArgs *) arg; + JS2Metadata *meta = ca->meta; + int32 result; + + if (ca->target == NULL) { + if (JS2VAL_IS_UNDEFINED(av) || JS2VAL_IS_UNDEFINED(bv)) { + /* Put undefined properties at the end. */ + result = (JS2VAL_IS_UNDEFINED(av)) ? 1 : -1; + } + else { + const String *astr = meta->toString(av); + const String *bstr = meta->toString(bv); + result = astr->compare(*bstr); + } + return result; + } + else { + js2val argv[2]; + argv[0] = av; + argv[1] = bv; + js2val v = JS2VAL_UNDEFINED;// XXX = cx->invokeFunction(ca->target, kNullValue, argv, 2); + float64 f = meta->toFloat64(v); + if (JSDOUBLE_IS_NaN(f) || (f == 0)) + result = 0; + else + if (f > 0) + result = 1; + else + result = -1; + return result; + } +} + + +static js2val Array_sort(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + CompareArgs ca; + ca.meta = meta; + ca.target = NULL; + + if (argc > 0) { + if (!JS2VAL_IS_UNDEFINED(argv[0])) { + if (meta->objectType(argv[0]) != meta->functionClass) + meta->reportError(Exception::typeError, "sort needs a compare function", meta->engine->errorPos()); + ca.target = JS2VAL_TO_OBJECT(argv[0]); + } + } + + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + if (length > 0) { + uint32 i; + js2val *vec = new js2val[length]; + + Multiname mn(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + for (i = 0; i < length; i++) { + mn.name = meta->toString(i); + meta->readDynamicProperty(thisObj, &mn, &lookup, RunPhase, &vec[i]); + delete mn.name; + } + + js_qsort(vec, length, &ca); + + for (i = 0; i < length; i++) { + mn.name = meta->toString(i); + meta->writeDynamicProperty(thisObj, &mn, true, vec[i], RunPhase); + delete mn.name; + } + delete[] mn.name; + } + return thisValue; +} + +static js2val Array_splice(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + if (argc > 1) { + uint32 k; + + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + uint32 length = getLength(meta, thisObj); + + js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass)); + ArrayInstance *A = checked_cast(JS2VAL_TO_OBJECT(result)); + + int32 arg0 = meta->toInteger(argv[0]); + uint32 start; + if (arg0 < 0) { + arg0 += length; + if (arg0 < 0) + start = 0; + else + start = toUInt32(arg0); + } + else { + if (toUInt32(arg0) >= length) + start = length; + else + start = toUInt32(arg0); + } + + uint32 deleteCount; + int32 arg1 = meta->toInteger(argv[1]); + if (arg1 < 0) + deleteCount = 0; + else + if (toUInt32(arg1) >= (length - start)) + deleteCount = length - start; + else + deleteCount = toUInt32(arg1); + + Multiname mn1(NULL, meta->publicNamespace); + Multiname mn2(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + for (k = 0; k < deleteCount; k++) { + mn1.name = meta->toString(start + k); + if (meta->hasOwnProperty(thisObj, mn1.name)) { + js2val rval; + mn2.name = meta->toString(k); + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval); + meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase); + delete mn2.name; + } + delete mn1.name; + } + setLength(meta, A, deleteCount); + + uint32 newItemCount = argc - 2; + if (newItemCount < deleteCount) { + bool deleteResult; + for (k = start; k < (length - deleteCount); k++) { + mn1.name = meta->toString(k + deleteCount); + mn2.name = meta->toString(k + newItemCount); + if (meta->hasOwnProperty(thisObj, mn1.name)) { + js2val rval; + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval); + meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase); + } + else + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + delete mn1.name; + delete mn2.name; + } + for (k = length; k > (length - deleteCount + newItemCount); k--) { + mn1.name = meta->toString(k - 1); + meta->deleteProperty(thisValue, &mn1, &lookup, RunPhase, &deleteResult); + delete mn1.name; + } + } + else { + if (newItemCount > deleteCount) { + for (k = length - deleteCount; k > start; k--) { + bool deleteResult; + mn1.name = meta->toString(k + deleteCount - 1); + mn1.name = meta->toString(k + newItemCount - 1); + if (meta->hasOwnProperty(thisObj, mn1.name)) { + js2val rval; + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval); + meta->writeDynamicProperty(A, &mn2, true, rval, RunPhase); + } + else + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + delete mn1.name; + delete mn2.name; + } + } + } + k = start; + for (uint32 i = 2; i < argc; i++) { + mn1.name = meta->toString(k++); + meta->writeDynamicProperty(A, &mn2, true, argv[i], RunPhase); + delete mn1.name; + } + setLength(meta, thisObj, (length - deleteCount + newItemCount)); + + return result; + } + return JS2VAL_UNDEFINED; +} + +static js2val Array_unshift(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + ASSERT(JS2VAL_IS_OBJECT(thisValue)); + JS2Object *thisObj = JS2VAL_TO_OBJECT(thisValue); + + uint32 length = getLength(meta, thisObj); + uint32 k; + + Multiname mn1(NULL, meta->publicNamespace); + Multiname mn2(NULL, meta->publicNamespace); + LookupKind lookup(false, NULL); + + for (k = length; k > 0; k--) { + bool deleteResult; + mn1.name = meta->toString(k - 1); + mn2.name = meta->toString(k + argc - 1); + if (meta->hasOwnProperty(thisObj, mn1.name)) { + js2val rval; + meta->readDynamicProperty(thisObj, &mn1, &lookup, RunPhase, &rval); + meta->writeDynamicProperty(thisObj, &mn2, true, rval, RunPhase); + } + else + meta->deleteProperty(thisValue, &mn2, &lookup, RunPhase, &deleteResult); + delete mn1.name; + delete mn2.name; + } + + for (k = 0; k < argc; k++) { + mn1.name = meta->toString(k); + meta->writeDynamicProperty(thisObj, &mn1, true, argv[k], RunPhase); + delete mn1.name; + } + setLength(meta, thisObj, (length + argc)); + + return thisValue; +} + +#if 0 +// An index has to pass the test that : +// meta->toString(ToUint32(meta->toString(index))) == meta->toString(index) +// +// the 'meta->toString(index)' operation is the default behaviour of '[]' +// +// isArrayIndex() is called when we know that index is a Number +// +static bool isArrayIndex(JS2Metadata *meta, js2val index, uint32 &intIndex) +{ + ASSERT(JS2VAL_IS_NUMBER(index)); + js2val v = JSValue::toUInt32(cx, index); + if ((JSValue::f64(v) == JSValue::f64(index)) && (JSValue::f64(v) < two32minus1)) { + intIndex = (uint32)JSValue::f64(v); + return true; + } + return false; +} + +js2val Array_GetElement(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + // the 'this' value is the first argument, then the index + if (argc != 2) + cx->reportError(Exception::referenceError, "[] only supports single dimension"); + + JSArrayInstance *arrInst = checked_cast(JSValue::instance(thisValue)); + + js2val index = argv[1]; + const String *name = JSValue::string(JSValue::meta->toString(cx, index)); + + arrInst->getProperty(cx, *name, NULL); + return cx->popValue(); +} + +js2val Array_SetElement(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) +{ + // the 'this' value is the first argument, then the rValue, and finally the index + if (argc != 3) + cx->reportError(Exception::referenceError, "[]= only supports single dimension"); + + JSArrayInstance *arrInst = checked_cast(JSValue::instance(thisValue)); + + js2val index = argv[2]; + const String *name = JSValue::string(JSValue::meta->toString(cx, index)); + + if (JS2VAL_IS_NUMBER(index)) { + uint32 intIndex; + if (isArrayIndex(cx, index, intIndex)) { + PropertyIterator it = arrInst->findNamespacedProperty(*name, NULL); + if (it == arrInst->mProperties.end()) + arrInst->insertNewProperty(*name, NULL, Property::Enumerable, Object_Type, argv[1]); + else { + Property *prop = PROPERTY(it); + ASSERT(prop->mFlag == ValuePointer); + prop->mData.vp = argv[1]; + } + if (intIndex >= arrInst->mLength) + arrInst->mLength = intIndex + 1; + } + } + else { + arrInst->setProperty(cx, *name, NULL, argv[1]); + } + return argv[0]; +} +#endif + + +void initArrayObject(JS2Metadata *meta) +{ + + typedef struct { + char *name; + uint16 length; + NativeCode *code; + } PrototypeFunction; + + PrototypeFunction arrayProtos[] = + { + { "toString", 0, Array_toString }, + { "toLocaleString", 0, Array_toString }, // XXX + { "toSource", 0, Array_toSource }, + { "push", 1, Array_push }, + { "pop", 0, Array_pop }, + { "concat", 1, Array_concat }, + { "join", 1, Array_join }, + { "reverse", 0, Array_reverse }, + { "shift", 0, Array_shift }, + { "slice", 2, Array_slice }, + { "sort", 1, Array_sort }, + { "splice", 2, Array_splice }, + { "unshift", 1, Array_unshift }, + { NULL } + }; + + NamespaceList publicNamespaceList; + publicNamespaceList.push_back(meta->publicNamespace); + + meta->arrayClass->construct = Array_Constructor; + + PrototypeFunction *pf = &arrayProtos[0]; + while (pf->name) { + FixedInstance *fInst = new FixedInstance(meta->functionClass); + fInst->fWrap = new FunctionWrapper(true, new ParameterFrame(JS2VAL_INACCESSIBLE, true), pf->code); + + InstanceMember *m = new InstanceMethod(fInst); + meta->defineInstanceMember(meta->arrayClass, &meta->cxt, &meta->world.identifiers[pf->name], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); + pf++; + } +} + +} +} diff --git a/mozilla/js2/src/js2date.cpp b/mozilla/js2/src/js2date.cpp index 3b845bc1697..bd5172f9a4e 100644 --- a/mozilla/js2/src/js2date.cpp +++ b/mozilla/js2/src/js2date.cpp @@ -298,7 +298,6 @@ static int32 WeekDay(float64 t) static float64 *Date_getProlog(JS2Metadata *meta, const js2val thisValue) { if (meta->objectType(thisValue) != meta->dateClass) - //|| ((checked_cast(JS2VAL_TO_OBJECT(thisValue))->type != meta->dateClass)) ) meta->reportError(Exception::typeError, "You really need a date", meta->engine->errorPos()); DateInstance *dateInst = checked_cast(JS2VAL_TO_OBJECT(thisValue)); return &dateInst->ms; @@ -388,7 +387,7 @@ static js2val Date_makeTime(JS2Metadata *meta, const js2val thisValue, js2val *a argc = maxargs; /* clamp argc */ for (i = 0; i < argc; i++) { - float64 f = meta->engine->toFloat64(argv[i]); + float64 f = meta->toFloat64(argv[i]); if (JSDOUBLE_IS_NaN(f)) { *date = nan; return meta->engine->nanValue; @@ -454,7 +453,7 @@ static js2val Date_makeDate(JS2Metadata *meta, const js2val thisValue, js2val *a argc = maxargs; /* clamp argc */ for (i = 0; i < argc; i++) { - float64 f = meta->engine->toFloat64(argv[i]); + float64 f = meta->toFloat64(argv[i]); if (JSDOUBLE_IS_NaN(f)) { *date = nan; return meta->engine->nanValue; @@ -874,11 +873,11 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, if (argc == 1) { if (!JS2VAL_IS_STRING(argv[0])) { /* the argument is a millisecond number */ - float64 d = meta->engine->toFloat64(argv[0]); + float64 d = meta->toFloat64(argv[0]); thisInst->ms = TIMECLIP(d); } else { /* the argument is a string; parse it. */ - const String *str = meta->engine->toString(argv[0]); + const String *str = meta->toString(argv[0]); float64 d = date_parseString(*str); thisInst->ms = TIMECLIP(d); } @@ -891,7 +890,7 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, for (loop = 0; loop < MAXARGS; loop++) { if (loop < argc) { - float64 double_arg = meta->engine->toFloat64(argv[loop]); + float64 double_arg = meta->toFloat64(argv[loop]); /* if any arg is NaN, make a NaN date object and return */ if (!JSDOUBLE_IS_FINITE(double_arg)) { @@ -924,7 +923,7 @@ js2val Date_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, js2val Date_parse(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 /*argc*/) { - const String *str = meta->engine->toString(argv[0]); + const String *str = meta->toString(argv[0]); float64 d = date_parseString(*str); d = TIMECLIP(d); return meta->engine->allocNumber(d); @@ -938,7 +937,7 @@ js2val Date_UTC(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uin for (loop = 0; loop < MAXARGS; loop++) { if (loop < argc) { - d = meta->engine->toFloat64(argv[loop]); + d = meta->toFloat64(argv[loop]); if (!JSDOUBLE_IS_FINITE(d)) return meta->engine->allocNumber(d); array[loop] = floor(d); @@ -1272,7 +1271,7 @@ static js2val Date_getUTCMilliseconds(JS2Metadata *meta, const js2val thisValue, static js2val Date_setTime(JS2Metadata *meta, const js2val thisValue, js2val argv[], uint32 /*argc*/) { float64 *date = Date_getProlog(meta, thisValue); - float64 result = meta->engine->toFloat64(argv[0]); + float64 result = meta->toFloat64(argv[0]); *date = TIMECLIP(result); return meta->engine->allocNumber(*date); } @@ -1286,7 +1285,7 @@ static js2val Date_setYear(JS2Metadata *meta, const js2val thisValue, js2val arg float64 *date = Date_getProlog(meta, thisValue); result = *date; - year = meta->engine->toFloat64(argv[0]); + year = meta->toFloat64(argv[0]); if (!JSDOUBLE_IS_FINITE(year)) { *date = nan; return meta->engine->allocNumber(*date); diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 8bf583b0dfb..f65c157245a 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -188,84 +188,6 @@ namespace MetaData { return new JavaScript::String(widenCString(chrp)); } - // x is not a String - const String *JS2Engine::convertValueToString(js2val x) - { - if (JS2VAL_IS_UNDEFINED(x)) - return undefined_StringAtom; - if (JS2VAL_IS_NULL(x)) - return null_StringAtom; - if (JS2VAL_IS_BOOLEAN(x)) - return (JS2VAL_TO_BOOLEAN(x)) ? true_StringAtom : false_StringAtom; - if (JS2VAL_IS_INT(x)) - return numberToString(JS2VAL_TO_INT(x)); - if (JS2VAL_IS_LONG(x)) { - float64 d; - JSLL_L2D(d, *JS2VAL_TO_LONG(x)); - return numberToString(&d); - } - if (JS2VAL_IS_ULONG(x)) { - float64 d; - JSLL_UL2D(d, *JS2VAL_TO_ULONG(x)); - return numberToString(&d); - } - if (JS2VAL_IS_FLOAT(x)) { - float64 d = *JS2VAL_TO_FLOAT(x); - return numberToString(&d); - } - if (JS2VAL_IS_DOUBLE(x)) - return numberToString(JS2VAL_TO_DOUBLE(x)); - return toString(toPrimitive(x)); - } - - // x is not a primitive (it is an object and not null) - js2val JS2Engine::convertValueToPrimitive(js2val x) - { - // return [[DefaultValue]] --> get property 'toString' and invoke it, - // if not available or result is not primitive then try property 'valueOf' - // if that's not available or returns a non primitive, throw a TypeError - - return STRING_TO_JS2VAL(object_StringAtom); - - ASSERT(false); - return JS2VAL_VOID; - } - - // x is not a number - float64 JS2Engine::convertValueToDouble(js2val x) - { - if (JS2VAL_IS_UNDEFINED(x)) - return nan; - if (JS2VAL_IS_NULL(x)) - return 0; - if (JS2VAL_IS_BOOLEAN(x)) - return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0; - if (JS2VAL_IS_STRING(x)) { - String *str = JS2VAL_TO_STRING(x); - char16 *numEnd; - return stringToDouble(str->data(), str->data() + str->length(), numEnd); - } - return toFloat64(toPrimitive(x)); - } - - // x is not a number, convert it to one - js2val JS2Engine::convertValueToGeneralNumber(js2val x) - { - // XXX Assuming convert to float64, rather than long/ulong - return allocNumber(toFloat64(x)); - } - - // x is not an Object, it needs to be wrapped in one - js2val JS2Engine::convertValueToObject(js2val x) - { - if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x)) - meta->reportError(Exception::typeError, "Can't convert to Object", errorPos()); - if (JS2VAL_IS_STRING(x)) - return String_Constructor(meta, JS2VAL_NULL, &x, 1); - // XXX need more - return OBJECT_TO_JS2VAL(new PrototypeInstance(meta->objectClass->prototype, meta->objectClass)); - } - // x is a Number, validate that it has no fractional component int64 JS2Engine::checkInteger(js2val x) { @@ -301,83 +223,6 @@ namespace MetaData { return i; } - // x is any js2val - float64 JS2Engine::toFloat64(js2val x) - { - if (JS2VAL_IS_INT(x)) - return JS2VAL_TO_INT(x); - else - if (JS2VAL_IS_DOUBLE(x)) - return *JS2VAL_TO_DOUBLE(x); - else - if (JS2VAL_IS_LONG(x)) { - float64 d; - JSLL_L2D(d, *JS2VAL_TO_LONG(x)); - return d; - } - else - if (JS2VAL_IS_ULONG(x)) { - float64 d; - JSLL_UL2D(d, *JS2VAL_TO_ULONG(x)); - return d; - } - else - if (JS2VAL_IS_FLOAT(x)) - return *JS2VAL_TO_FLOAT(x); - else - return convertValueToDouble(x); - } - - // x is not a bool - bool JS2Engine::convertValueToBoolean(js2val x) - { - if (JS2VAL_IS_UNDEFINED(x)) - return false; - if (JS2VAL_IS_NULL(x)) - return false; - if (JS2VAL_IS_INT(x)) - return (JS2VAL_TO_INT(x) != 0); - if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x)) - return (!JSLL_IS_ZERO(x)); - if (JS2VAL_IS_FLOAT(x)) { - float64 xd = *JS2VAL_TO_FLOAT(x); - return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd)); - } - if (JS2VAL_IS_DOUBLE(x)) { - float64 xd = *JS2VAL_TO_DOUBLE(x); - return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd)); - } - if (JS2VAL_IS_STRING(x)) { - String *str = JS2VAL_TO_STRING(x); - return (str->length() != 0); - } - return true; - } - - // x is not an int - int32 JS2Engine::convertValueToInteger(js2val x) - { - int32 i; - if (JS2VAL_IS_LONG(x)) { - JSLL_L2I(i, *JS2VAL_TO_LONG(x)); - return i; - } - if (JS2VAL_IS_ULONG(x)) { - JSLL_UL2I(i, *JS2VAL_TO_ULONG(x)); - return i; - } - if (JS2VAL_IS_FLOAT(x)) { - float64 f = *JS2VAL_TO_FLOAT(x); - return toInt32(f); - } - if (JS2VAL_IS_DOUBLE(x)) { - float64 d = *JS2VAL_TO_DOUBLE(x); - return toInt32(d); - } - float64 d = convertValueToDouble(x); - return toInt32(d); - } - int32 JS2Engine::toInt32(float64 d) { if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) ) @@ -444,7 +289,8 @@ namespace MetaData { INIT_STRINGATOM(object), Empty_StringAtom(&world.identifiers[""]), Dollar_StringAtom(&world.identifiers["$"]), - prototype_StringAtom(&world.identifiers["prototype"]) + INIT_STRINGATOM(prototype), + INIT_STRINGATOM(length) { for (int i = 0; i < 256; i++) float64Table[i] = NULL; diff --git a/mozilla/js2/src/js2engine.h b/mozilla/js2/src/js2engine.h index e2352735859..e3d14578203 100644 --- a/mozilla/js2/src/js2engine.h +++ b/mozilla/js2/src/js2engine.h @@ -156,27 +156,11 @@ public: // Use the pc map in the current bytecode container to get a source offset size_t errorPos(); - int32 toInt32(float64 f); - uint32 toUInt32(float64 f); - uint16 toUInt16(float64 f); + static int32 toInt32(float64 f); + static uint32 toUInt32(float64 f); + static uint16 toUInt16(float64 f); - const String *convertValueToString(js2val x); - js2val convertValueToPrimitive(js2val x); - float64 convertValueToDouble(js2val x); - bool convertValueToBoolean(js2val x); - int32 convertValueToInteger(js2val x); - js2val convertValueToGeneralNumber(js2val x); - js2val convertValueToObject(js2val x); - - const String *toString(js2val x){ if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); } - js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); } - float64 toFloat64(js2val x); - js2val toGeneralNumber(js2val x){ if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); } - bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); } - int32 toInteger(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else return convertValueToInteger(x); } - js2val toObject(js2val x) { if (JS2VAL_IS_OBJECT(x)) return x; else return convertValueToObject(x); } - js2val assignmentConversion(js2val val, JS2Class *type) { return val; } // XXX s'more code, please int64 checkInteger(js2val x); @@ -236,6 +220,7 @@ public: const String *Empty_StringAtom; const String *Dollar_StringAtom; const String *prototype_StringAtom; + const String *length_StringAtom; // The activation stack, when it's empty and a return is executed, the // interpreter quits diff --git a/mozilla/js2/src/js2math.cpp b/mozilla/js2/src/js2math.cpp index d03944f2f10..27b255b56e2 100644 --- a/mozilla/js2/src/js2math.cpp +++ b/mozilla/js2/src/js2math.cpp @@ -92,73 +92,73 @@ static js2val Math_abs(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar if (argc == 0) return meta->engine->nanValue; else - return meta->engine->allocNumber(fd::fabs(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::fabs(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_acos(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::acos(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::acos(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_asin(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::asin(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::asin(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_atan(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::atan(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::atan(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_atan2(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc <= 1) return meta->engine->nanValue; - float64 y = meta->engine->toFloat64(argv[0]); - float64 x = meta->engine->toFloat64(argv[1]); + float64 y = meta->engine->meta->toFloat64(argv[0]); + float64 x = meta->engine->meta->toFloat64(argv[1]); return meta->engine->allocNumber(fd::atan2(y, x)); } static js2val Math_ceil(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::ceil(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::ceil(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_cos(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::cos(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::cos(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_exp(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::exp(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::exp(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_floor(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; else - return meta->engine->allocNumber(fd::floor(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::floor(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_log(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::log(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::log(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_max(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->negInfValue; - float64 result = meta->engine->toFloat64(argv[0]); + float64 result = meta->engine->meta->toFloat64(argv[0]); if (JSDOUBLE_IS_NaN(result)) return meta->engine->nanValue; for (uint32 i = 1; i < argc; ++i) { - float64 arg = meta->engine->toFloat64(argv[i]); + float64 arg = meta->engine->meta->toFloat64(argv[i]); if (JSDOUBLE_IS_NaN(arg)) return meta->engine->nanValue; if (arg > result) result = arg; @@ -169,10 +169,10 @@ static js2val Math_min(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar { if (argc == 0) return meta->engine->posInfValue; - float64 result = meta->engine->toFloat64(argv[0]); + float64 result = meta->engine->meta->toFloat64(argv[0]); if (JSDOUBLE_IS_NaN(result)) return meta->engine->nanValue; for (uint32 i = 1; i < argc; ++i) { - float64 arg = meta->engine->toFloat64(argv[i]); + float64 arg = meta->engine->meta->toFloat64(argv[i]); if (JSDOUBLE_IS_NaN(arg)) return meta->engine->nanValue; if ((arg < result) || (JSDOUBLE_IS_POSZERO(result) && JSDOUBLE_IS_NEGZERO(arg))) result = arg; @@ -183,7 +183,7 @@ static js2val Math_pow(JS2Metadata *meta, const js2val /*thisValue*/, js2val *ar { if (argc < 1) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::pow(meta->engine->toFloat64(argv[0]), meta->engine->toFloat64(argv[1]))); + return meta->engine->allocNumber(fd::pow(meta->engine->meta->toFloat64(argv[0]), meta->engine->meta->toFloat64(argv[1]))); } /* @@ -265,26 +265,26 @@ static js2val Math_round(JS2Metadata *meta, const js2val /*thisValue*/, js2val * { if (argc == 0) return meta->engine->nanValue; - float64 x = meta->engine->toFloat64(argv[0]); + float64 x = meta->engine->meta->toFloat64(argv[0]); return meta->engine->allocNumber( fd::copysign( fd::floor(x + 0.5), x ) ); } static js2val Math_sin(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::sin(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::sin(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_sqrt(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::sqrt(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::sqrt(meta->engine->meta->toFloat64(argv[0]))); } static js2val Math_tan(JS2Metadata *meta, const js2val /*thisValue*/, js2val *argv, uint32 argc) { if (argc == 0) return meta->engine->nanValue; - return meta->engine->allocNumber(fd::tan(meta->engine->toFloat64(argv[0]))); + return meta->engine->allocNumber(fd::tan(meta->engine->meta->toFloat64(argv[0]))); } diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 6aa968d793d..c36dacc85f7 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -48,6 +48,7 @@ #include "world.h" #include "utilities.h" #include "js2value.h" +#include "jslong.h" #include "numerics.h" #include "reader.h" #include "parser.h" @@ -985,7 +986,7 @@ namespace MetaData { VariableStmtNode *vs = checked_cast(p); VariableBinding *vb = vs->bindings; while (vb) { - if (vb->member) { + if (vb->member) { // static or instance variable if (vb->member->kind == Member::Variable) { Variable *v = checked_cast(vb->member); JS2Class *type = getVariableType(v, CompilePhase, p->pos); @@ -2497,53 +2498,6 @@ doUnary: return STRING_TO_JS2VAL(meta->engine->object_StringAtom); } - js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) - { - // XXX Change constructors to take js2val pointer for the result (which would be an already - // rooted pointer). - RegExpInstance *thisInst = new RegExpInstance(meta->regexpClass); - JS2Object::RootIterator ri = JS2Object::addRoot(&thisInst); - js2val thatValue = OBJECT_TO_JS2VAL(thisInst); - REuint32 flags = 0; - - const String *regexpStr = meta->engine->Empty_StringAtom; - const String *flagStr = meta->engine->Empty_StringAtom; - if (argc > 0) { - if (meta->objectType(argv[0]) == meta->regexpClass) { - if ((argc == 1) || JS2VAL_IS_UNDEFINED(argv[1])) { - RegExpInstance *otherInst = checked_cast(JS2VAL_TO_OBJECT(argv[0])); - js2val src = otherInst->getSource(meta); - ASSERT(JS2VAL_IS_STRING(src)); - regexpStr = JS2VAL_TO_STRING(src); - flags = otherInst->mRegExp->flags; - } - else - meta->reportError(Exception::typeError, "Illegal RegExp constructor args", meta->engine->errorPos()); - } - else - regexpStr = meta->engine->toString(argv[0]); - if ((argc > 1) && !JS2VAL_IS_UNDEFINED(argv[1])) { - flagStr = meta->engine->toString(argv[1]); - if (parseFlags(flagStr->begin(), (int32)flagStr->length(), &flags) != RE_NO_ERROR) - meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), *regexpStr + "/" + *flagStr); // XXX error message? - } - } - REState *pState = REParse(regexpStr->begin(), (int32)regexpStr->length(), flags, RE_VERSION_1); - if (pState) { - thisInst->mRegExp = pState; - // XXX ECMA spec says these are DONTENUM - thisInst->setSource(meta, STRING_TO_JS2VAL(regexpStr)); - thisInst->setGlobal(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_GLOBAL) == RE_GLOBAL)); - thisInst->setIgnoreCase(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_IGNORECASE) == RE_IGNORECASE)); - thisInst->setLastIndex(meta, INT_TO_JS2VAL(0)); - thisInst->setMultiline(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_MULTILINE) == RE_MULTILINE)); - } - else - meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), "/" + *regexpStr + "/" + *flagStr); // XXX what about the RE parser error message? - JS2Object::removeRoot(ri); - return thatValue; - } - void JS2Metadata::addGlobalObjectFunction(char *name, NativeCode *code) { FixedInstance *fInst = new FixedInstance(functionClass); @@ -2600,6 +2554,7 @@ doUnary: NamespaceList publicNamespaceList; publicNamespaceList.push_back(publicNamespace); Variable *v; + InstanceMember *m; MAKEBUILTINCLASS(dateClass, objectClass, true, true, true, &world.identifiers["Date"]); v = new Variable(classClass, OBJECT_TO_JS2VAL(dateClass), true); @@ -2611,6 +2566,16 @@ doUnary: v = new Variable(classClass, OBJECT_TO_JS2VAL(regexpClass), true); defineStaticMember(&env, &world.identifiers["RegExp"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0); regexpClass->construct = RegExp_Constructor; + m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++); + defineInstanceMember(regexpClass, &cxt, &world.identifiers["source"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); + m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++); + defineInstanceMember(regexpClass, &cxt, &world.identifiers["global"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); + m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++); + defineInstanceMember(regexpClass, &cxt, &world.identifiers["lastIndex"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); + m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++); + defineInstanceMember(regexpClass, &cxt, &world.identifiers["ignoreCase"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); + m = new InstanceVariable(objectClass, false, false, regexpClass->slotCount++); + defineInstanceMember(regexpClass, &cxt, &world.identifiers["multiline"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, m, 0); v = new Variable(classClass, OBJECT_TO_JS2VAL(stringClass), true); defineStaticMember(&env, &world.identifiers["String"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0); @@ -2622,6 +2587,12 @@ doUnary: defineStaticMember(&env, &world.identifiers["Math"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0); initMathObject(this); + MAKEBUILTINCLASS(arrayClass, objectClass, true, true, true, &world.identifiers["Array"]); + v = new Variable(classClass, OBJECT_TO_JS2VAL(arrayClass), true); + defineStaticMember(&env, &world.identifiers["Array"], &publicNamespaceList, Attribute::NoOverride, false, ReadWriteAccess, v, 0); + // dateClass->prototype = new PrototypeInstance(NULL, dateClass); + initArrayObject(this); + } @@ -2638,7 +2609,9 @@ doUnary: return numberClass; if (JS2VAL_IS_STRING(objVal)) { if (JS2VAL_TO_STRING(objVal)->length() == 1) - return characterClass; + return stringClass; // XXX characterClass; Need the connection from class Character to + // class String - i.e. access to all the functions in 'String.prototype' - + // but (some of) those routines depened on being called on a StringInstance... else return stringClass; } @@ -2705,6 +2678,31 @@ doUnary: return NULL; } + // Return true if the object contains the property, but don't + // scan the prototype chain. Only scan dynamic properties. XXX + bool JS2Metadata::hasOwnProperty(JS2Object *obj, const String *name) + { + ASSERT(obj); + DynamicPropertyMap *dMap = NULL; + bool isPrototypeInstance = false; + if (obj->kind == DynamicInstanceKind) + dMap = &(checked_cast(obj))->dynamicProperties; + else + if (obj->kind == GlobalObjectKind) + dMap = &(checked_cast(obj))->dynamicProperties; + else { + ASSERT(obj->kind == PrototypeInstanceKind); + isPrototypeInstance = true; + dMap = &(checked_cast(obj))->dynamicProperties; + } + for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) { + if (i->first == *name) { + return true; + } + } + return false; + } + // Read the property from the container given by the public id in multiname - if that exists // bool JS2Metadata::readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval) @@ -2746,6 +2744,34 @@ doUnary: return false; // 'None' } + void DynamicInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue) + { + const DynamicPropertyMap::value_type e(*name, newValue); + dynamicProperties.insert(e); + } + + void ArrayInstance::writeProperty(JS2Metadata *meta, const String *name, js2val newValue) + { + // 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 + // + const DynamicPropertyMap::value_type e(*name, newValue); + dynamicProperties.insert(e); + + char16 *numEnd; + float64 f = stringToDouble(name->data(), name->data() + name->length(), numEnd); + uint32 index = JS2Engine::toUInt32(f); + + if (index == f) { + uint32 length = getLength(meta, this); + if (index >= length) + setLength(meta, this, index + 1); + } + } + // Write a value to a dynamic container - inserting into the map if not already there (if createIfMissing) bool JS2Metadata::writeDynamicProperty(JS2Object *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase) { @@ -2775,8 +2801,7 @@ doUnary: DynamicInstance *dynInst = checked_cast(container); InstanceBinding *ib = resolveInstanceMemberName(dynInst->type, multiname, ReadAccess, phase); if (ib == NULL) { - const DynamicPropertyMap::value_type e(*name, newValue); - dynInst->dynamicProperties.insert(e); + dynInst->writeProperty(this, name, newValue); return true; } } @@ -2858,9 +2883,10 @@ readClassProperty: InstanceBinding *ib = resolveInstanceMemberName(c, multiname, ReadAccess, phase); if ((ib == NULL) && isDynamicInstance) return readDynamicProperty(JS2VAL_TO_OBJECT(containerVal), multiname, lookupKind, phase, rval); - else - // XXX passing a primitive here ??? - return readInstanceMember(containerVal, c, (ib) ? &ib->qname : NULL, phase, rval); + else { + // XXX Spec. would have us passing a primitive here ??? + return readInstanceMember(toObject(containerVal), c, (ib) ? &ib->qname : NULL, phase, rval); + } } JS2Object *container = JS2VAL_TO_OBJECT(containerVal); switch (container->kind) { @@ -3388,6 +3414,184 @@ deleteClassProperty: } + // x is not a String + const String *JS2Metadata::convertValueToString(js2val x) + { + if (JS2VAL_IS_UNDEFINED(x)) + return engine->undefined_StringAtom; + if (JS2VAL_IS_NULL(x)) + return engine->null_StringAtom; + if (JS2VAL_IS_BOOLEAN(x)) + return (JS2VAL_TO_BOOLEAN(x)) ? engine->true_StringAtom : engine->false_StringAtom; + if (JS2VAL_IS_INT(x)) + return numberToString(JS2VAL_TO_INT(x)); + if (JS2VAL_IS_LONG(x)) { + float64 d; + JSLL_L2D(d, *JS2VAL_TO_LONG(x)); + return numberToString(&d); + } + if (JS2VAL_IS_ULONG(x)) { + float64 d; + JSLL_UL2D(d, *JS2VAL_TO_ULONG(x)); + return numberToString(&d); + } + if (JS2VAL_IS_FLOAT(x)) { + float64 d = *JS2VAL_TO_FLOAT(x); + return numberToString(&d); + } + if (JS2VAL_IS_DOUBLE(x)) + return numberToString(JS2VAL_TO_DOUBLE(x)); + return toString(toPrimitive(x)); + } + + // x is not a primitive (it is an object and not null) + js2val JS2Metadata::convertValueToPrimitive(js2val x) + { + // return [[DefaultValue]] --> get property 'toString' and invoke it, + // if not available or result is not primitive then try property 'valueOf' + // if that's not available or returns a non primitive, throw a TypeError + + Multiname mn(&world.identifiers["toString"], publicNamespace); + LookupKind lookup(false, NULL); + js2val result; + if (readProperty(x, &mn, &lookup, RunPhase, &result)) { + if (JS2VAL_IS_OBJECT(result)) { + JS2Object *obj = JS2VAL_TO_OBJECT(result); + if ((obj->kind == FixedInstanceKind) && (objectType(result) == functionClass)) { + FunctionWrapper *fWrap = (checked_cast(obj))->fWrap; + if (fWrap->code) { + result = (fWrap->code)(this, result, NULL, 0); + return result; + } + } + else + if (obj->kind == MethodClosureKind) { + MethodClosure *mc = checked_cast(obj); + FixedInstance *fInst = mc->method->fInst; + FunctionWrapper *fWrap = fInst->fWrap; + if (fWrap->code) { + result = (fWrap->code)(this, mc->thisObject, NULL, 0); + return result; + } + } + } + } + + return STRING_TO_JS2VAL(engine->object_StringAtom); + } + + // x is not a number + float64 JS2Metadata::convertValueToDouble(js2val x) + { + if (JS2VAL_IS_UNDEFINED(x)) + return nan; + if (JS2VAL_IS_NULL(x)) + return 0; + if (JS2VAL_IS_BOOLEAN(x)) + return (JS2VAL_TO_BOOLEAN(x)) ? 1.0 : 0.0; + if (JS2VAL_IS_STRING(x)) { + String *str = JS2VAL_TO_STRING(x); + char16 *numEnd; + return stringToDouble(str->data(), str->data() + str->length(), numEnd); + } + return toFloat64(toPrimitive(x)); + } + + // x is not a number, convert it to one + js2val JS2Metadata::convertValueToGeneralNumber(js2val x) + { + // XXX Assuming convert to float64, rather than long/ulong + return engine->allocNumber(toFloat64(x)); + } + + // x is not an Object, it needs to be wrapped in one + js2val JS2Metadata::convertValueToObject(js2val x) + { + if (JS2VAL_IS_UNDEFINED(x) || JS2VAL_IS_NULL(x) || JS2VAL_IS_SPECIALREF(x)) + reportError(Exception::typeError, "Can't convert to Object", engine->errorPos()); + if (JS2VAL_IS_STRING(x)) + return String_Constructor(this, JS2VAL_NULL, &x, 1); + // XXX need more + return OBJECT_TO_JS2VAL(new PrototypeInstance(objectClass->prototype, objectClass)); + } + + // x is any js2val + float64 JS2Metadata::toFloat64(js2val x) + { + if (JS2VAL_IS_INT(x)) + return JS2VAL_TO_INT(x); + else + if (JS2VAL_IS_DOUBLE(x)) + return *JS2VAL_TO_DOUBLE(x); + else + if (JS2VAL_IS_LONG(x)) { + float64 d; + JSLL_L2D(d, *JS2VAL_TO_LONG(x)); + return d; + } + else + if (JS2VAL_IS_ULONG(x)) { + float64 d; + JSLL_UL2D(d, *JS2VAL_TO_ULONG(x)); + return d; + } + else + if (JS2VAL_IS_FLOAT(x)) + return *JS2VAL_TO_FLOAT(x); + else + return convertValueToDouble(x); + } + + // x is not a bool + bool JS2Metadata::convertValueToBoolean(js2val x) + { + if (JS2VAL_IS_UNDEFINED(x)) + return false; + if (JS2VAL_IS_NULL(x)) + return false; + if (JS2VAL_IS_INT(x)) + return (JS2VAL_TO_INT(x) != 0); + if (JS2VAL_IS_LONG(x) || JS2VAL_IS_ULONG(x)) + return (!JSLL_IS_ZERO(x)); + if (JS2VAL_IS_FLOAT(x)) { + float64 xd = *JS2VAL_TO_FLOAT(x); + return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd)); + } + if (JS2VAL_IS_DOUBLE(x)) { + float64 xd = *JS2VAL_TO_DOUBLE(x); + return ! (JSDOUBLE_IS_POSZERO(xd) || JSDOUBLE_IS_NEGZERO(xd) || JSDOUBLE_IS_NaN(xd)); + } + if (JS2VAL_IS_STRING(x)) { + String *str = JS2VAL_TO_STRING(x); + return (str->length() != 0); + } + return true; + } + + // x is not an int + int32 JS2Metadata::convertValueToInteger(js2val x) + { + int32 i; + if (JS2VAL_IS_LONG(x)) { + JSLL_L2I(i, *JS2VAL_TO_LONG(x)); + return i; + } + if (JS2VAL_IS_ULONG(x)) { + JSLL_UL2I(i, *JS2VAL_TO_ULONG(x)); + return i; + } + if (JS2VAL_IS_FLOAT(x)) { + float64 f = *JS2VAL_TO_FLOAT(x); + return toInt32(f); + } + if (JS2VAL_IS_DOUBLE(x)) { + float64 d = *JS2VAL_TO_DOUBLE(x); + return toInt32(d); + } + float64 d = convertValueToDouble(x); + return toInt32(d); + } + /* * Throw an exception of the specified kind, indicating the position 'pos' and diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 86bc0e3a739..f77604284d8 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -60,10 +60,14 @@ typedef js2val (Constructor)(JS2Metadata *meta, const js2val thisValue, js2val * extern void initDateObject(JS2Metadata *meta); extern void initStringObject(JS2Metadata *meta); extern void initMathObject(JS2Metadata *meta); +extern void initArrayObject(JS2Metadata *meta); + extern js2val String_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); extern js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); extern js2val RegExp_exec(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); +extern uint32 getLength(JS2Metadata *meta, JS2Object *obj); +extern js2val setLength(JS2Metadata *meta, JS2Object *obj, uint32 length); // OBJECT is the semantic domain of all possible objects and is defined as: // OBJECT = UNDEFINED | NULL | BOOLEAN | FLOAT64 | LONG | ULONG | CHARACTER | STRING | NAMESPACE | @@ -514,6 +518,8 @@ public: Slot *slots; // A set of slots that hold this instance's fixed property values DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties virtual void markChildren(); + + virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue); }; // Prototype instances are represented as PROTOTYPE records. Prototype instances @@ -545,16 +551,28 @@ public: // that contains the string data class StringInstance : public FixedInstance { public: - StringInstance(JS2Class *type) : FixedInstance(type) { } + StringInstance(JS2Class *type) : FixedInstance(type), mValue(NULL) { } - String *mValue; + String *mValue; // has been allocated by engine in the GC'able Pond + + virtual void markChildren() { if (mValue) JS2Object::mark(mValue); } }; -// RegExp instances are fixed (not dynamic? XXX) instances created by the RegExp class, they have an extra field -// that contains the RegExp object -class RegExpInstance : public FixedInstance { +// Array instances are dynamic instances created by the Array class, they +// maintain the value of the 'length' property when 'indexable' elements +// are added. +class ArrayInstance : public DynamicInstance { public: - RegExpInstance(JS2Class *type) : FixedInstance(type) { } + ArrayInstance(JS2Class *type) : DynamicInstance(type) { } + + virtual void writeProperty(JS2Metadata *meta, const String *name, js2val newValue); +}; + +// RegExp instances are dynamic instances created by the RegExp class, they have an extra field +// that contains the RegExp object +class RegExpInstance : public DynamicInstance { +public: + RegExpInstance(JS2Class *type) : DynamicInstance(type) { } void setLastIndex(JS2Metadata *meta, js2val a); void setGlobal(JS2Metadata *meta, js2val a); @@ -922,6 +940,7 @@ public: bool readStaticMember(StaticMember *m, Phase phase, js2val *rval); bool readInstanceMember(js2val containerVal, JS2Class *c, QualifiedName *qname, Phase phase, js2val *rval); JS2Object *lookupDynamicProperty(JS2Object *obj, const String *name); + bool JS2Metadata::hasOwnProperty(JS2Object *obj, const String *name); bool writeProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase); bool writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase); @@ -941,6 +960,21 @@ public: void reportError(Exception::Kind kind, const char *message, size_t pos, const String &name); void reportError(Exception::Kind kind, const char *message, size_t pos, const String *name); + const String *convertValueToString(js2val x); + js2val convertValueToPrimitive(js2val x); + float64 convertValueToDouble(js2val x); + bool convertValueToBoolean(js2val x); + int32 convertValueToInteger(js2val x); + js2val convertValueToGeneralNumber(js2val x); + js2val convertValueToObject(js2val x); + + const String *toString(js2val x) { if (JS2VAL_IS_STRING(x)) return JS2VAL_TO_STRING(x); else return convertValueToString(x); } + js2val toPrimitive(js2val x) { if (JS2VAL_IS_PRIMITIVE(x)) return x; else return convertValueToPrimitive(x); } + float64 toFloat64(js2val x); + js2val toGeneralNumber(js2val x) { if (JS2VAL_IS_NUMBER(x)) return x; else return convertValueToGeneralNumber(x); } + bool toBoolean(js2val x) { if (JS2VAL_IS_BOOLEAN(x)) return JS2VAL_TO_BOOLEAN(x); else return convertValueToBoolean(x); } + int32 toInteger(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else return convertValueToInteger(x); } + js2val toObject(js2val x) { if (JS2VAL_IS_OBJECT(x)) return x; else return convertValueToObject(x); } // Used for interning strings World &world; @@ -980,6 +1014,7 @@ public: JS2Class *dateClass; JS2Class *regexpClass; JS2Class *mathClass; + JS2Class *arrayClass; Parser *mParser; // used for error reporting diff --git a/mozilla/js2/src/js2op_access.cpp b/mozilla/js2/src/js2op_access.cpp index 209a356a392..c26c878669a 100644 --- a/mozilla/js2/src/js2op_access.cpp +++ b/mozilla/js2/src/js2op_access.cpp @@ -130,7 +130,7 @@ LookupKind lookup(false, NULL); indexVal = pop(); b = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); @@ -144,7 +144,7 @@ LookupKind lookup(false, NULL); indexVal = pop(); b = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); bool result; if (!meta->deleteProperty(b, &mn, &lookup, RunPhase, &result)) @@ -163,7 +163,7 @@ a = pop(); indexVal = pop(); b = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); meta->writeProperty(b, &mn, &lookup, true, a, RunPhase); push(a); @@ -177,7 +177,7 @@ LookupKind lookup(false, NULL); indexVal = pop(); b = top(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); @@ -192,7 +192,7 @@ LookupKind lookup(false, NULL); indexVal = pop(); b = top(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); push(STRING_TO_JS2VAL(indexStr)); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(b, &mn, &lookup, RunPhase, &a)) diff --git a/mozilla/js2/src/js2op_arithmetic.cpp b/mozilla/js2/src/js2op_arithmetic.cpp index 8aa9d475d51..26b781d02b1 100644 --- a/mozilla/js2/src/js2op_arithmetic.cpp +++ b/mozilla/js2/src/js2op_arithmetic.cpp @@ -38,7 +38,7 @@ case eMinus: { a = pop(); - a = toGeneralNumber(a); + a = meta->toGeneralNumber(a); if (JS2VAL_IS_LONG(a)) { int64 v = *JS2VAL_TO_LONG(a); if (JSLL_EQ(v, JSLL_MININT)) @@ -55,22 +55,21 @@ pushLong(v); } else - pushNumber(-toFloat64(a)); + pushNumber(-meta->toFloat64(a)); } break; case ePlus: { a = pop(); - a = toGeneralNumber(a); - push(toGeneralNumber(a)); + push(meta->toGeneralNumber(a)); } break; case eComplement: { a = pop(); - a = toGeneralNumber(a); + a = meta->toGeneralNumber(a); if (JS2VAL_IS_LONG(a)) { int64 i = *JS2VAL_TO_LONG(a); JSLL_NOT(i, i); @@ -83,7 +82,7 @@ pushULong(i); } else { - pushNumber(~toInteger(a)); + pushNumber(~meta->toInteger(a)); } } } @@ -92,8 +91,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - int32 count = toInteger(b); + a = meta->toGeneralNumber(a); + int32 count = meta->toInteger(b); if (JS2VAL_IS_LONG(a)) { int64 r; JSLL_SHL(r, *JS2VAL_TO_LONG(a), count & 0x3F); @@ -106,15 +105,15 @@ pushULong(r); } else - pushNumber(toInteger(a) << (count & 0x1F)); + pushNumber(meta->toInteger(a) << (count & 0x1F)); } break; case eRightShift: { b = pop(); a = pop(); - a = toGeneralNumber(a); - int32 count = toInteger(b); + a = meta->toGeneralNumber(a); + int32 count = meta->toInteger(b); if (JS2VAL_IS_LONG(a)) { int64 r; JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F); @@ -127,15 +126,15 @@ pushULong(r); } else - pushNumber(toInteger(a) >> (count & 0x1F)); + pushNumber(meta->toInteger(a) >> (count & 0x1F)); } break; case eLogicalRightShift: { b = pop(); a = pop(); - a = toGeneralNumber(a); - int32 count = toInteger(b); + a = meta->toGeneralNumber(a); + int32 count = meta->toInteger(b); if (JS2VAL_IS_LONG(a)) { int64 r; JSLL_SHR(r, *JS2VAL_TO_LONG(a), count & 0x3F); @@ -148,15 +147,15 @@ pushULong(r); } else - pushNumber(toUInt32(toInteger(a)) >> (count & 0x1F)); + pushNumber(toUInt32(meta->toInteger(a)) >> (count & 0x1F)); } break; case eBitwiseAnd: { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -205,7 +204,7 @@ } } else - pushNumber(toInteger(a) & toInteger(b)); + pushNumber(meta->toInteger(a) & meta->toInteger(b)); } } break; @@ -213,8 +212,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -263,7 +262,7 @@ } } else - pushNumber(toInteger(a) ^ toInteger(b)); + pushNumber(meta->toInteger(a) ^ meta->toInteger(b)); } } break; @@ -271,8 +270,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -321,7 +320,7 @@ } } else - pushNumber(toInteger(a) | toInteger(b)); + pushNumber(meta->toInteger(a) | meta->toInteger(b)); } } break; @@ -330,18 +329,18 @@ { b = pop(); a = pop(); - a = toPrimitive(a); - b = toPrimitive(b); + a = meta->toPrimitive(a); + b = meta->toPrimitive(b); if (JS2VAL_IS_STRING(a) || JS2VAL_IS_STRING(b)) { - const String *astr = toString(a); - const String *bstr = toString(b); + const String *astr = meta->toString(a); + const String *bstr = meta->toString(b); String *c = allocStringPtr(astr); *c += *bstr; push(STRING_TO_JS2VAL(c)); } else { - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -390,8 +389,8 @@ } } else { - float64 x = toFloat64(a); - float64 y = toFloat64(b); + float64 x = meta->toFloat64(a); + float64 y = meta->toFloat64(b); float64 z = x + y; if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b)) pushFloat(z); @@ -407,8 +406,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -457,8 +456,8 @@ } } else { - float64 x = toFloat64(a); - float64 y = toFloat64(b); + float64 x = meta->toFloat64(a); + float64 y = meta->toFloat64(b); float64 z = x - y; if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b)) pushFloat(z); @@ -473,8 +472,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -523,8 +522,8 @@ } } else { - float64 x = toFloat64(a); - float64 y = toFloat64(b); + float64 x = meta->toFloat64(a); + float64 y = meta->toFloat64(b); float64 z = x * y; if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b)) pushFloat(z); @@ -539,8 +538,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -589,8 +588,8 @@ } } else { - float64 x = toFloat64(a); - float64 y = toFloat64(b); + float64 x = meta->toFloat64(a); + float64 y = meta->toFloat64(b); float64 z = x / y; if (JS2VAL_IS_FLOAT(a) || JS2VAL_IS_FLOAT(b)) pushFloat(z); @@ -605,8 +604,8 @@ { b = pop(); a = pop(); - a = toGeneralNumber(a); - b = toGeneralNumber(b); + a = meta->toGeneralNumber(a); + b = meta->toGeneralNumber(b); if (JS2VAL_IS_LONG(a)) { int64 x = *JS2VAL_TO_LONG(a); if (JS2VAL_IS_LONG(b)) { @@ -655,8 +654,8 @@ } } else { - float64 x = toFloat64(a); - float64 y = toFloat64(b); + float64 x = meta->toFloat64(a); + float64 y = meta->toFloat64(b); float64 z; #ifdef XP_PC /* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */ @@ -678,14 +677,14 @@ { b = pop(); a = pop(); - push(BOOLEAN_TO_JS2VAL(toBoolean(a) ^ toBoolean(b))); + push(BOOLEAN_TO_JS2VAL(meta->toBoolean(a) ^ meta->toBoolean(b))); } break; case eLogicalNot: { a = pop(); - push(BOOLEAN_TO_JS2VAL(!toBoolean(a))); + push(BOOLEAN_TO_JS2VAL(!meta->toBoolean(a))); } break; @@ -693,13 +692,13 @@ { b = pop(); a = pop(); - a = toPrimitive(a); - b = toPrimitive(b); + a = meta->toPrimitive(a); + b = meta->toPrimitive(b); bool rval; if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b)) rval = (*JS2VAL_TO_STRING(a) < *JS2VAL_TO_STRING(b)); else - rval = toFloat64(a) < toFloat64(b); + rval = meta->toFloat64(a) < meta->toFloat64(b); push(BOOLEAN_TO_JS2VAL(rval)); } break; @@ -708,13 +707,13 @@ { b = pop(); a = pop(); - a = toPrimitive(a); - b = toPrimitive(b); + a = meta->toPrimitive(a); + b = meta->toPrimitive(b); bool rval; if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b)) rval = (*JS2VAL_TO_STRING(a) <= *JS2VAL_TO_STRING(b)); else - rval = toFloat64(a) <= toFloat64(b); + rval = meta->toFloat64(a) <= meta->toFloat64(b); push(BOOLEAN_TO_JS2VAL(rval)); } break; @@ -723,13 +722,13 @@ { b = pop(); a = pop(); - a = toPrimitive(a); - b = toPrimitive(b); + a = meta->toPrimitive(a); + b = meta->toPrimitive(b); bool rval; if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b)) rval = (*JS2VAL_TO_STRING(a) > *JS2VAL_TO_STRING(b)); else - rval = toFloat64(a) > toFloat64(b); + rval = meta->toFloat64(a) > meta->toFloat64(b); push(BOOLEAN_TO_JS2VAL(rval)); } break; @@ -738,13 +737,13 @@ { b = pop(); a = pop(); - a = toPrimitive(a); - b = toPrimitive(b); + a = meta->toPrimitive(a); + b = meta->toPrimitive(b); bool rval; if (JS2VAL_IS_STRING(a) && JS2VAL_IS_STRING(b)) rval = (*JS2VAL_TO_STRING(a) >= *JS2VAL_TO_STRING(b)); else - rval = toFloat64(a) >= toFloat64(b); + rval = meta->toFloat64(a) >= meta->toFloat64(b); push(BOOLEAN_TO_JS2VAL(rval)); } break; @@ -762,29 +761,29 @@ if (JS2VAL_IS_BOOLEAN(b)) rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b)); else { - b = toPrimitive(b); + b = meta->toPrimitive(b); if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b)) rval = false; else - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); } } else if (JS2VAL_IS_NUMBER(a)) { - b = toPrimitive(b); + b = meta->toPrimitive(b); if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b)) rval = false; else - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); } else if (JS2VAL_IS_STRING(a)) { - b = toPrimitive(b); + b = meta->toPrimitive(b); if (JS2VAL_IS_NULL(b) || JS2VAL_IS_UNDEFINED(b)) rval = false; else if (JS2VAL_IS_BOOLEAN(b) || JS2VAL_IS_NUMBER(b)) - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); else rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b)); } @@ -793,31 +792,31 @@ rval = false; else if (JS2VAL_IS_BOOLEAN(b)) { - a = toPrimitive(a); + a = meta->toPrimitive(a); if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a)) rval = false; else if (JS2VAL_IS_BOOLEAN(a)) rval = (JS2VAL_TO_BOOLEAN(a) == JS2VAL_TO_BOOLEAN(b)); else - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); } else if (JS2VAL_IS_NUMBER(b)) { - a = toPrimitive(a); + a = meta->toPrimitive(a); if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a)) rval = false; else - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); } else if (JS2VAL_IS_STRING(b)) { - a = toPrimitive(a); + a = meta->toPrimitive(a); if (JS2VAL_IS_NULL(a) || JS2VAL_IS_UNDEFINED(a)) rval = false; else if (JS2VAL_IS_BOOLEAN(a) || JS2VAL_IS_NUMBER(a)) - rval = (toFloat64(a) == toFloat64(b)); + rval = (meta->toFloat64(a) == meta->toFloat64(b)); else rval = (*JS2VAL_TO_STRING(a) == *JS2VAL_TO_STRING(b)); } @@ -850,7 +849,7 @@ push(a); } else { - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->env.lexicalWrite(meta, mn, allocNumber(num + 1.0), true, phase); pushNumber(num); } @@ -862,7 +861,7 @@ Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; pc += sizeof(short); a = meta->env.lexicalRead(meta, mn, phase); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->env.lexicalWrite(meta, mn, allocNumber(num - 1.0), true, phase); pushNumber(num); } @@ -872,7 +871,7 @@ Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; pc += sizeof(short); a = meta->env.lexicalRead(meta, mn, phase); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num + 1.0); meta->env.lexicalWrite(meta, mn, a, true, phase); } @@ -882,7 +881,7 @@ Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; pc += sizeof(short); a = meta->env.lexicalRead(meta, mn, phase); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num - 1.0); meta->env.lexicalWrite(meta, mn, a, true, phase); } @@ -896,7 +895,7 @@ baseVal = pop(); if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->writeProperty(baseVal, mn, &lookup, true, allocNumber(num + 1.0), RunPhase); pushNumber(num); baseVal = JS2VAL_VOID; @@ -910,7 +909,7 @@ baseVal = pop(); if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->writeProperty(baseVal, mn, &lookup, true, allocNumber(num - 1.0), RunPhase); pushNumber(num); baseVal = JS2VAL_VOID; @@ -924,7 +923,7 @@ baseVal = pop(); if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num + 1.0); meta->writeProperty(baseVal, mn, &lookup, true, a, RunPhase); baseVal = JS2VAL_VOID; @@ -938,7 +937,7 @@ baseVal = pop(); if (!meta->readProperty(baseVal, mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num - 1.0); meta->writeProperty(baseVal, mn, &lookup, true, a, RunPhase); baseVal = JS2VAL_VOID; @@ -950,11 +949,11 @@ LookupKind lookup(false, NULL); indexVal = pop(); baseVal = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->writeProperty(baseVal, &mn, &lookup, true, allocNumber(num + 1.0), RunPhase); pushNumber(num); baseVal = JS2VAL_VOID; @@ -966,11 +965,11 @@ LookupKind lookup(false, NULL); indexVal = pop(); baseVal = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); meta->writeProperty(baseVal, &mn, &lookup, true, allocNumber(num - 1.0), RunPhase); pushNumber(num); baseVal = JS2VAL_VOID; @@ -982,11 +981,11 @@ LookupKind lookup(false, NULL); indexVal = pop(); baseVal = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num + 1.0); meta->writeProperty(baseVal, &mn, &lookup, true, a, RunPhase); baseVal = JS2VAL_VOID; @@ -998,11 +997,11 @@ LookupKind lookup(false, NULL); indexVal = pop(); baseVal = pop(); - const String *indexStr = toString(indexVal); + const String *indexStr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*indexStr], meta->publicNamespace); if (!meta->readProperty(baseVal, &mn, &lookup, RunPhase, &a)) meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); - float64 num = toFloat64(a); + float64 num = meta->toFloat64(a); a = pushNumber(num - 1.0); meta->writeProperty(baseVal, &mn, &lookup, true, a, RunPhase); baseVal = JS2VAL_VOID; diff --git a/mozilla/js2/src/js2op_flowcontrol.cpp b/mozilla/js2/src/js2op_flowcontrol.cpp index a8e7e496cf2..528bbf6bb88 100644 --- a/mozilla/js2/src/js2op_flowcontrol.cpp +++ b/mozilla/js2/src/js2op_flowcontrol.cpp @@ -34,7 +34,7 @@ case eBranchTrue: { a = pop(); - bool c = toBoolean(a); + bool c = meta->toBoolean(a); if (c) { int32 offset = BytecodeContainer::getOffset(pc); pc += offset; @@ -47,7 +47,7 @@ case eBranchFalse: { a = pop(); - bool c = toBoolean(a); + bool c = meta->toBoolean(a); if (!c) { int32 offset = BytecodeContainer::getOffset(pc); pc += offset; @@ -82,7 +82,7 @@ case eFirst: { a = pop(); - b = toObject(a); + b = meta->toObject(a); ForIteratorObject *fi = new ForIteratorObject(JS2VAL_TO_OBJECT(b)); push(OBJECT_TO_JS2VAL(fi)); push(BOOLEAN_TO_JS2VAL(fi->first())); diff --git a/mozilla/js2/src/js2op_invocation.cpp b/mozilla/js2/src/js2op_invocation.cpp index 4bf6730bb61..a16e0422c2a 100644 --- a/mozilla/js2/src/js2op_invocation.cpp +++ b/mozilla/js2/src/js2op_invocation.cpp @@ -37,12 +37,12 @@ { uint16 argCount = BytecodeContainer::getShort(pc); pc += sizeof(uint16); - a = top(); + a = top(argCount + 1); ASSERT(JS2VAL_IS_OBJECT(a) && !JS2VAL_IS_NULL(a)); JS2Object *obj = JS2VAL_TO_OBJECT(a); if (obj->kind == ClassKind) { JS2Class *c = checked_cast(obj); - a = c->construct(meta, JS2VAL_NULL, NULL, argCount); + a = c->construct(meta, JS2VAL_NULL, base(argCount), argCount); pop(argCount + 1); push(a); } @@ -94,11 +94,11 @@ uint16 argCount = BytecodeContainer::getShort(pc); pc += sizeof(uint16); a = top(argCount + 2); // 'this' - b = top(argCount + 1); // target function + b = top(argCount + 1); // target function if (JS2VAL_IS_PRIMITIVE(b)) meta->reportError(Exception::badValueError, "Can't call on primitive value", errorPos()); JS2Object *fObj = JS2VAL_TO_OBJECT(b); - if (fObj->kind == FixedInstanceKind) { + if ((fObj->kind == FixedInstanceKind) && (meta->objectType(b) == meta->functionClass)) { FixedInstance *fInst = checked_cast(fObj); FunctionWrapper *fWrap = fInst->fWrap; js2val compileThis = fWrap->compileFrame->thisObject; diff --git a/mozilla/js2/src/js2op_literal.cpp b/mozilla/js2/src/js2op_literal.cpp index d76f2d9b0ae..f90aa105c1d 100644 --- a/mozilla/js2/src/js2op_literal.cpp +++ b/mozilla/js2/src/js2op_literal.cpp @@ -73,6 +73,14 @@ } break; + case eRegExp: + { + RegExpInstance *x = bCon->mRegExpList[BytecodeContainer::getShort(pc)]; + push(OBJECT_TO_JS2VAL(x)); + pc += sizeof(short); + } + break; + case eNull: { push(JS2VAL_NULL); diff --git a/mozilla/js2/src/js2regexp.cpp b/mozilla/js2/src/js2regexp.cpp index ea6689e0ed0..090e7106633 100644 --- a/mozilla/js2/src/js2regexp.cpp +++ b/mozilla/js2/src/js2regexp.cpp @@ -134,23 +134,23 @@ namespace MetaData { if (argc > 0) { int32 index = 0; - const String *str = meta->engine->toString(argv[0]); + const String *str = meta->engine->meta->toString(argv[0]); js2val globalMultiline = thisInst->getMultiline(meta); if (thisInst->getGlobal(meta)) { js2val lastIndex = thisInst->getLastIndex(meta); - index = meta->engine->toInteger(lastIndex); + index = meta->engine->meta->toInteger(lastIndex); } - REMatchState *match = REExecute(thisInst->mRegExp, str->begin(), index, toInt32(str->length()), meta->engine->toBoolean(globalMultiline)); + REMatchState *match = REExecute(thisInst->mRegExp, str->begin(), index, toInt32(str->length()), meta->toBoolean(globalMultiline)); if (match) { PrototypeInstance *A = new PrototypeInstance(meta->objectClass->prototype, meta->objectClass); result = OBJECT_TO_JS2VAL(A); js2val matchStr = meta->engine->allocString(str->substr((uint32)match->startIndex, (uint32)match->endIndex - match->startIndex)); - Multiname mname(&meta->world.identifiers[*numberToString((long)0)], meta->publicNamespace); + Multiname mname(&meta->world.identifiers[*meta->toString((long)0)], meta->publicNamespace); meta->writeDynamicProperty(A, &mname, true, matchStr, RunPhase); for (int32 i = 0; i < match->parenCount; i++) { - Multiname mname(&meta->world.identifiers[*numberToString(i + 1)], meta->publicNamespace); + Multiname mname(&meta->world.identifiers[*meta->toString(i + 1)], meta->publicNamespace); if (match->parens[i].index != -1) { js2val parenStr = meta->engine->allocString(str->substr((uint32)(match->parens[i].index), (uint32)(match->parens[i].length))); meta->writeDynamicProperty(A, &mname, true, parenStr, RunPhase); @@ -182,5 +182,52 @@ namespace MetaData { return result; } + js2val RegExp_Constructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) + { + // XXX Change constructors to take js2val pointer for the result (which would be an already + // rooted pointer). + RegExpInstance *thisInst = new RegExpInstance(meta->regexpClass); + JS2Object::RootIterator ri = JS2Object::addRoot(&thisInst); + js2val thatValue = OBJECT_TO_JS2VAL(thisInst); + REuint32 flags = 0; + + const String *regexpStr = meta->engine->Empty_StringAtom; + const String *flagStr = meta->engine->Empty_StringAtom; + if (argc > 0) { + if (meta->objectType(argv[0]) == meta->regexpClass) { + if ((argc == 1) || JS2VAL_IS_UNDEFINED(argv[1])) { + RegExpInstance *otherInst = checked_cast(JS2VAL_TO_OBJECT(argv[0])); + js2val src = otherInst->getSource(meta); + ASSERT(JS2VAL_IS_STRING(src)); + regexpStr = JS2VAL_TO_STRING(src); + flags = otherInst->mRegExp->flags; + } + else + meta->reportError(Exception::typeError, "Illegal RegExp constructor args", meta->engine->errorPos()); + } + else + regexpStr = meta->toString(argv[0]); + if ((argc > 1) && !JS2VAL_IS_UNDEFINED(argv[1])) { + flagStr = meta->toString(argv[1]); + if (parseFlags(flagStr->begin(), (int32)flagStr->length(), &flags) != RE_NO_ERROR) + meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), *regexpStr + "/" + *flagStr); // XXX error message? + } + } + REState *pState = REParse(regexpStr->begin(), (int32)regexpStr->length(), flags, RE_VERSION_1); + if (pState) { + thisInst->mRegExp = pState; + // XXX ECMA spec says these are DONTENUM + thisInst->setSource(meta, STRING_TO_JS2VAL(regexpStr)); + thisInst->setGlobal(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_GLOBAL) == RE_GLOBAL)); + thisInst->setIgnoreCase(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_IGNORECASE) == RE_IGNORECASE)); + thisInst->setLastIndex(meta, INT_TO_JS2VAL(0)); + thisInst->setMultiline(meta, BOOLEAN_TO_JS2VAL((pState->flags & RE_MULTILINE) == RE_MULTILINE)); + } + else + meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), "/" + *regexpStr + "/" + *flagStr); // XXX what about the RE parser error message? + JS2Object::removeRoot(ri); + return thatValue; + } + } } diff --git a/mozilla/js2/src/js2string.cpp b/mozilla/js2/src/js2string.cpp index 74d56aa024e..f1c067596a4 100644 --- a/mozilla/js2/src/js2string.cpp +++ b/mozilla/js2/src/js2string.cpp @@ -65,9 +65,9 @@ js2val String_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val StringInstance *strInst = checked_cast(JS2VAL_TO_OBJECT(thatValue)); if (argc > 0) - strInst->mValue = meta->engine->allocStringPtr(meta->engine->toString(argv[0])); + strInst->mValue = meta->engine->allocStringPtr(meta->engine->meta->toString(argv[0])); else - strInst->mValue = meta->engine->allocStringPtr((String *)NULL); + strInst->mValue = meta->engine->allocStringPtr(""); return thatValue; } @@ -109,7 +109,7 @@ 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->engine->toString(thisValue)); + js2val S = STRING_TO_JS2VAL(meta->engine->meta->toString(thisValue)); js2val regexp = argv[0]; @@ -144,7 +144,7 @@ static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *a static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) { - js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue)); + js2val S = STRING_TO_JS2VAL(meta->engine->meta->toString(thisValue)); js2val regexp = argv[0]; if ((argc == 0) || (meta->objectType(thisValue) != meta->regexpClass)) { @@ -170,7 +170,7 @@ static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *ar else lastIndex = match->endIndex; js2val matchStr = meta->engine->allocString(JS2VAL_TO_STRING(S)->substr(toUInt32(match->startIndex), toUInt32(match->endIndex) - match->startIndex)); - Multiname mname(&meta->world.identifiers[*numberToString(index)], meta->publicNamespace); + Multiname mname(&meta->world.identifiers[*meta->toString(index)], meta->publicNamespace); index++; meta->writeDynamicProperty(A, &mname, true, matchStr, RunPhase); } @@ -179,14 +179,13 @@ static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *ar } } -#if 0 static const String interpretDollar(JS2Metadata *meta, const String *replaceStr, uint32 dollarPos, const String *searchStr, REMatchState *match, uint32 &skip) { skip = 2; const char16 *dollarValue = replaceStr->begin() + dollarPos + 1; switch (*dollarValue) { case '$': - return meta->engine->Dollar_StringAtom; + return *meta->engine->Dollar_StringAtom; case '&': return searchStr->substr((uint32)match->startIndex, (uint32)match->endIndex - match->startIndex); case '`': @@ -220,7 +219,7 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr, // fall thru default: skip = 1; - return meta->engine->Dollar_StringAtom; + return *meta->engine->Dollar_StringAtom; } } @@ -235,7 +234,7 @@ static const String interpretDollar(JS2Metadata *meta, const String *replaceStr, * in the same manner as in String.prototype.match, including the update of searchValue.lastIndex. Let m * be the number of left capturing parentheses in searchValue (NCapturingParens as specified in section 15.10.2.1). * - * If searchValue is not a regular expression, let searchString be ToString(searchValue) and search string for the first + * If searchValue is not a regular expression, let searchString be meta->toString(searchValue) and search string for the first * occurrence of searchString. Let m be 0. * * If replaceValue is a function, then for each matched substring, call the function with the following m + 3 arguments. @@ -255,19 +254,19 @@ 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->engine->toString(thisValue); + const String *S = meta->engine->meta->toString(thisValue); js2val searchValue; js2val replaceValue; if (argc > 0) searchValue = argv[0]; if (argc > 1) replaceValue = argv[1]; - const String *replaceStr = meta->engine->toString(replaceValue); + const String *replaceStr = meta->engine->meta->toString(replaceValue); if (meta->objectType(searchValue) != meta->regexpClass) { - REState *pState = (checked_cast(JS2VAL_TO_OBJECT(searchValue)))->mRegExp; + RegExpInstance *reInst = checked_cast(JS2VAL_TO_OBJECT(searchValue)); + REState *pState = reInst->mRegExp; REMatchState *match; -// uint32 m = pState->parenCount; String newString; int32 lastIndex = 0; @@ -282,7 +281,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val * if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) { uint32 skip; insertString += replaceStr->substr(start, dollarPos - start); - insertString += interpretDollar(cx, replaceStr, dollarPos, S, match, skip); + insertString += interpretDollar(meta, replaceStr, dollarPos, S, match, skip); start = dollarPos + skip; } else { @@ -304,11 +303,11 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val * } newString += S->substr(toUInt32(lastIndex), toUInt32(S->length()) - lastIndex); if ((pState->flags & RE_GLOBAL) == 0) - JS2VAL_TO_OBJECT(searchValue)->setProperty(cx, cx->LastIndex_StringAtom, NULL, JSValue::newNumber((float64)lastIndex)); + reInst->setLastIndex(meta, meta->engine->allocNumber((float64)lastIndex)); return meta->engine->allocString(newString); } else { - const String *searchStr = JSValue::string(JSValue::toString(cx, searchValue)); + const String *searchStr = meta->engine->meta->toString(searchValue); REMatchState match; uint32 pos = S->find(*searchStr, 0); if (pos == String::npos) @@ -324,7 +323,7 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val * if ((dollarPos != String::npos) && (dollarPos < (replaceStr->length() - 1))) { uint32 skip; insertString += replaceStr->substr(start, dollarPos - start); - insertString += interpretDollar(cx, replaceStr, dollarPos, S, &match, skip); + insertString += interpretDollar(meta, replaceStr, dollarPos, S, &match, skip); start = dollarPos + skip; } else { @@ -365,7 +364,7 @@ static void strSplitMatch(const String *S, uint32 q, const String *R, MatchResul result.failure = false; } -static void regexpSplitMatch(const String *S, uint32 q, REState *RE, MatchResult &result) +static void regexpSplitMatch(JS2Metadata *meta, const String *S, uint32 q, REState *RE, MatchResult &result) { result.failure = true; result.captures = NULL; @@ -392,10 +391,11 @@ static void regexpSplitMatch(const String *S, uint32 q, REState *RE, MatchResult static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) { - const String *S = meta->engine->toString(thisValue); + const String *S = meta->engine->meta->toString(thisValue); + + js2val result = OBJECT_TO_JS2VAL(new ArrayInstance(meta->arrayClass)); + ArrayInstance *A = checked_cast(JS2VAL_TO_OBJECT(result)); - js2val result = Array_Type->newInstance(cx); - JSArrayInstance *A = checked_cast(JSValue::instance(result)); uint32 lim; js2val separatorV = (argc > 0) ? argv[0] : JS2VAL_UNDEFINED; js2val limitV = (argc > 1) ? argv[1] : JS2VAL_UNDEFINED; @@ -413,7 +413,7 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar if (meta->objectType(separatorV) == meta->regexpClass) RE = (checked_cast(JS2VAL_TO_OBJECT(separatorV)))->mRegExp; else - R = meta->engine->toString(separatorV); + R = meta->engine->meta->toString(separatorV); if (lim == 0) return result; @@ -425,15 +425,18 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar return JSValue(A); } */ + Multiname mn(NULL, meta->publicNamespace); if (s == 0) { MatchResult z; if (RE) - regexpSplitMatch(S, 0, RE, z); + regexpSplitMatch(meta, S, 0, RE, z); else strSplitMatch(S, 0, R, z); if (!z.failure) return result; - A->setProperty(cx, widenCString("0"), NULL, STRING_TO_JS2VAL(S)); + mn.name = meta->toString((int32)0); + meta->writeDynamicProperty(A, &mn, true, STRING_TO_JS2VAL(S), RunPhase); + delete mn.name; return result; } @@ -441,14 +444,15 @@ static js2val String_split(JS2Metadata *meta, const js2val thisValue, js2val *ar uint32 q = p; step11: if (q == s) { - String *T = meta->engine->allocString(*S, p, (s - p)); - js2val v = STRING_TO_JS2VAL(T); - A->setProperty(cx, *numberToString(A->mLength), NULL, v); + js2val v = meta->engine->allocString(new String(*S, p, (s - p))); + mn.name = meta->toString(getLength(meta, A)); + meta->writeDynamicProperty(A, &mn, true, v, RunPhase); + delete mn.name; return result; } MatchResult z; if (RE) - regexpSplitMatch(S, q, RE, z); + regexpSplitMatch(meta, S, q, RE, z); else strSplitMatch(S, q, R, z); if (z.failure) { @@ -462,27 +466,30 @@ step11: } String *T = meta->engine->allocStringPtr(new String(*S, p, (q - p))); // XXX js2val v = STRING_TO_JS2VAL(T); - A->setProperty(cx, *numberToString(A->mLength), NULL, v); - if (A->mLength == lim) + mn.name = meta->toString(getLength(meta, A)); + meta->writeDynamicProperty(A, &mn, true, v, RunPhase); + delete mn.name; + if (getLength(meta, A) == lim) return result; p = e; for (uint32 i = 0; i < z.capturesCount; i++) { - A->setProperty(cx, *numberToString(A->mLength), NULL, z.captures[i]); - if (A->mLength == lim) + mn.name = meta->toString(getLength(meta, A)); + meta->writeDynamicProperty(A, &mn, true, z.captures[i], RunPhase); + delete mn.name; + if (getLength(meta, A) == lim) return result; } } } -#endif static js2val String_charAt(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) { - const String *str = meta->engine->toString(thisValue); + const String *str = meta->engine->meta->toString(thisValue); uint32 pos = 0; if (argc > 0) - pos = toUInt32(meta->engine->toInteger(argv[0])); + pos = toUInt32(meta->toInteger(argv[0])); if ((pos < 0) || (pos >= str->size())) return STRING_TO_JS2VAL(meta->engine->Empty_StringAtom); @@ -493,11 +500,11 @@ 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->engine->toString(thisValue); + const String *str = meta->toString(thisValue); uint32 pos = 0; if (argc > 0) - pos = toUInt32(meta->engine->toInteger(argv[0])); + pos = toUInt32(meta->toInteger(argv[0])); if ((pos < 0) || (pos >= str->size())) return meta->engine->nanValue; @@ -507,11 +514,11 @@ 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->engine->toString(thisValue); + const String *str = meta->toString(thisValue); String *result = meta->engine->allocStringPtr(str); for (uint32 i = 0; i < argc; i++) { - *result += *meta->engine->toString(argv[i]); + *result += *meta->toString(argv[i]); } return STRING_TO_JS2VAL(result); @@ -522,12 +529,12 @@ static js2val String_indexOf(JS2Metadata *meta, const js2val thisValue, js2val * if (argc == 0) return meta->engine->allocNumber(-1.0); - const String *str = meta->engine->toString(thisValue); - const String *searchStr = meta->engine->toString(argv[0]); + const String *str = meta->toString(thisValue); + const String *searchStr = meta->toString(argv[0]); uint32 pos = 0; if (argc > 1) { - float64 fpos = meta->engine->toFloat64(argv[1]); + float64 fpos = meta->toFloat64(argv[1]); if (JSDOUBLE_IS_NaN(fpos)) pos = 0; if (fpos < 0) @@ -549,12 +556,12 @@ static js2val String_lastIndexOf(JS2Metadata *meta, const js2val thisValue, js2v if (argc == 0) return meta->engine->allocNumber(-1.0); - const String *str = meta->engine->toString(thisValue); - const String *searchStr = meta->engine->toString(argv[0]); + const String *str = meta->toString(thisValue); + const String *searchStr = meta->toString(argv[0]); uint32 pos = str->size(); if (argc > 1) { - float64 fpos = meta->engine->toFloat64(argv[1]); + float64 fpos = meta->toFloat64(argv[1]); if (JSDOUBLE_IS_NaN(fpos)) pos = str->size(); else { @@ -580,7 +587,7 @@ static js2val String_localeCompare(JS2Metadata *meta, const js2val /*thisValue*/ static js2val String_toLowerCase(JS2Metadata *meta, const js2val thisValue, js2val * /*argv*/, uint32 /*argc*/) { - js2val S = STRING_TO_JS2VAL(meta->engine->toString(thisValue)); + js2val S = STRING_TO_JS2VAL(meta->toString(thisValue)); String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S)); for (String::iterator i = result->begin(), end = result->end(); i != end; i++) @@ -591,7 +598,7 @@ 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->engine->toString(thisValue)); + js2val S = STRING_TO_JS2VAL(meta->toString(thisValue)); String *result = meta->engine->allocStringPtr(JS2VAL_TO_STRING(S)); for (String::iterator i = result->begin(), end = result->end(); i != end; i++) @@ -623,13 +630,13 @@ 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->engine->toString(thisValue); + const String *sourceString = meta->toString(thisValue); uint32 sourceLength = sourceString->size(); uint32 start, end; if (argc > 0) { - int32 arg0 = meta->engine->toInteger(argv[0]); + int32 arg0 = meta->toInteger(argv[0]); if (arg0 < 0) { arg0 += sourceLength; if (arg0 < 0) @@ -648,7 +655,7 @@ static js2val String_slice(JS2Metadata *meta, const js2val thisValue, js2val *ar start = 0; // XXX argc must be > 1 since the length of the function is 1 if (argc > 1) { - int32 arg1 = meta->engine->toInteger(argv[1]); + int32 arg1 = meta->toInteger(argv[1]); if (arg1 < 0) { arg1 += sourceLength; if (arg1 < 0) @@ -695,20 +702,20 @@ 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->engine->toString(thisValue); + const String *sourceString = meta->toString(thisValue); uint32 sourceLength = sourceString->size(); uint32 start, end; if (argc > 0) { - float64 farg0 = meta->engine->toFloat64(argv[0]); + float64 farg0 = meta->toFloat64(argv[0]); if (JSDOUBLE_IS_NaN(farg0) || (farg0 < 0)) start = 0; else { if (!JSDOUBLE_IS_FINITE(farg0)) start = sourceLength; else { - start = meta->engine->toUInt32(farg0); + start = JS2Engine::toUInt32(farg0); if (start > sourceLength) start = sourceLength; } @@ -718,14 +725,14 @@ static js2val String_substring(JS2Metadata *meta, const js2val thisValue, js2val start = 0; if (argc > 1) { - float64 farg1 = meta->engine->toFloat64(argv[1]); + float64 farg1 = meta->toFloat64(argv[1]); if (JSDOUBLE_IS_NaN(farg1) || (farg1 < 0)) end = 0; else { if (!JSDOUBLE_IS_FINITE(farg1)) end = sourceLength; else { - end = meta->engine->toUInt32(farg1); + end = JS2Engine::toUInt32(farg1); if (end > sourceLength) end = sourceLength; } @@ -762,13 +769,11 @@ void initStringObject(JS2Metadata *meta) { "indexOf", 2, String_indexOf }, // XXX ECMA spec says 1, but tests want 2 XXX { "lastIndexOf", 2, String_lastIndexOf }, // XXX ECMA spec says 1, but tests want 2 XXX { "localeCompare", 1, String_localeCompare }, -#if 0 { "match", 1, String_match }, { "replace", 2, String_replace }, { "search", 1, String_search }, { "slice", 2, String_slice }, { "split", 1, String_split }, // XXX ECMA spec says 2, but tests want 1 XXX -#endif { "substring", 2, String_substring }, { "toSource", 0, String_toString }, { "toLocaleUpperCase", 0, String_toUpperCase }, // (sic)