mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Compute 'this' in call ObjectOp so it can be overriden (572495, r=jorendorff).
This commit is contained in:
parent
2d3b5bbe7a
commit
02be8d79fb
@ -281,9 +281,13 @@ js_ComputeGlobalThis(JSContext *cx, jsval *argv)
|
||||
return CallThisObjectHook(cx, thisp, argv);
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
ComputeThis(JSContext *cx, jsval *argv)
|
||||
JSObject *
|
||||
js_ComputeThis(JSContext *cx, jsval *argv)
|
||||
{
|
||||
JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning
|
||||
if (JSVAL_IS_NULL(argv[-1]))
|
||||
return js_ComputeGlobalThis(cx, argv);
|
||||
|
||||
JSObject *thisp;
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_NULL(argv[-1]));
|
||||
@ -301,15 +305,6 @@ ComputeThis(JSContext *cx, jsval *argv)
|
||||
return CallThisObjectHook(cx, thisp, argv);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_ComputeThis(JSContext *cx, jsval *argv)
|
||||
{
|
||||
JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning
|
||||
if (JSVAL_IS_NULL(argv[-1]))
|
||||
return js_ComputeGlobalThis(cx, argv);
|
||||
return ComputeThis(cx, argv);
|
||||
}
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
|
||||
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
|
||||
@ -433,112 +428,13 @@ class AutoPreserveEnumerators {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Find a function reference and its 'this' object implicit first parameter
|
||||
* under argc arguments on cx's stack, and call the function. Push missing
|
||||
* required arguments, allocate declared local variables, and pop everything
|
||||
* when done. Then push the return value.
|
||||
*/
|
||||
JS_REQUIRES_STACK JS_FRIEND_API(JSBool)
|
||||
js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
static JS_REQUIRES_STACK bool
|
||||
Invoke(JSContext *cx, JSFunction *fun, JSScript *script, JSNative native,
|
||||
const InvokeArgsGuard &args, uintN flags)
|
||||
{
|
||||
jsval *vp = args.getvp();
|
||||
uintN argc = args.getArgc();
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
jsval *vp = args.getvp();
|
||||
|
||||
jsval v = vp[0];
|
||||
if (JSVAL_IS_PRIMITIVE(v)) {
|
||||
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *funobj = JSVAL_TO_OBJECT(v);
|
||||
JSObject *parent = funobj->getParent();
|
||||
JSClass *clasp = funobj->getClass();
|
||||
|
||||
/* Filled by the following if/else statement. */
|
||||
JSNative native;
|
||||
JSFunction *fun;
|
||||
JSScript *script;
|
||||
if (clasp != &js_FunctionClass) {
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (clasp == &js_NoSuchMethodClass)
|
||||
return NoSuchMethod(cx, argc, vp, flags);
|
||||
#endif
|
||||
|
||||
/* Function is inlined, all other classes use object ops. */
|
||||
const JSObjectOps *ops = funobj->map->ops;
|
||||
|
||||
fun = NULL;
|
||||
script = NULL;
|
||||
|
||||
/* Try a call or construct native object op. */
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
if (!JSVAL_IS_OBJECT(vp[1])) {
|
||||
if (!js_PrimitiveToObject(cx, &vp[1]))
|
||||
return false;
|
||||
}
|
||||
native = ops->construct;
|
||||
} else {
|
||||
native = ops->call;
|
||||
}
|
||||
if (!native) {
|
||||
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Get private data and set derived locals from it. */
|
||||
fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
native = NULL;
|
||||
script = fun->u.i.script;
|
||||
JS_ASSERT(script);
|
||||
|
||||
if (script->isEmpty()) {
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
*vp = vp[1];
|
||||
} else {
|
||||
*vp = JSVAL_VOID;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
native = fun->u.n.native;
|
||||
script = NULL;
|
||||
}
|
||||
|
||||
if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {
|
||||
/* Handle bound method special case. */
|
||||
vp[1] = OBJECT_TO_JSVAL(parent);
|
||||
} else if (!JSVAL_IS_OBJECT(vp[1])) {
|
||||
JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));
|
||||
if (PRIMITIVE_THIS_TEST(fun, vp[1]))
|
||||
goto start_call;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
} else {
|
||||
/*
|
||||
* We must call js_ComputeThis in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*
|
||||
* But we need to compute |this| eagerly only for so-called "slow"
|
||||
* (i.e., not fast) native functions. Fast natives must use either
|
||||
* JS_THIS or JS_THIS_OBJECT, and scripted functions will go through
|
||||
* the appropriate this-computing bytecode, e.g., JSOP_THIS.
|
||||
*/
|
||||
if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) {
|
||||
if (!js_ComputeThis(cx, vp + 2))
|
||||
return false;
|
||||
flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
}
|
||||
|
||||
start_call:
|
||||
if (native && fun && fun->isFastNative()) {
|
||||
#ifdef DEBUG_NOT_THROWING
|
||||
JSBool alreadyThrowing = cx->throwing;
|
||||
@ -620,6 +516,7 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
cx->stack().pushInvokeFrame(cx, args, frame, regs);
|
||||
|
||||
/* Now that the frame has been pushed, fix up the scope chain. */
|
||||
JSObject *parent = JSVAL_TO_OBJECT(vp[0])->getParent();
|
||||
if (native) {
|
||||
/* Slow natives expect the caller's scopeChain as their scopeChain. */
|
||||
if (JSStackFrame *down = fp->down)
|
||||
@ -677,6 +574,110 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a function reference and its 'this' object implicit first parameter
|
||||
* under argc arguments on cx's stack, and call the function. Push missing
|
||||
* required arguments, allocate declared local variables, and pop everything
|
||||
* when done. Then push the return value.
|
||||
*/
|
||||
JS_REQUIRES_STACK JS_FRIEND_API(JSBool)
|
||||
js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
||||
{
|
||||
jsval *vp = args.getvp();
|
||||
uintN argc = args.getArgc();
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
|
||||
jsval v = vp[0];
|
||||
if (JSVAL_IS_PRIMITIVE(v)) {
|
||||
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *funobj = JSVAL_TO_OBJECT(v);
|
||||
JSClass *clasp = funobj->getClass();
|
||||
|
||||
if (clasp == &js_FunctionClass) {
|
||||
/* Get private data and set derived locals from it. */
|
||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||
JSNative native;
|
||||
JSScript *script;
|
||||
if (FUN_INTERPRETED(fun)) {
|
||||
native = NULL;
|
||||
script = fun->u.i.script;
|
||||
JS_ASSERT(script);
|
||||
|
||||
if (script->isEmpty()) {
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]));
|
||||
*vp = vp[1];
|
||||
} else {
|
||||
*vp = JSVAL_VOID;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
native = fun->u.n.native;
|
||||
script = NULL;
|
||||
}
|
||||
|
||||
if (JSFUN_BOUND_METHOD_TEST(fun->flags)) {
|
||||
/* Handle bound method special case. */
|
||||
vp[1] = OBJECT_TO_JSVAL(funobj->getParent());
|
||||
} else if (!JSVAL_IS_OBJECT(vp[1])) {
|
||||
JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT));
|
||||
if (PRIMITIVE_THIS_TEST(fun, vp[1]))
|
||||
return Invoke(cx, fun, script, native, args, flags);
|
||||
}
|
||||
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(args.getvp()[1]));
|
||||
} else {
|
||||
/*
|
||||
* We must call js_ComputeThis in case we are not called from the
|
||||
* interpreter, where a prior bytecode has computed an appropriate
|
||||
* |this| already.
|
||||
*
|
||||
* But we need to compute |this| eagerly only for so-called "slow"
|
||||
* (i.e., not fast) native functions. Fast natives must use either
|
||||
* JS_THIS or JS_THIS_OBJECT, and scripted functions will go through
|
||||
* the appropriate this-computing bytecode, e.g., JSOP_THIS.
|
||||
*/
|
||||
if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) {
|
||||
jsval *vp = args.getvp();
|
||||
if (!js_ComputeThis(cx, vp + 2))
|
||||
return false;
|
||||
flags |= JSFRAME_COMPUTED_THIS;
|
||||
}
|
||||
}
|
||||
return Invoke(cx, fun, script, native, args, flags);
|
||||
}
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
if (clasp == &js_NoSuchMethodClass)
|
||||
return NoSuchMethod(cx, argc, vp, flags);
|
||||
#endif
|
||||
|
||||
/* Function is inlined, all other classes use object ops. */
|
||||
const JSObjectOps *ops = funobj->map->ops;
|
||||
|
||||
/* Try a call or construct native object op. */
|
||||
JSNative native;
|
||||
if (flags & JSINVOKE_CONSTRUCT) {
|
||||
if (!JSVAL_IS_OBJECT(vp[1])) {
|
||||
if (!js_PrimitiveToObject(cx, &vp[1]))
|
||||
return false;
|
||||
}
|
||||
native = ops->construct;
|
||||
} else {
|
||||
native = ops->call;
|
||||
}
|
||||
if (!native) {
|
||||
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS);
|
||||
return false;
|
||||
}
|
||||
return Invoke(cx, NULL, NULL, native, args, flags);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
|
@ -5578,9 +5578,10 @@ GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval)
|
||||
JSBool
|
||||
js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSClass *clasp;
|
||||
if (!cx->fp->getThisObject(cx))
|
||||
return false;
|
||||
|
||||
clasp = JSVAL_TO_OBJECT(argv[-2])->getClass();
|
||||
JSClass *clasp = JSVAL_TO_OBJECT(argv[-2])->getClass();
|
||||
if (!clasp->call) {
|
||||
#ifdef NARCISSUS
|
||||
JSObject *callee, *args;
|
||||
|
@ -933,7 +933,8 @@ proxy_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JSObject *proxy = JSVAL_TO_OBJECT(argv[-2]);
|
||||
JS_ASSERT(proxy->isProxy());
|
||||
AutoPendingProxyOperation pending(cx, proxy);
|
||||
return js_InternalCall(cx, obj, proxy->fslots[JSSLOT_PROXY_CALL], argc, argv, rval);
|
||||
return !!cx->fp->getThisObject(cx) &&
|
||||
js_InternalCall(cx, obj, proxy->fslots[JSSLOT_PROXY_CALL], argc, argv, rval);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -5340,8 +5340,11 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
static JSBool
|
||||
regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
return regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv,
|
||||
JS_FALSE, rval);
|
||||
if (!cx->fp->getThisObject(cx))
|
||||
return false;
|
||||
|
||||
return !!cx->fp->getThisObject(cx) &&
|
||||
regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, JS_FALSE, rval);
|
||||
}
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
Loading…
Reference in New Issue
Block a user