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);
|
return CallThisObjectHook(cx, thisp, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSObject *
|
JSObject *
|
||||||
ComputeThis(JSContext *cx, jsval *argv)
|
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;
|
JSObject *thisp;
|
||||||
|
|
||||||
JS_ASSERT(!JSVAL_IS_NULL(argv[-1]));
|
JS_ASSERT(!JSVAL_IS_NULL(argv[-1]));
|
||||||
@ -301,15 +305,6 @@ ComputeThis(JSContext *cx, jsval *argv)
|
|||||||
return CallThisObjectHook(cx, thisp, 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
|
#if JS_HAS_NO_SUCH_METHOD
|
||||||
|
|
||||||
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
|
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
|
||||||
@ -433,112 +428,13 @@ class AutoPreserveEnumerators {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static JS_REQUIRES_STACK bool
|
||||||
* Find a function reference and its 'this' object implicit first parameter
|
Invoke(JSContext *cx, JSFunction *fun, JSScript *script, JSNative native,
|
||||||
* under argc arguments on cx's stack, and call the function. Push missing
|
const InvokeArgsGuard &args, uintN flags)
|
||||||
* 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();
|
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()) {
|
if (native && fun && fun->isFastNative()) {
|
||||||
#ifdef DEBUG_NOT_THROWING
|
#ifdef DEBUG_NOT_THROWING
|
||||||
JSBool alreadyThrowing = cx->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);
|
cx->stack().pushInvokeFrame(cx, args, frame, regs);
|
||||||
|
|
||||||
/* Now that the frame has been pushed, fix up the scope chain. */
|
/* Now that the frame has been pushed, fix up the scope chain. */
|
||||||
|
JSObject *parent = JSVAL_TO_OBJECT(vp[0])->getParent();
|
||||||
if (native) {
|
if (native) {
|
||||||
/* Slow natives expect the caller's scopeChain as their scopeChain. */
|
/* Slow natives expect the caller's scopeChain as their scopeChain. */
|
||||||
if (JSStackFrame *down = fp->down)
|
if (JSStackFrame *down = fp->down)
|
||||||
@ -677,6 +574,110 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
|||||||
return ok;
|
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
|
JSBool
|
||||||
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
|
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
|
||||||
uintN argc, jsval *argv, jsval *rval)
|
uintN argc, jsval *argv, jsval *rval)
|
||||||
|
@ -5578,9 +5578,10 @@ GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval)
|
|||||||
JSBool
|
JSBool
|
||||||
js_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
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) {
|
if (!clasp->call) {
|
||||||
#ifdef NARCISSUS
|
#ifdef NARCISSUS
|
||||||
JSObject *callee, *args;
|
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]);
|
JSObject *proxy = JSVAL_TO_OBJECT(argv[-2]);
|
||||||
JS_ASSERT(proxy->isProxy());
|
JS_ASSERT(proxy->isProxy());
|
||||||
AutoPendingProxyOperation pending(cx, proxy);
|
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
|
JSBool
|
||||||
|
@ -5340,8 +5340,11 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||||||
static JSBool
|
static JSBool
|
||||||
regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||||
{
|
{
|
||||||
return regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv,
|
if (!cx->fp->getThisObject(cx))
|
||||||
JS_FALSE, rval);
|
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
|
#if JS_HAS_XDR
|
||||||
|
Loading…
Reference in New Issue
Block a user