зеркало из https://github.com/mozilla/pjs.git
Fix violation of function prototyping due to cloned function object implementation (300079, r=mrbkap; expecting r=igor after the fact, want to get this in for widespread testing tomorrow).
This commit is contained in:
Родитель
810be3dd6c
Коммит
b98558a7cd
|
@ -1267,11 +1267,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
|
|||
js_InitDateClass(cx, obj);
|
||||
}
|
||||
|
||||
#define ATOM_OFFSET(name) offsetof(JSAtomState,name##Atom)
|
||||
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
|
||||
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
|
||||
#define CLASP(name) (JSClass *)&js_##name##Class
|
||||
|
||||
#define CLASP(name) ((JSClass *)&js_##name##Class)
|
||||
#define EAGER_ATOM(name) ATOM_OFFSET(name), NULL
|
||||
#define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL
|
||||
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
|
||||
|
@ -1640,11 +1636,7 @@ JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj,
|
|||
return js_SetIdArrayLength(cx, ida, i);
|
||||
}
|
||||
|
||||
#undef ATOM_OFFSET
|
||||
#undef CLASS_ATOM_OFFSET
|
||||
#undef OFFSET_TO_ATOM
|
||||
#undef CLASP
|
||||
|
||||
#undef EAGER_ATOM
|
||||
#undef EAGER_CLASS_ATOM
|
||||
#undef EAGER_ATOM_CLASP
|
||||
|
|
|
@ -248,6 +248,10 @@ struct JSAtomState {
|
|||
#endif
|
||||
};
|
||||
|
||||
#define ATOM_OFFSET(name) offsetof(JSAtomState, name##Atom)
|
||||
#define OFFSET_TO_ATOM(rt,off) (*(JSAtom **)((char*)&(rt)->atomState + (off)))
|
||||
#define CLASS_ATOM_OFFSET(name) offsetof(JSAtomState,classAtoms[JSProto_##name])
|
||||
|
||||
#define CLASS_ATOM(cx,name) \
|
||||
((cx)->runtime->atomState.classAtoms[JSProto_##name])
|
||||
|
||||
|
|
116
js/src/jsfun.c
116
js/src/jsfun.c
|
@ -962,19 +962,32 @@ JSClass js_CallClass = {
|
|||
*
|
||||
* The extensions below other than length, i.e., the ones not in ECMA-262,
|
||||
* are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
|
||||
* with ECMA we must allow a delegating object to override them.
|
||||
* with ECMA we must allow a delegating object to override them. Therefore to
|
||||
* avoid entraining garbage in Function.prototype slots, they must be resolved
|
||||
* in non-prototype function objects, wherefore the lazy_function_props table
|
||||
* and fun_resolve's use of it.
|
||||
*/
|
||||
#define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
|
||||
|
||||
static JSPropertySpec function_props[] = {
|
||||
{js_arguments_str, CALL_ARGUMENTS, JSPROP_PERMANENT, 0,0},
|
||||
{js_arity_str, FUN_ARITY, JSPROP_PERMANENT, 0,0},
|
||||
{js_caller_str, FUN_CALLER, JSPROP_PERMANENT, 0,0},
|
||||
{js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0},
|
||||
{js_name_str, FUN_NAME, JSPROP_PERMANENT, 0,0},
|
||||
{0,0,0,0,0}
|
||||
};
|
||||
|
||||
typedef struct LazyFunctionProp {
|
||||
uint16 atomOffset;
|
||||
int8 tinyid;
|
||||
uint8 attrs;
|
||||
} LazyFunctionProp;
|
||||
|
||||
/* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
|
||||
static LazyFunctionProp lazy_function_props[] = {
|
||||
{ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT},
|
||||
{ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT},
|
||||
{ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT},
|
||||
{ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT},
|
||||
};
|
||||
|
||||
static JSBool
|
||||
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
{
|
||||
|
@ -1094,46 +1107,71 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
JSObject **objp)
|
||||
{
|
||||
JSFunction *fun;
|
||||
JSString *str;
|
||||
JSAtom *prototypeAtom;
|
||||
|
||||
/*
|
||||
* No need to reflect fun.prototype in 'fun.prototype = ...' or in an
|
||||
* unqualified reference to prototype, which the emitter looks up as a
|
||||
* hidden atom when attempting to bind to a formal parameter or local
|
||||
* variable slot.
|
||||
*/
|
||||
if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_HIDDEN))
|
||||
return JS_TRUE;
|
||||
JSAtom *atom;
|
||||
uintN i;
|
||||
|
||||
if (!JSVAL_IS_STRING(id))
|
||||
return JS_TRUE;
|
||||
|
||||
/* No valid function object should lack private data, but check anyway. */
|
||||
/* No valid function object should lack private data. */
|
||||
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
|
||||
if (!fun || !fun->object)
|
||||
JS_ASSERT(fun && fun->object);
|
||||
|
||||
/*
|
||||
* Check for a hidden formal parameter or local variable binding in the
|
||||
* clone-parent of obj, which would be a different, non-null fun->object.
|
||||
*/
|
||||
if (flags & JSRESOLVE_HIDDEN) {
|
||||
if (fun->object != obj) {
|
||||
JSObject *pobj;
|
||||
JSProperty *prop;
|
||||
|
||||
atom = js_AtomizeString(cx, JSVAL_TO_STRING(id), 0);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
if (!js_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom),
|
||||
&pobj, &prop)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (prop) {
|
||||
JS_ASSERT(pobj == fun->object);
|
||||
*objp = pobj;
|
||||
OBJ_DROP_PROPERTY(cx, pobj, prop);
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* No need to reflect fun.prototype in 'fun.prototype = ...'. This test
|
||||
* must come after the JSRESOLVE_HIDDEN test, since call_resolve may look
|
||||
* for a hidden function object property from an assignment bytecode.
|
||||
*/
|
||||
if (flags & JSRESOLVE_ASSIGNING)
|
||||
return JS_TRUE;
|
||||
|
||||
/*
|
||||
* Ok, check whether id is 'prototype' and bootstrap the function object's
|
||||
* prototype property.
|
||||
*/
|
||||
str = JSVAL_TO_STRING(id);
|
||||
prototypeAtom = cx->runtime->atomState.classPrototypeAtom;
|
||||
if (str == ATOM_TO_STRING(prototypeAtom)) {
|
||||
atom = cx->runtime->atomState.classPrototypeAtom;
|
||||
if (id == ATOM_KEY(atom)) {
|
||||
JSObject *proto, *parentProto;
|
||||
jsval pval;
|
||||
|
||||
proto = parentProto = NULL;
|
||||
if (fun->object != obj && fun->object) {
|
||||
if (fun->object != obj &&
|
||||
(!cx->runtime->findObjectPrincipals ||
|
||||
cx->runtime->findObjectPrincipals(cx, obj) ==
|
||||
cx->runtime->findObjectPrincipals(cx, fun->object))) {
|
||||
/*
|
||||
* Clone of a function: make its prototype property value have the
|
||||
* same class as the clone-parent's prototype.
|
||||
* Clone of a function where the clone and the object owning fun
|
||||
* appear to be in the same trust domain: make the cloned function
|
||||
* object's 'prototype' property value have the same class as the
|
||||
* clone-parent's 'prototype' value.
|
||||
*/
|
||||
if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(prototypeAtom),
|
||||
&pval)) {
|
||||
if (!OBJ_GET_PROPERTY(cx, fun->object, ATOM_TO_JSID(atom), &pval))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(pval)) {
|
||||
/*
|
||||
* We are about to allocate a new object, so hack the newborn
|
||||
|
@ -1175,6 +1213,24 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
|||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
|
||||
LazyFunctionProp *lfp = &lazy_function_props[i];
|
||||
|
||||
atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
|
||||
if (id == ATOM_KEY(atom)) {
|
||||
if (!js_DefineNativeProperty(cx, obj,
|
||||
ATOM_TO_JSID(atom), JSVAL_VOID,
|
||||
NULL, NULL, lfp->attrs,
|
||||
SPROP_HAS_SHORTID, lfp->tinyid,
|
||||
NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
*objp = obj;
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
|
@ -1457,8 +1513,10 @@ fun_trace(JSTracer *trc, JSObject *obj)
|
|||
fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
|
||||
if (fun) {
|
||||
JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private");
|
||||
if (fun->object != obj)
|
||||
JS_CALL_TRACER(trc, fun->object, JSTRACE_OBJECT, "object");
|
||||
if (fun->atom)
|
||||
JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "name");
|
||||
JS_CALL_TRACER(trc, fun->atom, JSTRACE_ATOM, "atom");
|
||||
if (FUN_INTERPRETED(fun) && fun->u.i.script)
|
||||
js_TraceScript(trc, fun->u.i.script);
|
||||
}
|
||||
|
@ -2170,7 +2228,7 @@ js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
|||
JSFunction *fun;
|
||||
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
|
||||
newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
|
||||
newfunobj = js_NewObject(cx, &js_FunctionClass, NULL, parent);
|
||||
if (!newfunobj)
|
||||
return NULL;
|
||||
fun = (JSFunction *) JS_GetPrivate(cx, funobj);
|
||||
|
|
Загрузка…
Ссылка в новой задаче