Bug 1303678. r=arai
authorJeff Walden <jwalden@mit.edu>
Fri, 30 Sep 2016 13:11:53 -0700
changeset 318106 b08857e08eb88c58d4ba92014c607ce54568bf57
parent 318105 83fd09630531e9f23124a53e4e17bc57b82894be
child 318107 7e451af5058d08984d8d5440177a757dd68a53b2
push id33211
push usercbook@mozilla.com
push dateMon, 17 Oct 2016 09:38:38 +0000
treeherderautoland@e4ef6fa03aa8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai
bugs1303678
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1303678. r=arai
js/src/asmjs/WasmInstance.cpp
js/src/builtin/Reflect.cpp
js/src/builtin/ReflectParse.cpp
js/src/jit/VMFunctions.cpp
js/src/js.msg
js/src/jsfun.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/vm/Debugger.cpp
js/src/vm/Interpreter.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Stack.h
--- a/js/src/asmjs/WasmInstance.cpp
+++ b/js/src/asmjs/WasmInstance.cpp
@@ -110,17 +110,17 @@ Instance::tableTls(const TableDesc& td) 
 
 bool
 Instance::callImport(JSContext* cx, uint32_t funcImportIndex, unsigned argc, const uint64_t* argv,
                      MutableHandleValue rval)
 {
     const FuncImport& fi = metadata().funcImports[funcImportIndex];
 
     InvokeArgs args(cx);
-    if (!args.init(argc))
+    if (!args.init(cx, argc))
         return false;
 
     bool hasI64Arg = false;
     MOZ_ASSERT(fi.sig().args().length() == argc);
     for (size_t i = 0; i < argc; i++) {
         switch (fi.sig().args()[i]) {
           case ValType::I32:
             args[i].set(Int32Value(*(int32_t*)&argv[i]));
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -34,21 +34,17 @@ InitArgsFromArrayLike(JSContext* cx, Han
         return false;
 
     // Steps 4-5.
     uint32_t len;
     if (!GetLengthProperty(cx, obj, &len))
         return false;
 
     // Allocate space for the arguments.
-    if (len > ARGS_LENGTH_MAX) {
-        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
-        return false;
-    }
-    if (!args->init(len))
+    if (!args->init(cx, len))
         return false;
 
     // Steps 6-8.
     for (uint32_t index = 0; index < len; index++) {
         if (!GetElement(cx, obj, obj, index, (*args)[index]))
             return false;
     }
 
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -333,17 +333,17 @@ class NodeBuilder
 
     // Invoke a user-defined callback. The actual signature is:
     //
     //     bool callback(HandleValue fun, HandleValue... args, TokenPos* pos,
     //                   MutableHandleValue dst);
     template <typename... Arguments>
     MOZ_MUST_USE bool callback(HandleValue fun, Arguments&&... args) {
         InvokeArgs iargs(cx);
-        if (!iargs.init(sizeof...(args) - 2 + size_t(saveLoc)))
+        if (!iargs.init(cx, sizeof...(args) - 2 + size_t(saveLoc)))
             return false;
 
         return callbackHelper(fun, iargs, 0, Forward<Arguments>(args)...);
     }
 
     // WARNING: Returning a Handle is non-standard, but it works in this case
     // because both |v| and |UndefinedHandleValue| are definitely rooted on a
     // previous stack frame (i.e. we're just choosing between two
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -66,17 +66,17 @@ InvokeFunction(JSContext* cx, HandleObje
     RootedValue fval(cx, ObjectValue(*obj));
     if (constructing) {
         if (!IsConstructor(fval)) {
             ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
             return false;
         }
 
         ConstructArgs cargs(cx);
-        if (!cargs.init(argc))
+        if (!cargs.init(cx, argc))
             return false;
 
         for (uint32_t i = 0; i < argc; i++)
             cargs[i].set(argvWithoutThis[i]);
 
         RootedValue newTarget(cx, argvWithoutThis[argc]);
 
         // If |this| hasn't been created, or is JS_UNINITIALIZED_LEXICAL,
@@ -97,17 +97,17 @@ InvokeFunction(JSContext* cx, HandleObje
         // Otherwise the default |this| has already been created.  We could
         // almost perform a *call* at this point, but we'd break |new.target|
         // in the function.  So in this one weird case we call a one-off
         // construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
         return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
     }
 
     InvokeArgs args(cx);
-    if (!args.init(argc))
+    if (!args.init(cx, argc))
         return false;
 
     for (size_t i = 0; i < argc; i++)
         args[i].set(argvWithoutThis[i]);
 
     return Call(cx, fval, thisv, args, rval);
 }
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -138,17 +138,17 @@ MSG_DEF(JSMSG_PRECISION_RANGE,         1
 // Function
 MSG_DEF(JSMSG_BAD_APPLY_ARGS,          1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array")
 MSG_DEF(JSMSG_BAD_FORMAL,              0, JSEXN_SYNTAXERR, "malformed formal parameter")
 MSG_DEF(JSMSG_CALLER_IS_STRICT,        0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
 MSG_DEF(JSMSG_DEPRECATED_USAGE,        1, JSEXN_REFERENCEERR, "deprecated {0} usage")
 MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION,   1, JSEXN_TYPEERR, "{0} is not a scripted function")
 MSG_DEF(JSMSG_NO_REST_NAME,            0, JSEXN_SYNTAXERR, "no parameter name after ...")
 MSG_DEF(JSMSG_PARAMETER_AFTER_REST,    0, JSEXN_SYNTAXERR, "parameter after rest parameter")
-MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
+MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS,      0, JSEXN_RANGEERR, "too many arguments provided for a function call")
 
 // CSP
 MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_ERR, "call to eval() blocked by CSP")
 MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,    0, JSEXN_ERR, "call to Function() blocked by CSP")
 
 // Wrappers
 MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED,     1, JSEXN_ERR, "Permission denied to define accessor property {0}")
 MSG_DEF(JSMSG_DEAD_OBJECT,             0, JSEXN_TYPEERR, "can't access dead object")
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1234,17 +1234,17 @@ js::fun_call(JSContext* cx, unsigned arg
         return false;
     }
 
     size_t argCount = args.length();
     if (argCount > 0)
         argCount--; // strip off provided |this|
 
     InvokeArgs iargs(cx);
-    if (!iargs.init(argCount))
+    if (!iargs.init(cx, argCount))
         return false;
 
     for (size_t i = 0; i < argCount; i++)
         iargs[i].set(args[i + 1]);
 
     return Call(cx, func, args.get(0), iargs, args.rval());
 }
 
@@ -1274,17 +1274,17 @@ js::fun_apply(JSContext* cx, unsigned ar
     // A JS_OPTIMIZED_ARGUMENTS magic value means that 'arguments' flows into
     // this apply call from a scripted caller and, as an optimization, we've
     // avoided creating it since apply can simply pull the argument values from
     // the calling frame (which we must do now).
     if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         // Step 3-6.
         ScriptFrameIter iter(cx);
         MOZ_ASSERT(iter.numActualArgs() <= ARGS_LENGTH_MAX);
-        if (!args2.init(iter.numActualArgs()))
+        if (!args2.init(cx, iter.numActualArgs()))
             return false;
 
         // Steps 7-8.
         iter.unaliasedForEachActual(cx, CopyTo(args2.array()));
     } else {
         // Step 3.
         if (!args[1].isObject()) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
@@ -1295,23 +1295,20 @@ js::fun_apply(JSContext* cx, unsigned ar
         // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
         // original version of ES5).
         RootedObject aobj(cx, &args[1].toObject());
         uint32_t length;
         if (!GetLengthProperty(cx, aobj, &length))
             return false;
 
         // Step 6.
-        if (length > ARGS_LENGTH_MAX) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
+        if (!args2.init(cx, length))
             return false;
-        }
 
-        if (!args2.init(length))
-            return false;
+        MOZ_ASSERT(length <= ARGS_LENGTH_MAX);
 
         // Steps 7-8.
         if (!GetElements(cx, aobj, length, args2.array()))
             return false;
     }
 
     // Step 9.
     return Call(cx, fval, args[0], args2, args.rval());
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -363,17 +363,17 @@ CrossCompartmentWrapper::nativeCall(JSCo
     RootedObject wrapper(cx, &srcArgs.thisv().toObject());
     MOZ_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) ||
                !UncheckedUnwrap(wrapper)->is<CrossCompartmentWrapperObject>());
 
     RootedObject wrapped(cx, wrappedObject(wrapper));
     {
         AutoCompartment call(cx, wrapped);
         InvokeArgs dstArgs(cx);
-        if (!dstArgs.init(srcArgs.length()))
+        if (!dstArgs.init(cx, srcArgs.length()))
             return false;
 
         Value* src = srcArgs.base();
         Value* srcend = srcArgs.array() + srcArgs.length();
         Value* dst = dstArgs.base();
 
         RootedValue source(cx);
         for (; src < srcend; ++src, ++dst) {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1697,17 +1697,17 @@ CallMethodIfPresent(JSContext* cx, Handl
     RootedValue fval(cx);
     if (!GetProperty(cx, obj, obj, id, &fval))
         return false;
 
     if (!IsCallable(fval))
         return true;
 
     InvokeArgs args(cx);
-    if (!args.init(argc))
+    if (!args.init(cx, argc))
         return false;
 
     for (size_t i = 0; i < argc; i++)
         args[i].set(argv[i]);
 
     rval.setObject(*obj); // overwritten by successful Call
     return js::Call(cx, fval, rval, args, rval);
 }
@@ -9949,17 +9949,17 @@ DebuggerObject::call(JSContext* cx, Hand
      * compartment and populate args.rval().
      */
     LeaveDebuggeeNoExecute nnx(cx);
 
     bool ok;
     {
         InvokeArgs invokeArgs(cx);
 
-        ok = invokeArgs.init(args2.length());
+        ok = invokeArgs.init(cx, args2.length());
         if (ok) {
             for (size_t i = 0; i < args2.length(); ++i)
                 invokeArgs[i].set(args2[i]);
 
             ok = js::Call(cx, calleev, thisv, invokeArgs, result);
         }
     }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4730,16 +4730,18 @@ bool
 js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, HandleValue thisv,
                         HandleValue callee, HandleValue arr, HandleValue newTarget, MutableHandleValue res)
 {
     RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
     uint32_t length = aobj->length();
     JSOp op = JSOp(*pc);
     bool constructing = op == JSOP_SPREADNEW || op == JSOP_SPREADSUPERCALL;
 
+    // {Construct,Invoke}Args::init does this too, but this gives us a better
+    // error message.
     if (length > ARGS_LENGTH_MAX) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                   constructing ? JSMSG_TOO_MANY_CON_SPREADARGS
                                                : JSMSG_TOO_MANY_FUN_SPREADARGS);
         return false;
     }
 
     // Do our own checks for the callee being a function, as Invoke uses the
@@ -4765,29 +4767,29 @@ js::SpreadCallOperation(JSContext* cx, H
         MOZ_ASSERT(!aobj->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE));
 #endif
 
     if (constructing) {
         if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget))
             return false;
 
         ConstructArgs cargs(cx);
-        if (!cargs.init(length))
+        if (!cargs.init(cx, length))
             return false;
 
         if (!GetElements(cx, aobj, length, cargs.array()))
             return false;
 
         RootedObject obj(cx);
         if (!Construct(cx, callee, cargs, newTarget, &obj))
             return false;
         res.setObject(*obj);
     } else {
         InvokeArgs args(cx);
-        if (!args.init(length))
+        if (!args.init(cx, length))
             return false;
 
         if (!GetElements(cx, aobj, length, args.array()))
             return false;
 
         if ((op == JSOP_SPREADEVAL || op == JSOP_STRICTSPREADEVAL) &&
             cx->global()->valueIsEval(callee))
         {
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -209,17 +209,17 @@ intrinsic_UnsafeCallWrappedFunction(JSCo
 
     MOZ_RELEASE_ASSERT(args[0].isObject());
     RootedObject wrappedFun(cx, &args[0].toObject());
     RootedObject fun(cx, UncheckedUnwrap(wrappedFun));
     MOZ_RELEASE_ASSERT(fun->is<JSFunction>());
     MOZ_RELEASE_ASSERT(fun->as<JSFunction>().isSelfHostedOrIntrinsic());
 
     InvokeArgs args2(cx);
-    if (!args2.init(args.length() - 2))
+    if (!args2.init(cx, args.length() - 2))
         return false;
 
     args2.setThis(args[1]);
 
     for (size_t i = 0; i < args2.length(); i++)
         args2[i].set(args[i + 2]);
 
     AutoWaivePolicy waivePolicy(cx, wrappedFun, JSID_VOIDHANDLE, BaseProxyHandler::CALL);
@@ -1710,17 +1710,17 @@ CallSelfHostedNonGenericMethod(JSContext
 
     RootedValue selfHostedFun(cx);
     if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &selfHostedFun))
         return false;
 
     MOZ_ASSERT(selfHostedFun.toObject().is<JSFunction>());
 
     InvokeArgs args2(cx);
-    if (!args2.init(args.length() - 1))
+    if (!args2.init(cx, args.length() - 1))
         return false;
 
     for (size_t i = 0; i < args.length() - 1; i++)
         args2[i].set(args[i]);
 
     return js::Call(cx, selfHostedFun, args.thisv(), args2, args.rval());
 }
 
@@ -1909,17 +1909,17 @@ intrinsic_ConstructFunction(JSContext* c
     MOZ_ASSERT(args.length() == 3);
     MOZ_ASSERT(IsConstructor(args[0]));
     MOZ_ASSERT(IsConstructor(args[1]));
     MOZ_ASSERT(args[2].toObject().is<ArrayObject>());
 
     RootedArrayObject argsList(cx, &args[2].toObject().as<ArrayObject>());
     uint32_t len = argsList->length();
     ConstructArgs constructArgs(cx);
-    if (!constructArgs.init(len))
+    if (!constructArgs.init(cx, len))
         return false;
     for (uint32_t index = 0; index < len; index++)
         constructArgs[index].set(argsList->getDenseElement(index));
 
     RootedObject res(cx);
     if (!Construct(cx, args[0], constructArgs, args[1], &res))
         return false;
 
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -18,29 +18,29 @@
 
 #include "asmjs/WasmFrameIterator.h"
 #include "gc/Rooting.h"
 #include "jit/JitFrameIterator.h"
 #ifdef CHECK_OSIPOINT_REGISTERS
 #include "jit/Registers.h" // for RegisterDump
 #endif
 #include "js/RootingAPI.h"
+#include "vm/ArgumentsObject.h"
 #include "vm/SavedFrame.h"
 
 struct JSCompartment;
 
 namespace JS {
 namespace dbg {
 class AutoEntryMonitor;
 } // namespace dbg
 } // namespace JS
 
 namespace js {
 
-class ArgumentsObject;
 class InterpreterRegs;
 class CallObject;
 class FrameIter;
 class EnvironmentObject;
 class ScriptFrameIter;
 class SPSProfiler;
 class InterpreterFrame;
 class LexicalEnvironmentObject;
@@ -943,17 +943,22 @@ class GenericArgsBase
   : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
 {
   protected:
     AutoValueVector v_;
 
     explicit GenericArgsBase(JSContext* cx) : v_(cx) {}
 
   public:
-    bool init(unsigned argc) {
+    bool init(JSContext* cx, unsigned argc) {
+        if (argc > ARGS_LENGTH_MAX) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_ARGUMENTS);
+            return false;
+        }
+
         // callee, this, arguments[, new.target iff constructing]
         size_t len = 2 + argc + uint32_t(Construct);
         MOZ_ASSERT(len > argc);  // no overflow
         if (!v_.resize(len))
             return false;
 
         *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(argc, v_.begin());
         this->constructing_ = Construct;
@@ -963,16 +968,18 @@ class GenericArgsBase
     }
 };
 
 /** Function call/construct args of statically-known count. */
 template <MaybeConstruct Construct, size_t N>
 class FixedArgsBase
   : public mozilla::Conditional<Construct, AnyConstructArgs, AnyInvokeArgs>::Type
 {
+    static_assert(N <= ARGS_LENGTH_MAX, "o/~ too many args o/~");
+
   protected:
     JS::AutoValueArray<2 + N + uint32_t(Construct)> v_;
 
     explicit FixedArgsBase(JSContext* cx) : v_(cx) {
         *static_cast<JS::CallArgs*>(this) = CallArgsFromVp(N, v_.begin());
         this->constructing_ = Construct;
         if (Construct)
             this->CallArgs::setThis(MagicValue(JS_IS_CONSTRUCTING));
@@ -1019,17 +1026,17 @@ class FixedConstructArgs : public detail
     explicit FixedConstructArgs(JSContext* cx) : Base(cx) {}
 };
 
 template <class Args, class Arraylike>
 inline bool
 FillArgumentsFromArraylike(JSContext* cx, Args& args, const Arraylike& arraylike)
 {
     uint32_t len = arraylike.length();
-    if (!args.init(len))
+    if (!args.init(cx, len))
         return false;
 
     for (uint32_t i = 0; i < len; i++)
         args[i].set(arraylike[i]);
 
     return true;
 }