mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
Implement optimized object-ops for dense arrays, b=322889, r+a=brendan.
This commit is contained in:
parent
5038f77cb2
commit
8de570e122
@ -129,7 +129,7 @@ else
|
|||||||
ifdef USE_MSVC
|
ifdef USE_MSVC
|
||||||
OPTIMIZER = -Zi
|
OPTIMIZER = -Zi
|
||||||
else
|
else
|
||||||
OPTIMIZER = -g
|
OPTIMIZER = -g3
|
||||||
endif
|
endif
|
||||||
DEFINES += -DDEBUG -DDEBUG_$(USER)
|
DEFINES += -DDEBUG -DDEBUG_$(USER)
|
||||||
OBJDIR_TAG = _DBG
|
OBJDIR_TAG = _DBG
|
||||||
|
24
js/src/js.c
24
js/src/js.c
@ -52,6 +52,7 @@
|
|||||||
#include "jsutil.h"
|
#include "jsutil.h"
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
#include "jsapi.h"
|
#include "jsapi.h"
|
||||||
|
#include "jsarray.h"
|
||||||
#include "jsatom.h"
|
#include "jsatom.h"
|
||||||
#include "jscntxt.h"
|
#include "jscntxt.h"
|
||||||
#include "jsdbgapi.h"
|
#include "jsdbgapi.h"
|
||||||
@ -325,7 +326,11 @@ static int
|
|||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
|
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;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,6 +376,9 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||||||
case 'e':
|
case 'e':
|
||||||
case 'v':
|
case 'v':
|
||||||
case 'S':
|
case 'S':
|
||||||
|
#ifdef JS_GC_ZEAL
|
||||||
|
case 'Z':
|
||||||
|
#endif
|
||||||
++i;
|
++i;
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
@ -415,6 +423,14 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||||||
JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
|
JS_SetVersion(cx, (JSVersion) atoi(argv[i]));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef JS_GC_ZEAL
|
||||||
|
case 'Z':
|
||||||
|
if (++i == argc)
|
||||||
|
return usage();
|
||||||
|
JS_SetGCZeal(cx, atoi(argv[i]));
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
reportWarnings = JS_TRUE;
|
reportWarnings = JS_TRUE;
|
||||||
break;
|
break;
|
||||||
@ -2531,6 +2547,9 @@ static JSFunctionSpec shell_functions[] = {
|
|||||||
JS_FS("stopShark", js_StopShark, 0,0,0),
|
JS_FS("stopShark", js_StopShark, 0,0,0),
|
||||||
JS_FS("connectShark", js_ConnectShark, 0,0,0),
|
JS_FS("connectShark", js_ConnectShark, 0,0,0),
|
||||||
JS_FS("disconnectShark", js_DisconnectShark, 0,0,0),
|
JS_FS("disconnectShark", js_DisconnectShark, 0,0,0),
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG_ARRAYS
|
||||||
|
JS_FS("arrayInfo", js_ArrayInfo, 1,0,0),
|
||||||
#endif
|
#endif
|
||||||
JS_FS_END
|
JS_FS_END
|
||||||
};
|
};
|
||||||
@ -2602,6 +2621,9 @@ static const char *const shell_help_messages[] = {
|
|||||||
" The -k switch does this automatically.",
|
" The -k switch does this automatically.",
|
||||||
"disconnectShark() Disconnect from Shark.",
|
"disconnectShark() Disconnect from Shark.",
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef DEBUG_ARRAYS
|
||||||
|
"arrayInfo(a1, a2, ...) Report statistics about arrays.",
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Help messages must match shell functions. */
|
/* Help messages must match shell functions. */
|
||||||
|
@ -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_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_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_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")
|
||||||
|
@ -3665,7 +3665,7 @@ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
|
|||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsArrayObject(JSContext *cx, JSObject *obj)
|
JS_IsArrayObject(JSContext *cx, JSObject *obj)
|
||||||
{
|
{
|
||||||
return OBJ_GET_CLASS(cx, obj) == &js_ArrayClass;
|
return OBJ_IS_ARRAY(cx, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
949
js/src/jsarray.c
949
js/src/jsarray.c
File diff suppressed because it is too large
Load Diff
@ -53,7 +53,11 @@ JS_BEGIN_EXTERN_C
|
|||||||
extern JSBool
|
extern JSBool
|
||||||
js_IdIsIndex(jsval id, jsuint *indexp);
|
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 *
|
extern JSObject *
|
||||||
js_InitArrayClass(JSContext *cx, JSObject *obj);
|
js_InitArrayClass(JSContext *cx, JSObject *obj);
|
||||||
@ -61,7 +65,13 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
|
|||||||
extern JSObject *
|
extern JSObject *
|
||||||
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector);
|
js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector);
|
||||||
|
|
||||||
#define JSSLOT_ARRAY_LENGTH JSSLOT_PRIVATE
|
/* 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
|
extern JSBool
|
||||||
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
|
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,
|
js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp,
|
||||||
void *arg, void *tmp);
|
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
|
JS_END_EXTERN_C
|
||||||
|
|
||||||
#endif /* jsarray_h___ */
|
#endif /* jsarray_h___ */
|
||||||
|
@ -4125,14 +4125,23 @@ interrupt:
|
|||||||
str = JSVAL_TO_STRING(lval);
|
str = JSVAL_TO_STRING(lval);
|
||||||
rval = INT_TO_JSVAL(JSSTRING_LENGTH(str));
|
rval = INT_TO_JSVAL(JSSTRING_LENGTH(str));
|
||||||
} else if (!JSVAL_IS_PRIMITIVE(lval) &&
|
} else if (!JSVAL_IS_PRIMITIVE(lval) &&
|
||||||
(obj = JSVAL_TO_OBJECT(lval),
|
(obj = JSVAL_TO_OBJECT(lval), OBJ_IS_ARRAY(cx, obj))) {
|
||||||
OBJ_GET_CLASS(cx, obj) == &js_ArrayClass)) {
|
|
||||||
|
jsuint length;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We know that the array is created with only its 'length'
|
* We know that the array is created with only its 'length'
|
||||||
* private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
|
* private data in a fixed slot at JSSLOT_ARRAY_LENGTH. See
|
||||||
* also JSOP_ARRAYPUSH, far below.
|
* 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 {
|
} else {
|
||||||
i = -1;
|
i = -1;
|
||||||
len = JSOP_LENGTH_LENGTH;
|
len = JSOP_LENGTH_LENGTH;
|
||||||
@ -6544,10 +6553,7 @@ interrupt:
|
|||||||
* of the comprehension have added the only properties directly in
|
* of the comprehension have added the only properties directly in
|
||||||
* the array object.
|
* the array object.
|
||||||
*/
|
*/
|
||||||
lval = obj->fslots[JSSLOT_ARRAY_LENGTH];
|
i = obj->fslots[JSSLOT_ARRAY_LENGTH];
|
||||||
JS_ASSERT(JSVAL_IS_INT(lval));
|
|
||||||
i = JSVAL_TO_INT(lval);
|
|
||||||
SAVE_SP_AND_PC(fp);
|
|
||||||
if (i == ARRAY_INIT_LIMIT) {
|
if (i == ARRAY_INIT_LIMIT) {
|
||||||
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
|
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
|
||||||
JSMSG_ARRAY_INIT_TOO_BIG);
|
JSMSG_ARRAY_INIT_TOO_BIG);
|
||||||
|
@ -324,7 +324,7 @@ js_GetNativeIteratorFlags(JSContext *cx, JSObject *iterobj)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
|
* 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_FRIEND_API(JSBool)
|
||||||
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
|
js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp)
|
||||||
|
@ -4127,8 +4127,10 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
|
|||||||
rt = cx->runtime;
|
rt = cx->runtime;
|
||||||
clasp = OBJ_GET_CLASS(cx, obj);
|
clasp = OBJ_GET_CLASS(cx, obj);
|
||||||
enumerate = clasp->enumerate;
|
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);
|
return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp);
|
||||||
|
}
|
||||||
|
|
||||||
switch (enum_op) {
|
switch (enum_op) {
|
||||||
case JSENUMERATE_INIT:
|
case JSENUMERATE_INIT:
|
||||||
@ -4840,8 +4842,8 @@ js_DumpScopeMeters(JSRuntime *rt)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void
|
void
|
||||||
PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
||||||
{
|
{
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
uint32 slot;
|
uint32 slot;
|
||||||
@ -4852,14 +4854,18 @@ PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
|||||||
uint32 key;
|
uint32 key;
|
||||||
const char *slotname;
|
const char *slotname;
|
||||||
|
|
||||||
JS_ASSERT(trc->debugPrinter == PrintObjectSlotName);
|
JS_ASSERT(trc->debugPrinter == js_PrintObjectSlotName);
|
||||||
obj = (JSObject *)trc->debugPrintArg;
|
obj = (JSObject *)trc->debugPrintArg;
|
||||||
slot = (uint32)trc->debugPrintIndex;
|
slot = (uint32)trc->debugPrintIndex;
|
||||||
|
|
||||||
scope = OBJ_SCOPE(obj);
|
if (OBJ_IS_NATIVE(obj)) {
|
||||||
sprop = SCOPE_LAST_PROP(scope);
|
scope = OBJ_SCOPE(obj);
|
||||||
while (sprop && sprop->slot != slot)
|
sprop = SCOPE_LAST_PROP(scope);
|
||||||
sprop = sprop->parent;
|
while (sprop && sprop->slot != slot)
|
||||||
|
sprop = sprop->parent;
|
||||||
|
} else {
|
||||||
|
sprop = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sprop) {
|
if (!sprop) {
|
||||||
switch (slot) {
|
switch (slot) {
|
||||||
@ -5001,7 +5007,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
|
|||||||
for (i = 0; i != nslots; ++i) {
|
for (i = 0; i != nslots; ++i) {
|
||||||
v = STOBJ_GET_SLOT(obj, i);
|
v = STOBJ_GET_SLOT(obj, i);
|
||||||
if (JSVAL_IS_TRACEABLE(v)) {
|
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));
|
JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,6 +666,9 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp);
|
|||||||
extern void
|
extern void
|
||||||
js_TraceObject(JSTracer *trc, JSObject *obj);
|
js_TraceObject(JSTracer *trc, JSObject *obj);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
js_Clear(JSContext *cx, JSObject *obj);
|
js_Clear(JSContext *cx, JSObject *obj);
|
||||||
|
|
||||||
|
@ -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,
|
* matches, an index property telling the length of the left context,
|
||||||
* and an input property referring to the input string.
|
* and an input property referring to the input string.
|
||||||
*/
|
*/
|
||||||
obj = js_NewArrayObject(cx, 0, NULL);
|
obj = js_NewSlowArrayObject(cx);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
ok = JS_FALSE;
|
ok = JS_FALSE;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1221,13 +1221,12 @@ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
|
|||||||
* We may have set slot from a nearly-matching sprop, above.
|
* We may have set slot from a nearly-matching sprop, above.
|
||||||
* If so, we're overwriting that nearly-matching sprop, so we
|
* If so, we're overwriting that nearly-matching sprop, so we
|
||||||
* can reuse its slot -- we don't need to allocate a new one.
|
* can reuse its slot -- we don't need to allocate a new one.
|
||||||
* Callers should therefore pass SPROP_INVALID_SLOT for all
|
* Similarly, we use a specific slot if provided by the caller.
|
||||||
* non-alias, unshared property adds.
|
|
||||||
*/
|
*/
|
||||||
if (slot != SPROP_INVALID_SLOT)
|
if (slot == SPROP_INVALID_SLOT &&
|
||||||
JS_ASSERT(overwriting);
|
!js_AllocSlot(cx, scope->object, &slot)) {
|
||||||
else if (!js_AllocSlot(cx, scope->object, &slot))
|
|
||||||
goto fail_overwrite;
|
goto fail_overwrite;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +813,7 @@ str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Forcefully ignore the first (or any) argument and return toUpperCase(),
|
* 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) {
|
if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) {
|
||||||
NORMALIZE_THIS(cx, vp, str);
|
NORMALIZE_THIS(cx, vp, str);
|
||||||
@ -1270,7 +1270,8 @@ match_glob(JSContext *cx, jsint count, GlobData *data)
|
|||||||
if (!matchstr)
|
if (!matchstr)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
v = STRING_TO_JSVAL(matchstr);
|
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
|
static JSBool
|
||||||
@ -1803,7 +1804,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
|
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
v = STRING_TO_JSVAL(str);
|
v = STRING_TO_JSVAL(str);
|
||||||
ok = JS_SetElement(cx, arrayobj, 0, &v);
|
ok = OBJ_SET_PROPERTY(cx, arrayobj, INT_TO_JSID(0), &v);
|
||||||
} else {
|
} else {
|
||||||
if (JSVAL_IS_REGEXP(cx, vp[2])) {
|
if (JSVAL_IS_REGEXP(cx, vp[2])) {
|
||||||
re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));
|
re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2]));
|
||||||
|
Loading…
Reference in New Issue
Block a user