Eliminate Closure per ECMA ed. 3, fix brutal sharing of lambdas (20076, r=rogerl,shaver).
git-svn-id: svn://10.0.0.236/trunk@54474 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
30da73de36
commit
ca2032e66d
@ -974,7 +974,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj)
|
||||
|
||||
/* Initialize the rest of the standard objects and functions. */
|
||||
return (array_proto = js_InitArrayClass(cx, obj)) != NULL &&
|
||||
js_InitArgsCallClosureClasses(cx, obj, obj_proto) &&
|
||||
js_InitArgsAndCallClasses(cx, obj, obj_proto) &&
|
||||
js_InitBooleanClass(cx, obj) &&
|
||||
js_InitMathClass(cx, obj) &&
|
||||
js_InitNumberClass(cx, obj) &&
|
||||
@ -2194,7 +2194,6 @@ JS_PUBLIC_API(JSObject *)
|
||||
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
||||
{
|
||||
JSFunction *fun;
|
||||
JSObject *newfunobj;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
if (OBJ_GET_CLASS(cx, funobj) != &js_FunctionClass) {
|
||||
@ -2202,16 +2201,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
||||
return funobj;
|
||||
}
|
||||
fun = JS_GetPrivate(cx, funobj);
|
||||
|
||||
newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
|
||||
if (!newfunobj)
|
||||
return NULL;
|
||||
if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return newfunobj;
|
||||
return js_CloneFunctionObject(cx, funobj, parent);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
|
||||
@ -577,100 +577,6 @@ JSClass js_CallClass = {
|
||||
|
||||
#endif /* JS_HAS_CALL_OBJECT */
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
static JSBool
|
||||
Closure(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSStackFrame *caller;
|
||||
JSObject *varParent, *closureParent;
|
||||
JSFunction *fun;
|
||||
|
||||
if (!cx->fp->constructing) {
|
||||
obj = js_NewObject(cx, &js_ClosureClass, NULL, NULL);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
if (!(caller = cx->fp->down) || !caller->scopeChain)
|
||||
return JS_TRUE;
|
||||
|
||||
varParent = js_FindVariableScope(cx, &fun);
|
||||
if (!varParent)
|
||||
return JS_FALSE;
|
||||
|
||||
closureParent = caller->scopeChain;
|
||||
if (argc != 0) {
|
||||
fun = js_ValueToFunction(cx, &argv[0], JS_FALSE);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
OBJ_SET_PROTO(cx, obj, fun->object);
|
||||
if (argc > 1) {
|
||||
if (!js_ValueToObject(cx, argv[1], &closureParent))
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
OBJ_SET_PARENT(cx, obj, closureParent);
|
||||
|
||||
/* Make sure constructor is not inherited from fun->object. */
|
||||
return js_DefineProperty(cx, obj,
|
||||
(jsid)cx->runtime->atomState.constructorAtom,
|
||||
argv[-2], NULL, NULL,
|
||||
JSPROP_READONLY | JSPROP_PERMANENT,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
closure_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
JSObject *proto;
|
||||
|
||||
if (type == JSTYPE_FUNCTION) {
|
||||
proto = OBJ_GET_PROTO(cx, obj);
|
||||
if (proto)
|
||||
*vp = OBJECT_TO_JSVAL(proto);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
return js_TryValueOf(cx, obj, type, vp);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
closure_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
JSObject *closure, *callobj;
|
||||
JSFunction *fun;
|
||||
jsval junk;
|
||||
|
||||
/* Get a call object to link the closure's parent into the scope chain. */
|
||||
fp = cx->fp;
|
||||
closure = JSVAL_TO_OBJECT(argv[-2]);
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, closure) == &js_ClosureClass);
|
||||
callobj = js_GetCallObject(cx, fp, OBJ_GET_PARENT(cx, closure), NULL);
|
||||
if (!callobj)
|
||||
return JS_FALSE;
|
||||
fp->scopeChain = callobj;
|
||||
|
||||
/* Make the function object, not its closure, available as argv[-2]. */
|
||||
fun = fp->fun;
|
||||
argv[-2] = OBJECT_TO_JSVAL(fun->object);
|
||||
if (fun->call)
|
||||
return fun->call(cx, obj, argc, argv, rval);
|
||||
if (fun->script)
|
||||
return js_Interpret(cx, &junk);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSClass js_ClosureClass = {
|
||||
"Closure",
|
||||
0,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, closure_convert, JS_FinalizeStub,
|
||||
NULL, NULL, closure_call, closure_call,
|
||||
NULL,NULL,{0,0}
|
||||
};
|
||||
#endif /* JS_HAS_LEXICAL_CLOSURE */
|
||||
|
||||
static JSPropertySpec function_props[] = {
|
||||
/*
|
||||
* We make fun.arguments readonly in fun_setProperty, unless it is being
|
||||
@ -1696,8 +1602,7 @@ bad:
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InitArgsCallClosureClasses(JSContext *cx, JSObject *obj,
|
||||
JSObject *objProto)
|
||||
js_InitArgsAndCallClasses(JSContext *cx, JSObject *obj, JSObject *objProto)
|
||||
{
|
||||
#if JS_HAS_ARGS_OBJECT
|
||||
if (!JS_InitClass(cx, obj, objProto, &js_ArgumentsClass, Arguments, 0,
|
||||
@ -1707,19 +1612,12 @@ js_InitArgsCallClosureClasses(JSContext *cx, JSObject *obj,
|
||||
#endif
|
||||
|
||||
#if JS_HAS_CALL_OBJECT
|
||||
if (!JS_InitClass(cx, obj, NULL, &js_CallClass, Call, 0,
|
||||
if (!JS_InitClass(cx, obj, objProto, &js_CallClass, Call, 0,
|
||||
call_props, NULL, NULL, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
if (!JS_InitClass(cx, obj, NULL, &js_ClosureClass, Closure, 0,
|
||||
NULL, NULL, NULL, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -1767,12 +1665,30 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative call, uintN nargs,
|
||||
return fun;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
||||
{
|
||||
JSObject *newfunobj;
|
||||
JSFunction *fun;
|
||||
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass);
|
||||
newfunobj = js_NewObject(cx, &js_FunctionClass, funobj, parent);
|
||||
if (!newfunobj)
|
||||
return NULL;
|
||||
fun = JS_GetPrivate(cx, funobj);
|
||||
if (!js_LinkFunctionObject(cx, fun, newfunobj)) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
return newfunobj;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object)
|
||||
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *funobj)
|
||||
{
|
||||
if (!fun->object)
|
||||
fun->object = object;
|
||||
if (!JS_SetPrivate(cx, object, fun))
|
||||
fun->object = funobj;
|
||||
if (!JS_SetPrivate(cx, funobj, fun))
|
||||
return JS_FALSE;
|
||||
JS_ATOMIC_ADDREF(&fun->nrefs, 1);
|
||||
return JS_TRUE;
|
||||
|
||||
@ -59,7 +59,7 @@ struct JSFunction {
|
||||
|
||||
extern JSClass js_ArgumentsClass;
|
||||
extern JSClass js_CallClass;
|
||||
extern JSClass js_ClosureClass;
|
||||
|
||||
/* JS_FRIEND_DATA so that JSVAL_IS_FUNCTION is callable from outside */
|
||||
extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
|
||||
|
||||
@ -77,13 +77,16 @@ extern JSObject *
|
||||
js_InitFunctionClass(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern JSBool
|
||||
js_InitArgsCallClosureClasses(JSContext *cx, JSObject *obj,
|
||||
js_InitArgsAndCallClasses(JSContext *cx, JSObject *obj,
|
||||
JSObject *objProto);
|
||||
|
||||
extern JSFunction *
|
||||
js_NewFunction(JSContext *cx, JSObject *funobj, JSNative call, uintN nargs,
|
||||
uintN flags, JSObject *parent, JSAtom *atom);
|
||||
|
||||
extern JSObject *
|
||||
js_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent);
|
||||
|
||||
extern JSBool
|
||||
js_LinkFunctionObject(JSContext *cx, JSFunction *fun, JSObject *object);
|
||||
|
||||
|
||||
@ -471,33 +471,25 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags)
|
||||
* We attempt the conversion under all circumstances for 1.2, but
|
||||
* only if there is a call op defined otherwise.
|
||||
*/
|
||||
if (cx->version == JSVERSION_1_2
|
||||
|| ((ops == &js_ObjectOps) ? clasp->call : ops->call)) {
|
||||
if (cx->version == JSVERSION_1_2 ||
|
||||
((ops == &js_ObjectOps) ? clasp->call : ops->call)) {
|
||||
ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
|
||||
if (!ok)
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_FUNCTION(cx, v)) {
|
||||
fun = NULL;
|
||||
script = NULL;
|
||||
minargs = nvars = 0;
|
||||
} else {
|
||||
if (JSVAL_IS_FUNCTION(cx, v)) {
|
||||
funobj = JSVAL_TO_OBJECT(v);
|
||||
parent = OBJ_GET_PARENT(cx, funobj);
|
||||
|
||||
fun = JS_GetPrivate(cx, funobj);
|
||||
if (clasp != &js_ClosureClass) {
|
||||
/* Make vp refer to funobj to keep it available as argv[-2]. */
|
||||
*vp = v;
|
||||
goto have_fun;
|
||||
}
|
||||
|
||||
/* Closure invocation may need extra arg and local var slots. */
|
||||
script = fun->script;
|
||||
minargs = fun->nargs + fun->extra;
|
||||
nvars = fun->nvars;
|
||||
/* Make vp refer to funobj to keep it available as argv[-2]. */
|
||||
*vp = v;
|
||||
goto have_fun;
|
||||
}
|
||||
fun = NULL;
|
||||
script = NULL;
|
||||
minargs = nvars = 0;
|
||||
|
||||
/* Try a call or construct native object op, using fun as fallback. */
|
||||
native = frame.constructing ? ops->construct : ops->call;
|
||||
@ -930,17 +922,11 @@ ImportProperty(JSContext *cx, JSObject *obj, jsid id)
|
||||
goto out;
|
||||
if (JSVAL_IS_FUNCTION(cx, value)) {
|
||||
funobj = JSVAL_TO_OBJECT(value);
|
||||
closure = js_ConstructObject(cx, &js_ClosureClass, funobj, obj);
|
||||
closure = js_CloneFunctionObject(cx, funobj, obj);
|
||||
if (!closure) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* The Closure() constructor resets the closure object's parent
|
||||
* to be the current scope chain. Set it to the object that the
|
||||
* imported function is being defined in.
|
||||
*/
|
||||
OBJ_SET_PARENT(cx, closure, obj);
|
||||
value = OBJECT_TO_JSVAL(closure);
|
||||
}
|
||||
|
||||
@ -1027,10 +1013,6 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
uintN off, npairs;
|
||||
JSBool match;
|
||||
#endif
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
JSFunction *fun2;
|
||||
JSObject *closure;
|
||||
#endif
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
JSPropertyOp getter, setter;
|
||||
#endif
|
||||
@ -1974,9 +1956,8 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
if (!JSVAL_IS_OBJECT(lval) ||
|
||||
(obj2 = JSVAL_TO_OBJECT(lval)) == NULL ||
|
||||
/* XXX clean up to avoid special cases above ObjectOps layer */
|
||||
(clasp = OBJ_GET_CLASS(cx, obj2),
|
||||
clasp == &js_FunctionClass || clasp == &js_ClosureClass) ||
|
||||
!obj2->map->ops->construct)
|
||||
OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
|
||||
!obj2->map->ops->construct)
|
||||
{
|
||||
fun = js_ValueToFunction(cx, vp, JS_TRUE);
|
||||
if (!fun) {
|
||||
@ -2440,30 +2421,30 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
* If the nearest variable scope is a function, not a call object,
|
||||
* replace it in the scope chain with its call object.
|
||||
*/
|
||||
obj = js_FindVariableScope(cx, &fun);
|
||||
if (!obj) {
|
||||
parent = js_FindVariableScope(cx, &fun);
|
||||
if (!parent) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Name the closure in the object at the head of the scope chain,
|
||||
* referenced by obj.
|
||||
* referenced by parent.
|
||||
*/
|
||||
if (fp->scopeChain != obj) {
|
||||
obj = fp->scopeChain;
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_WithClass);
|
||||
if (fp->scopeChain != parent) {
|
||||
parent = fp->scopeChain;
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, parent) == &js_WithClass);
|
||||
#if JS_BUG_WITH_CLOSURE
|
||||
/*
|
||||
* If in a with statement, set obj to the With object's
|
||||
* If in a with statement, set parent to the With object's
|
||||
* prototype, i.e., the object specified in the head of
|
||||
* the with statement.
|
||||
*/
|
||||
while (OBJ_GET_CLASS(cx, obj) == &js_WithClass) {
|
||||
proto = OBJ_GET_PROTO(cx, obj);
|
||||
while (OBJ_GET_CLASS(cx, parent) == &js_WithClass) {
|
||||
proto = OBJ_GET_PROTO(cx, parent);
|
||||
if (!proto)
|
||||
break;
|
||||
obj = proto;
|
||||
parent = proto;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -2473,46 +2454,45 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
* From it, get the function to close.
|
||||
*/
|
||||
atom = GET_ATOM(cx, script, pc);
|
||||
JS_ASSERT(ATOM_IS_OBJECT(atom));
|
||||
obj2 = ATOM_TO_OBJECT(atom);
|
||||
fun2 = JS_GetPrivate(cx, obj2);
|
||||
JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom)));
|
||||
obj = ATOM_TO_OBJECT(atom);
|
||||
fun = JS_GetPrivate(cx, obj);
|
||||
|
||||
/*
|
||||
* Let closure = new Closure(obj2).
|
||||
* NB: js_ConstructObject does not use the "constructor" property
|
||||
* of the new object it creates, because in this case and others
|
||||
* such as js_WithClass, that property refers to the prototype's
|
||||
* constructor function.
|
||||
* Clone the function object with the current scope chain as the
|
||||
* clone's parent. The original function object is the prototype
|
||||
* of the clone.
|
||||
*/
|
||||
SAVE_SP(fp);
|
||||
closure = js_ConstructObject(cx, &js_ClosureClass, obj2, obj);
|
||||
if (!closure) {
|
||||
obj = js_CloneFunctionObject(cx, obj, parent);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Define a property in obj with id fun2->atom and value closure,
|
||||
* but only if fun2 is not anonymous.
|
||||
* Define a property in parent with id fun->atom and value obj,
|
||||
* but only if fun is not anonymous.
|
||||
*/
|
||||
if (fun2->atom) {
|
||||
if (fun->atom) {
|
||||
SAVE_SP(fp);
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)fun2->atom,
|
||||
OBJECT_TO_JSVAL(closure),
|
||||
(fun2->flags & JSFUN_GETTER)
|
||||
? (JSPropertyOp) closure
|
||||
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
||||
rval = attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj);
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom, rval,
|
||||
(attrs & JSFUN_GETTER)
|
||||
? (JSPropertyOp) obj
|
||||
: NULL,
|
||||
(fun2->flags & JSFUN_SETTER)
|
||||
? (JSPropertyOp) closure
|
||||
(attrs & JSFUN_SETTER)
|
||||
? (JSPropertyOp) obj
|
||||
: NULL,
|
||||
fun2->flags | JSPROP_ENUMERATE,
|
||||
attrs | JSPROP_ENUMERATE,
|
||||
NULL);
|
||||
if (!ok) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(closure));
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
break;
|
||||
#endif /* JS_HAS_LEXICAL_CLOSURE */
|
||||
|
||||
@ -2675,16 +2655,11 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
* is not and will not be standardized.
|
||||
*/
|
||||
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
||||
obj = js_NewObject(cx, &js_FunctionClass, obj, parent);
|
||||
obj = js_CloneFunctionObject(cx, obj, parent);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
ok = js_LinkFunctionObject(cx, fun, obj);
|
||||
if (!ok) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
||||
@ -2715,6 +2690,91 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
#if JS_HAS_LEXICAL_CLOSURE
|
||||
case JSOP_ANONFUNOBJ:
|
||||
/* Push the specified function object literal. */
|
||||
parent = fp->scopeChain;
|
||||
JS_ASSERT(parent == js_FindVariableScope(cx, &fun));
|
||||
atom = GET_ATOM(cx, script, pc);
|
||||
obj = ATOM_TO_OBJECT(atom);
|
||||
|
||||
/* If re-parenting, push a clone of the function object. */
|
||||
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
||||
obj = js_CloneFunctionObject(cx, obj, parent);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
break;
|
||||
|
||||
case JSOP_NAMEDFUNOBJ:
|
||||
/* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
|
||||
atom = GET_ATOM(cx, script, pc);
|
||||
rval = ATOM_KEY(atom);
|
||||
JS_ASSERT(JSVAL_IS_FUNCTION(cx, rval));
|
||||
obj = JSVAL_TO_OBJECT(rval);
|
||||
fun = JS_GetPrivate(cx, obj);
|
||||
|
||||
/*
|
||||
* 1. Create a new object as if by the expression new Object().
|
||||
* 2. Add Result(1) to the front of the scope chain.
|
||||
*
|
||||
* Step 2 is achieved by making the new object's parent be the
|
||||
* current scope chain, and then making the new object the parent
|
||||
* of the Function object clone.
|
||||
*/
|
||||
parent = js_ConstructObject(cx, &js_ObjectClass, NULL,
|
||||
fp->scopeChain);
|
||||
if (!parent) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. Create a new Function object as specified in section 13.2
|
||||
* with [parameters and body specified by the function expression
|
||||
* that was parsed by the compiler into a Function object, and
|
||||
* saved in the script's atom map].
|
||||
*/
|
||||
obj = js_CloneFunctionObject(cx, obj, parent);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. Create a property in the object Result(1). The property's
|
||||
* name is [fun->atom, the identifier parsed by the compiler],
|
||||
* value is Result(3), and attributes are { DontDelete, ReadOnly }.
|
||||
*/
|
||||
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
|
||||
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
|
||||
(attrs & JSFUN_GETTER)
|
||||
? (JSPropertyOp) obj
|
||||
: NULL,
|
||||
(attrs & JSFUN_SETTER)
|
||||
? (JSPropertyOp) obj
|
||||
: NULL,
|
||||
attrs |
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT |
|
||||
JSPROP_READONLY,
|
||||
NULL);
|
||||
if (!ok) {
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* 5. Remove Result(1) from the front of the scope chain [no-op].
|
||||
* 6. Return Result(3).
|
||||
*/
|
||||
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
||||
break;
|
||||
#endif /* JS_HAS_LEXICAL_CLOSURE */
|
||||
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
case JSOP_GETTER:
|
||||
case JSOP_SETTER:
|
||||
|
||||
@ -1672,6 +1672,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
case JSOP_NUMBER:
|
||||
case JSOP_STRING:
|
||||
case JSOP_OBJECT:
|
||||
case JSOP_ANONFUNOBJ:
|
||||
case JSOP_NAMEDFUNOBJ:
|
||||
atom = GET_ATOM(cx, jp->script, pc);
|
||||
key = ATOM_KEY(atom);
|
||||
if (JSVAL_IS_INT(key)) {
|
||||
|
||||
@ -248,6 +248,12 @@ OPDEF(JSOP_SETTER, 124,js_setter_str,js_setter_str,1, 0, 0, 0, JOF_BYTE)
|
||||
/*
|
||||
* Prolog bytecodes for defining function, var, and const names.
|
||||
*/
|
||||
OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME|JOF_SET)
|
||||
OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_CONST|JOF_SET)
|
||||
OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME|JOF_SET)
|
||||
OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME)
|
||||
|
||||
/* Auto-clone (if needed due to re-parenting) and push an anonymous function. */
|
||||
OPDEF(JSOP_ANONFUNOBJ, 128, "anonfunobj", NULL, 3, 0, 1, 12, JOF_CONST)
|
||||
|
||||
/* ECMA ed. 3 named function expression. */
|
||||
OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 12, JOF_CONST)
|
||||
|
||||
@ -554,8 +554,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
*/
|
||||
if (outerFun || cx->fp->scopeChain != parent || InWithStatement(tc))
|
||||
pn->pn_op = JSOP_CLOSURE;
|
||||
else if (lambda)
|
||||
pn->pn_op = JSOP_OBJECT;
|
||||
else if (lambda || !fun->atom)
|
||||
pn->pn_op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
|
||||
else
|
||||
#endif
|
||||
pn->pn_op = JSOP_NOP;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user