[Bug 411575] SM: faster js_PutCallObject, r=brendan

This commit is contained in:
Igor Bukanov 2008-06-30 19:17:33 +02:00
Родитель 4f461a2d1f
Коммит 99ee0550d6
3 изменённых файлов: 119 добавлений и 72 удалений

Просмотреть файл

@ -583,6 +583,10 @@ JSClass js_ArgumentsClass = {
JS_CLASS_TRACE(args_or_call_trace), NULL
};
#define JSSLOT_SCRIPTED_FUNCTION (JSSLOT_PRIVATE + 1)
#define JSSLOT_CALL_ARGUMENTS (JSSLOT_PRIVATE + 2)
#define CALL_CLASS_FIXED_RESERVED_SLOTS 2
JSObject *
js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
{
@ -603,10 +607,12 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
/* Create the call object and link it to its stack frame. */
callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0);
if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
cx->weakRoots.newborn[GCX_OBJECT] = NULL;
if (!callobj)
return NULL;
}
JS_SetPrivate(cx, callobj, fp);
STOBJ_SET_SLOT(callobj, JSSLOT_SCRIPTED_FUNCTION,
OBJECT_TO_JSVAL(FUN_OBJECT(fp->fun)));
fp->callobj = callobj;
/* Make callobj be the scope chain and the variables object. */
@ -616,44 +622,78 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
return callobj;
}
static JSBool
call_enumerate(JSContext *cx, JSObject *obj);
JSFunction *
js_GetCallObjectFunction(JSObject *obj)
{
jsval v;
JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_CallClass);
v = STOBJ_GET_SLOT(obj, JSSLOT_SCRIPTED_FUNCTION);
if (JSVAL_IS_VOID(v)) {
/* Newborn or prototype object. */
return NULL;
}
JS_ASSERT(!JSVAL_IS_PRIMITIVE(v));
return (JSFunction *) JSVAL_TO_OBJECT(v);
}
JS_FRIEND_API(JSBool)
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
{
JSObject *callobj;
JSBool ok;
jsid argsid;
jsval aval;
JSFunction *fun;
uintN n;
JSScope *scope;
/*
* Reuse call_enumerate here to reflect all actual args and vars into the
* call object from fp.
* Since for a call object all fixed slots happen to be taken, we can copy
* arguments and variables straight into JSObject.dslots.
*/
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
1 + CALL_CLASS_FIXED_RESERVED_SLOTS);
callobj = fp->callobj;
if (!callobj)
return JS_TRUE;
ok = call_enumerate(cx, callobj);
/*
* Get the arguments object to snapshot fp's actual argument values.
*/
ok = JS_TRUE;
if (fp->argsobj) {
if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
argsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
aval = OBJECT_TO_JSVAL(fp->argsobj);
ok &= js_SetProperty(cx, callobj, argsid, &aval);
STOBJ_SET_SLOT(callobj, JSSLOT_CALL_ARGUMENTS,
OBJECT_TO_JSVAL(fp->argsobj));
}
ok &= js_PutArgsObject(cx, fp);
}
fun = fp->fun;
JS_ASSERT(fun == js_GetCallObjectFunction(callobj));
n = JS_GET_LOCAL_NAME_COUNT(fun);
if (n != 0) {
JS_LOCK_OBJ(cx, callobj);
n += JS_INITIAL_NSLOTS;
if (n > STOBJ_NSLOTS(callobj))
ok &= js_ReallocSlots(cx, callobj, n, JS_TRUE);
scope = OBJ_SCOPE(callobj);
if (ok) {
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
memcpy(callobj->dslots + fun->nargs, fp->vars,
fun->u.i.nvars * sizeof(jsval));
if (scope->object == callobj && n > scope->map.freeslot)
scope->map.freeslot = n;
}
JS_UNLOCK_SCOPE(cx, scope);
}
/*
* Clear the private pointer to fp, which is about to go away (js_Invoke).
* Do this last because the call_enumerate and js_GetProperty calls above
* need to follow the private slot to find fp.
* Do this last because js_GetProperty calls above need to follow the
* private slot to find fp.
*/
ok &= JS_SetPrivate(cx, callobj, NULL);
JS_SetPrivate(cx, callobj, NULL);
fp->callobj = NULL;
return ok;
}
@ -661,28 +701,16 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
static JSBool
call_enumerate(JSContext *cx, JSObject *obj)
{
JSStackFrame *fp;
JSFunction *fun;
uintN n, i, slot;
uintN n, i;
void *mark;
jsuword *names;
JSBool ok;
JSAtom *name;
JSObject *pobj;
JSProperty *prop;
jsval v;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
/*
* Reflect actual args from fp->argv for formal parameters, and local vars
* and functions in fp->vars for declared variables and nested-at-top-level
* local functions.
*/
fun = fp->fun;
fun = js_GetCallObjectFunction(obj);
n = JS_GET_LOCAL_NAME_COUNT(fun);
if (n == 0)
return JS_TRUE;
@ -715,11 +743,7 @@ call_enumerate(JSContext *cx, JSObject *obj)
* JSPROP_PERMANENT.
*/
JS_ASSERT(prop && pobj == obj);
slot = ((JSScopeProperty *) prop)->slot;
OBJ_DROP_PROPERTY(cx, pobj, prop);
v = (i < fun->nargs) ? fp->argv[i] : fp->vars[i - fun->nargs];
LOCKED_OBJ_SET_SLOT(obj, slot, v);
}
ok = JS_TRUE;
@ -738,36 +762,53 @@ static JSBool
CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
JSCallPropertyKind kind, JSBool setter)
{
JSStackFrame *fp;
JSFunction *fun;
JSStackFrame *fp;
uintN i;
jsval *array;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
if (STOBJ_GET_CLASS(obj) != &js_CallClass)
return JS_TRUE;
fun = fp->fun;
JS_ASSERT(fun && FUN_INTERPRETED(fun));
fun = js_GetCallObjectFunction(obj);
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (kind == JSCPK_ARGUMENTS) {
if (setter) {
SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS);
} else if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
JSObject *argsobj;
if (fp)
SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS);
STOBJ_SET_SLOT(obj, JSSLOT_CALL_ARGUMENTS, *vp);
} else {
if (fp && !TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
JSObject *argsobj;
argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(argsobj);
argsobj = js_GetArgsObject(cx, fp);
if (!argsobj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(argsobj);
} else {
*vp = STOBJ_GET_SLOT(obj, JSSLOT_CALL_ARGUMENTS);
}
}
return JS_TRUE;
}
}
JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id));
i = (uint16) JSVAL_TO_INT(id);
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
if (!fp) {
i += CALL_CLASS_FIXED_RESERVED_SLOTS;
if (kind == JSCPK_VAR)
i += fun->nargs;
else
JS_ASSERT(kind == JSCPK_ARG);
return setter
? JS_SetReservedSlot(cx, obj, i, *vp)
: JS_GetReservedSlot(cx, obj, i, vp);
}
JS_ASSERT(fun->u.i.nvars == fp->nvars);
if (kind == JSCPK_ARG) {
array = fp->argv;
@ -822,48 +863,39 @@ static JSBool
call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
JSObject **objp)
{
JSStackFrame *fp;
JSFunction *fun;
jsid id;
JSLocalKind localKind;
JSPropertyOp getter, setter;
uintN slot, attrs;
jsval *vp;
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (!fp)
return JS_TRUE;
fun = fp->fun;
JS_ASSERT(fun);
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fun);
if (!JSVAL_IS_STRING(idval))
return JS_TRUE;
fun = js_GetCallObjectFunction(obj);
if (!fun)
return JS_TRUE;
if (!js_ValueToStringId(cx, idval, &id))
return JS_FALSE;
localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
if (localKind != JSLOCAL_NONE) {
JS_ASSERT((uint16) slot == slot);
attrs = JSPROP_PERMANENT | JSPROP_SHARED;
if (localKind == JSLOCAL_ARG) {
JS_ASSERT(slot < fun->nargs);
vp = fp->argv;
getter = js_GetCallArg;
setter = SetCallArg;
attrs = JSPROP_PERMANENT;
} else {
JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
JS_ASSERT(fun->u.i.nvars == fp->nvars);
JS_ASSERT(slot < fun->u.i.nvars);
vp = fp->vars;
getter = js_GetCallVar;
setter = SetCallVar;
attrs = (localKind == JSLOCAL_CONST)
? JSPROP_PERMANENT | JSPROP_READONLY
: JSPROP_PERMANENT;
if (localKind == JSLOCAL_CONST)
attrs |= JSPROP_READONLY;
}
if (!js_DefineNativeProperty(cx, obj, id, vp[slot], getter, setter,
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter,
attrs, SPROP_HAS_SHORTID, (int16) slot,
NULL)) {
return JS_FALSE;
@ -879,7 +911,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
GetCallArguments, SetCallArguments,
JSPROP_PERMANENT, 0, 0, NULL)) {
JSPROP_PERMANENT | JSPROP_SHARED,
0, 0, NULL)) {
return JS_FALSE;
}
*objp = obj;
@ -903,9 +936,20 @@ call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
return JS_TRUE;
}
static uint32
call_reserveSlots(JSContext *cx, JSObject *obj)
{
JSFunction *fun;
fun = js_GetCallObjectFunction(obj);
return JS_GET_LOCAL_NAME_COUNT(fun);
}
JS_FRIEND_DATA(JSClass) js_CallClass = {
js_Call_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) |
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
@ -914,7 +958,7 @@ JS_FRIEND_DATA(JSClass) js_CallClass = {
NULL, NULL,
NULL, NULL,
NULL, NULL,
JS_CLASS_TRACE(args_or_call_trace), NULL,
JS_CLASS_TRACE(args_or_call_trace), call_reserveSlots
};
/*

Просмотреть файл

@ -1951,10 +1951,6 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
return clone;
}
static JSBool
js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
JSBool exactAllocation);
JSBool
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
{
@ -2304,7 +2300,7 @@ FreeSlots(JSContext *cx, JSObject *obj)
#define DYNAMIC_WORDS_TO_SLOTS(words) \
(JS_ASSERT((words) > 1), (words) - 1 + JS_INITIAL_NSLOTS)
static JSBool
JSBool
js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
JSBool exactAllocation)
{

Просмотреть файл

@ -689,6 +689,13 @@ js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
extern JSBool
js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v);
/*
* obj must be locked.
*/
extern JSBool
js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots,
JSBool exactAllocation);
extern JSObject *
js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller);