Backed out changeset b404ad209cb9. (Bug 587257 - Make Array.prototype.join faster. r=lw)

This commit is contained in:
Robert Sayre
2010-08-23 19:20:46 -04:00
parent 1048ce19a6
commit 808e78428e
3 changed files with 66 additions and 111 deletions

View File

@@ -106,7 +106,6 @@
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "jscntxtinlines.h"
#include "jsstrinlines.h"
using namespace js;
@@ -1255,89 +1254,38 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
}
#endif
typedef HashSet<JSObject *> ObjSet;
class AutoArrayCycleDetector
{
public:
AutoArrayCycleDetector(JSContext *cx, JSObject *obj JS_GUARD_OBJECT_NOTIFIER_PARAM)
: context(cx), object(obj), genBefore(0),
hashPointer(context->busyArrays.lookupForAdd(object)), cycle(!!hashPointer)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
~AutoArrayCycleDetector() {
JS_ASSERT(context);
if (!cycle && hashPointer) {
if (genBefore == context->busyArrays.generation())
context->busyArrays.remove(hashPointer);
else
context->busyArrays.remove(object);
}
}
bool foundCycle() {
return cycle;
}
bool update() {
JS_ASSERT(!hashPointer);
if (!context->busyArrays.add(hashPointer, object))
return false;
genBefore = context->busyArrays.generation();
return true;
}
protected:
JSContext *context;
JSObject *object;
uint32 genBefore;
ObjSet::AddPtr hashPointer;
JSBool cycle;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
static inline JSBool
GetElementCharacters(JSContext *cx, JSObject *obj, JSBool locale, JSCharBuffer *cb, Value *rval)
{
if (locale) {
/* Work on obj.toLocalString() instead. */
JSObject *robj;
if (!js_ValueToObjectOrNull(cx, *rval, &robj))
return false;
rval->setObjectOrNull(robj);
JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom;
if (!js_TryMethod(cx, robj, atom, 0, NULL, rval))
return false;
}
/* avoid calling js_ValueToCharBuffer if possible */
if (rval->isString())
return js_StringValueToCharBuffer(cx, *rval, *cb);
return js_ValueToCharBuffer(cx, *rval, *cb);
}
static JSBool
array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
JSString *sepstr, Value *rval)
{
JS_CHECK_RECURSION(cx, return false);
AutoArrayCycleDetector detector(cx, obj);
if (detector.foundCycle()) {
/*
* Use HashTable entry as the cycle indicator. On first visit, create the
* entry, and, when leaving, remove the entry.
*/
typedef js::HashSet<JSObject *> ObjSet;
ObjSet::AddPtr hashp = cx->busyArrays.lookupForAdd(obj);
uint32 genBefore;
if (!hashp) {
/* Not in hash table, so not a cycle. */
if (!cx->busyArrays.add(hashp, obj)) {
JS_ReportOutOfMemory(cx);
return false;
}
genBefore = cx->busyArrays.generation();
} else {
/* Cycle, so return empty string. */
rval->setString(ATOM_TO_STRING(cx->runtime->atomState.emptyAtom));
return true;
}
if (!detector.update())
return false;
AutoObjectRooter tvr(cx, obj);
/* After this point, all paths exit through the 'out' label. */
MUST_FLOW_THROUGH("out");
bool ok = false;
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
@@ -1357,41 +1305,53 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
jsuint length;
if (!js_GetLengthProperty(cx, obj, &length))
return false;
goto out;
/* avoid extra checks inside the loop if possible */
if (seplen == 0 && obj->isDenseArray()) {
jsuint len = JS_MIN(length, obj->getDenseArrayCapacity());
for (Value *vp = obj->getDenseArrayElements(), *end = vp + len; vp != end; ++vp) {
if (!JS_CHECK_OPERATION_LIMIT(cx))
return false;
*rval = *vp;
if (!rval->isMagic(JS_ARRAY_HOLE) && !rval->isNullOrUndefined()) {
if (!GetElementCharacters(cx, obj, locale, &cb, rval))
return false;
}
}
} else {
for (jsuint index = 0; index < length; index++) {
/* Use rval to locally root each element value. */
JSBool hole;
for (jsuint index = 0; index < length; index++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, obj, index, &hole, rval))
return false;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, rval)) {
goto out;
}
if (!hole && !rval->isNullOrUndefined()) {
if (!GetElementCharacters(cx, obj, locale, &cb, rval))
return false;
/* Get element's character string. */
if (!(hole || rval->isNullOrUndefined())) {
if (locale) {
/* Work on obj.toLocalString() instead. */
JSObject *robj;
if (!js_ValueToObjectOrNull(cx, *rval, &robj))
goto out;
rval->setObjectOrNull(robj);
JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom;
if (!js_TryMethod(cx, robj, atom, 0, NULL, rval))
goto out;
}
/* Append the separator. */
if (index + 1 != length) {
if (!cb.append(sep, seplen))
return false;
}
if (!js_ValueToCharBuffer(cx, *rval, cb))
goto out;
}
/* Append the separator. */
if (index + 1 != length) {
if (!cb.append(sep, seplen))
goto out;
}
}
/* Finalize the buffer. */
return BufferToString(cx, cb, rval);
if (!BufferToString(cx, cb, rval))
goto out;
ok = true;
out:
if (genBefore == cx->busyArrays.generation())
cx->busyArrays.remove(hashp);
else
cx->busyArrays.remove(obj);
return ok;
}
/* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
@@ -2672,7 +2632,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
return JS_FALSE;
}
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
vp->setNumber(i);
vp->setNumber(i);
return JS_TRUE;
}
if (i == stop)