Implement optimized object-ops for dense arrays, b=322889, r+a=brendan.

This commit is contained in:
shaver@mozilla.org 2008-02-18 13:01:47 -08:00
parent 5038f77cb2
commit 8de570e122
13 changed files with 915 additions and 149 deletions

View File

@ -129,7 +129,7 @@ else
ifdef USE_MSVC
OPTIMIZER = -Zi
else
OPTIMIZER = -g
OPTIMIZER = -g3
endif
DEFINES += -DDEBUG -DDEBUG_$(USER)
OBJDIR_TAG = _DBG

View File

@ -52,6 +52,7 @@
#include "jsutil.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jsarray.h"
#include "jsatom.h"
#include "jscntxt.h"
#include "jsdbgapi.h"
@ -325,7 +326,11 @@ static int
usage(void)
{
fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
fprintf(gErrFile, "usage: js [-PswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] [scriptfile] [scriptarg...]\n");
fprintf(gErrFile, "usage: js [-zKPswWxCi] [-b branchlimit] [-c stackchunksize] [-o option] [-v version] [-f scriptfile] [-e script] [-S maxstacksize] "
#ifdef JS_GC_ZEAL
"[-Z gczeal] "
#endif
"[scriptfile] [scriptarg...]\n");
return 2;
}
@ -371,6 +376,9 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
case 'e':
case 'v':
case 'S':
#ifdef JS_GC_ZEAL
case 'Z':
#endif
++i;
break;
default:;
@ -415,6 +423,14 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
break;
#ifdef JS_GC_ZEAL
case 'Z':
if (++i == argc)
return usage();
JS_SetGCZeal(cx, atoi(argv[i]));
break;
#endif
case 'w':
reportWarnings = JS_TRUE;
break;
@ -2531,6 +2547,9 @@ static JSFunctionSpec shell_functions[] = {
JS_FS("stopShark", js_StopShark, 0,0,0),
JS_FS("connectShark", js_ConnectShark, 0,0,0),
JS_FS("disconnectShark", js_DisconnectShark, 0,0,0),
#endif
#ifdef DEBUG_ARRAYS
JS_FS("arrayInfo", js_ArrayInfo, 1,0,0),
#endif
JS_FS_END
};
@ -2602,6 +2621,9 @@ static const char *const shell_help_messages[] = {
" The -k switch does this automatically.",
"disconnectShark() Disconnect from Shark.",
#endif
#ifdef DEBUG_ARRAYS
"arrayInfo(a1, a2, ...) Report statistics about arrays.",
#endif
};
/* Help messages must match shell functions. */

View File

@ -304,3 +304,4 @@ MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid incremen
MSG_DEF(JSMSG_NULL_OR_UNDEFINED, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")
MSG_DEF(JSMSG_BAD_OBJECT_INIT, 224, 0, JSEXN_SYNTAXERR, "invalid object initializer")
MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 225, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties")

View File

@ -3665,7 +3665,7 @@ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
JS_PUBLIC_API(JSBool)
JS_IsArrayObject(JSContext *cx, JSObject *obj)
{
return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
return OBJ_IS_ARRAY(cx, obj);
}
JS_PUBLIC_API(JSBool)

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,11 @@ JS_BEGIN_EXTERN_C
extern JSBool
js_IdIsIndex(jsval id, jsuint *indexp);
extern JSClass js_ArrayClass;
extern JSClass js_ArrayClass, js_SlowArrayClass;
#define ARRAY_IS_DENSE(cx, obj) (OBJ_GET_CLASS(cx, obj) == &js_ArrayClass)
#define OBJ_IS_ARRAY(cx, obj) (ARRAY_IS_DENSE(cx, obj) || \
OBJ_GET_CLASS(cx, obj) == &js_SlowArrayClass)
extern JSObject *
js_InitArrayClass(JSContext *cx, JSObject *obj);
@ -61,7 +65,13 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
extern JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector);
/* Create an array object that starts out already made slow/sparse. */
extern JSObject *
js_NewSlowArrayObject(JSContext *cx);
#define JSSLOT_ARRAY_LENGTH JSSLOT_PRIVATE
#define JSSLOT_ARRAY_COUNT (JSSLOT_ARRAY_LENGTH + 1)
#define JSSLOT_ARRAY_LOOKUP_HOLDER (JSSLOT_ARRAY_COUNT + 1)
extern JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
@ -99,6 +109,11 @@ extern JSBool
js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp,
void *arg, void *tmp);
#ifdef DEBUG_ARRAYS
extern JSBool
js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
#endif
JS_END_EXTERN_C
#endif /* jsarray_h___ */

View File

@ -4125,14 +4125,23 @@ interrupt:
str = JSVAL_TO_STRING(lval);
rval = INT_TO_JSVAL(JSSTRING_LENGTH(str));
} else if (!JSVAL_IS_PRIMITIVE(lval) &&
(obj = JSVAL_TO_OBJECT(lval),
OBJ_GET_CLASS(cx, obj) == &js_ArrayClass)) {
(obj = JSVAL_TO_OBJECT(lval), OBJ_IS_ARRAY(cx, obj))) {
jsuint length;
/*
* We know that the array is created with only its 'length'
* private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
* also JSOP_ARRAYPUSH, far below.
*/
rval = obj->fslots[JSSLOT_ARRAY_LENGTH];
length = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (length <= JSVAL_INT_MAX) {
rval = INT_TO_JSVAL(length);
} else {
ok = js_NewDoubleValue(cx, (jsdouble)length, &rval);
if (!ok)
goto out;
}
} else {
i = -1;
len = JSOP_LENGTH_LENGTH;
@ -6544,10 +6553,7 @@ interrupt:
* of the comprehension have added the only properties directly in
* the array object.
*/
lval = obj->fslots[JSSLOT_ARRAY_LENGTH];
JS_ASSERT(JSVAL_IS_INT(lval));
i = JSVAL_TO_INT(lval);
SAVE_SP_AND_PC(fp);
i = obj->fslots[JSSLOT_ARRAY_LENGTH];
if (i == ARRAY_INIT_LIMIT) {
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
JSMSG_ARRAY_INIT_TOO_BIG);

View File

@ -324,7 +324,7 @@ js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj)
/*
* Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
* Otherwise construct the defualt iterator.
* Otherwise construct the default iterator.
*/
JS_FRIEND_API(JSBool)
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)

View File

@ -4127,8 +4127,10 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
rt = cx->runtime;
clasp = OBJ_GET_CLASS(cx, obj);
enumerate = clasp->enumerate;
if (clasp->flags & JSCLASS_NEW_ENUMERATE)
if (clasp->flags & JSCLASS_NEW_ENUMERATE) {
JS_ASSERT(enumerate != JS_EnumerateStub);
return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
}
switch (enum_op) {
case JSENUMERATE_INIT:
@ -4840,8 +4842,8 @@ js_DumpScopeMeters(JSRuntime *rt)
#endif
#ifdef DEBUG
static void
PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
void
js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
{
JSObject *obj;
uint32 slot;
@ -4852,14 +4854,18 @@ PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
uint32 key;
const char *slotname;
JS_ASSERT(trc->debugPrinter == PrintObjectSlotName);
JS_ASSERT(trc->debugPrinter == js_PrintObjectSlotName);
obj = (JSObject *)trc->debugPrintArg;
slot = (uint32)trc->debugPrintIndex;
if (OBJ_IS_NATIVE(obj)) {
scope = OBJ_SCOPE(obj);
sprop = SCOPE_LAST_PROP(scope);
while (sprop && sprop->slot != slot)
sprop = sprop->parent;
} else {
sprop = NULL;
}
if (!sprop) {
switch (slot) {
@ -5001,7 +5007,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
for (i = 0; i != nslots; ++i) {
v = STOBJ_GET_SLOT(obj, i);
if (JSVAL_IS_TRACEABLE(v)) {
JS_SET_TRACING_DETAILS(trc, PrintObjectSlotName, obj, i);
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
}
}

View File

@ -666,6 +666,9 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp);
extern void
js_TraceObject(JSTracer *trc, JSObject *obj);
extern void
js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
extern void
js_Clear(JSContext *cx, JSObject *obj);

View File

@ -3437,7 +3437,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp,
* matches, an index property telling the length of the left context,
* and an input property referring to the input string.
*/
obj = js_NewArrayObject(cx, 0, NULL);
obj = js_NewSlowArrayObject(cx);
if (!obj) {
ok = JS_FALSE;
goto out;

View File

@ -1221,15 +1221,14 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
* We may have set slot from a nearly-matching sprop, above.
* If so, we're overwriting that nearly-matching sprop, so we
* can reuse its slot -- we don't need to allocate a new one.
* Callers should therefore pass SPROP_INVALID_SLOT for all
* non-alias, unshared property adds.
* Similarly, we use a specific slot if provided by the caller.
*/
if (slot != SPROP_INVALID_SLOT)
JS_ASSERT(overwriting);
else if (!js_AllocSlot(cx, scope->object, &slot))
if (slot == SPROP_INVALID_SLOT &&
!js_AllocSlot(cx, scope->object, &slot)) {
goto fail_overwrite;
}
}
}
/*
* Check for a watchpoint on a deleted property; if one exists, change

View File

@ -813,7 +813,7 @@ str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp)
/*
* Forcefully ignore the first (or any) argument and return toUpperCase(),
* ECMA has reserved that argument, presumbaly for defining the locale.
* ECMA has reserved that argument, presumably for defining the locale.
*/
if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
NORMALIZE_THIS(cx, vp, str);
@ -1270,7 +1270,8 @@ match_glob(JSContext *cx, jsint count, GlobData *data)
if (!matchstr)
return JS_FALSE;
v = STRING_TO_JSVAL(matchstr);
return js_SetProperty(cx, arrayobj, INT_TO_JSID(count), &v);
JS_ASSERT(count <= JSVAL_INT_MAX);
return OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(count), &v);
}
static JSBool
@ -1803,7 +1804,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
if (argc == 0) {
v = STRING_TO_JSVAL(str);
ok = JS_SetElement(cx, arrayobj, 0, &v);
ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v);
} else {
if (JSVAL_IS_REGEXP(cx, vp[2])) {
re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));