Bug 1259877 - Add CallFromStack for certain internal users, js::Call for general use, and mark js::Invoke as deprecated. r=efaust

--HG--
extra : rebase_source : 4e2d82e18da373cc7ab7ba30e86af2f777665794
This commit is contained in:
Jeff Walden 2016-03-21 15:51:13 -07:00
Родитель 525e0715b0
Коммит 20b04cbd46
2 изменённых файлов: 87 добавлений и 47 удалений

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

@ -501,24 +501,17 @@ js::InternalCallOrConstruct(JSContext* cx, const CallArgs& args, MaybeConstruct
return ok;
}
bool
js::Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc, const Value* argv,
MutableHandleValue rval)
static bool
InternalCall(JSContext* cx, const AnyInvokeArgs& args)
{
InvokeArgs args(cx);
if (!args.init(argc))
return false;
args.setCallee(fval);
args.setThis(thisv);
PodCopy(args.array(), argv, argc);
MOZ_ASSERT(args.array() + args.length() == args.end(),
"must pass calling arguments to a calling attempt");
if (args.thisv().isObject()) {
/*
* We must call the thisValue hook in case we are not called from the
* interpreter, where a prior bytecode has computed an appropriate
* |this| already. But don't do that if fval is a DOM function.
*/
// We must call the thisValue hook in case we are not called from the
// interpreter, where a prior bytecode has computed an appropriate
// |this| already. But don't do that if fval is a DOM function.
HandleValue fval = args.calleev();
if (!fval.isObject() || !fval.toObject().is<JSFunction>() ||
!fval.toObject().as<JSFunction>().isNative() ||
!fval.toObject().as<JSFunction>().jitInfo() ||
@ -529,13 +522,50 @@ js::Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc,
}
}
if (!InternalCallOrConstruct(cx, args, NO_CONSTRUCT))
return InternalCallOrConstruct(cx, args, NO_CONSTRUCT);
}
static bool
CallFromStack(JSContext* cx, const CallArgs& args)
{
return InternalCall(cx, static_cast<const AnyInvokeArgs&>(args));
}
// ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.12 Call.
bool
js::Call(JSContext* cx, HandleValue fval, HandleValue thisv, const AnyInvokeArgs& args,
MutableHandleValue rval)
{
// Explicitly qualify these methods to bypass AnyInvokeArgs's deliberate
// shadowing.
args.CallArgs::setCallee(fval);
args.CallArgs::setThis(thisv);
if (!InternalCall(cx, args))
return false;
rval.set(args.rval());
return true;
}
// DEPRECATED. TO BE REMOVED. DO NOT ADD NEW USES.
bool
js::Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc, const Value* argv,
MutableHandleValue rval)
{
RootedValue fv(cx, fval);
RootedValue tv(cx, thisv);
InvokeArgs args(cx);
if (!args.init(argc))
return false;
for (unsigned i = 0; i < argc; i++)
args[i].set(argv[i]);
return Call(cx, fv, tv, args, rval);
}
static bool
InternalConstruct(JSContext* cx, const AnyConstructArgs& args)
{
@ -639,7 +669,9 @@ js::CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter, MutableHand
// bug 355497.
JS_CHECK_RECURSION(cx, return false);
return Invoke(cx, thisv, getter, 0, nullptr, rval);
FixedInvokeArgs<0> args(cx);
return Call(cx, getter, thisv, args, rval);
}
bool
@ -647,8 +679,12 @@ js::CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter, HandleValue
{
JS_CHECK_RECURSION(cx, return false);
FixedInvokeArgs<1> args(cx);
args[0].set(v);
RootedValue ignored(cx);
return Invoke(cx, thisv, setter, 1, v.address(), &ignored);
return Call(cx, setter, thisv, args, &ignored);
}
bool
@ -2728,7 +2764,7 @@ CASE(JSOP_STRICTEVAL)
if (!DirectEval(cx, args.get(0), args.rval()))
goto error;
} else {
if (!InternalInvoke(cx, args))
if (!CallFromStack(cx, args))
goto error;
}
@ -2810,7 +2846,7 @@ CASE(JSOP_FUNCALL)
ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, args.thisv(), nullptr);
goto error;
}
if (!InternalInvoke(cx, args))
if (!CallFromStack(cx, args))
goto error;
}
Value* newsp = args.spAfterCall();
@ -4616,35 +4652,25 @@ js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, Hand
res.setObject(*obj);
} else {
InvokeArgs args(cx);
if (!args.init(length))
return false;
args.setCallee(callee);
args.setThis(thisv);
if (!GetElements(cx, aobj, length, args.array()))
return false;
switch (op) {
case JSOP_SPREADCALL:
if (!Invoke(cx, args))
if ((op == JSOP_SPREADEVAL || op == JSOP_STRICTSPREADEVAL) &&
cx->global()->valueIsEval(callee))
{
if (!DirectEval(cx, args.get(0), res))
return false;
} else {
MOZ_ASSERT(op == JSOP_SPREADCALL ||
op == JSOP_SPREADEVAL ||
op == JSOP_STRICTSPREADEVAL,
"bad spread opcode");
if (!Call(cx, callee, thisv, args, res))
return false;
res.set(args.rval());
break;
case JSOP_SPREADEVAL:
case JSOP_STRICTSPREADEVAL:
if (cx->global()->valueIsEval(callee)) {
if (!DirectEval(cx, args.get(0), res))
return false;
} else {
if (!Invoke(cx, args))
return false;
res.set(args.rval());
}
break;
default:
MOZ_CRASH("bad spread opcode");
}
}

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

@ -83,11 +83,7 @@ InternalInvoke(JSContext* cx, const CallArgs& args)
return InternalCallOrConstruct(cx, args, NO_CONSTRUCT);
}
/*
* Attempt to call a value with the provided |this| and arguments. This
* function places no requirements on the caller: it may be called at any time,
* and it takes care of copying |fval|, |thisv|, and arguments onto the stack.
*/
// DEPRECATED. TO BE REMOVED. DO NOT ADD NEW USES.
extern bool
Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc, const Value* argv,
MutableHandleValue rval);
@ -102,9 +98,24 @@ CallGetter(JSContext* cx, HandleValue thisv, HandleValue getter, MutableHandleVa
extern bool
CallSetter(JSContext* cx, HandleValue thisv, HandleValue setter, HandleValue rval);
// ES7 rev 0c1bd3004329336774cbc90de727cd0cf5f11e93 7.3.12 Call(F, V, argumentsList).
// All parameters are required, hopefully forcing callers to be careful not to
// (say) blindly pass callee as |newTarget| when a different value should have
// been passed. Behavior is unspecified if any element of |args| isn't initialized.
//
// |rval| is written to *only* after |fval| and |thisv| have been consumed, so
// |rval| *may* alias either argument.
extern bool
Call(JSContext* cx, HandleValue fval, HandleValue thisv, const AnyInvokeArgs& args,
MutableHandleValue rval);
// ES6 7.3.13 Construct(F, argumentsList, newTarget). All parameters are
// required, hopefully forcing callers to be careful not to (say) blindly pass
// callee as |newTarget| when a different value should have been passed.
// Behavior is unspecified if any element of |args| isn't initialized.
//
// |rval| is written to *only* after |fval| and |newTarget| have been consumed,
// so |rval| *may* alias either argument.
//
// NOTE: As with the ES6 spec operation, it's the caller's responsibility to
// ensure |fval| and |newTarget| are both |IsConstructor|.
@ -127,6 +138,9 @@ ConstructFromStack(JSContext* cx, const CallArgs& args);
// Call Construct(fval, args, newTarget), but use the given |thisv| as |this|
// during construction of |fval|.
//
// |rval| is written to *only* after |fval|, |thisv|, and |newTarget| have been
// consumed, so |rval| *may* alias any of these arguments.
//
// This method exists only for very rare cases where a |this| was created
// caller-side for construction of |fval|: basically only for JITs using
// |CreateThis|. If that's not you, use Construct()!