Bug 1303678. r=arai a=ritu
authorJeff Walden <jwalden@mit.edu>
Tue, 04 Oct 2016 10:40:52 -0700
changeset 350611 6b3607656acc1508c568370faedee953e9ef11b6
parent 350610 7e1133eb4dbe8a4aebc2d5f648fb877494b01b83
child 350612 55334c13f6e0e57237d7995f624960f8449bb4a2
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersarai, ritu
bugs1303678
milestone50.0
Bug 1303678. r=arai a=ritu
js/src/asmjs/WasmInstance.cpp
js/src/builtin/MapObject.cpp
js/src/builtin/Reflect.cpp
js/src/builtin/ReflectParse.cpp
js/src/builtin/WeakMapObject.cpp
js/src/builtin/WeakSetObject.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
@@ -205,17 +205,17 @@ Instance::toggleProfiling(JSContext* cx)
 
 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/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -540,17 +540,17 @@ MapObject::construct(JSContext* cx, unsi
 
                 HeapPtr<Value> rval(val);
                 if (!map->put(hkey, rval)) {
                     ReportOutOfMemory(cx);
                     return false;
                 }
                 WriteBarrierPost(cx->runtime(), map, key);
             } else {
-                if (!args2.init(2))
+                if (!args2.init(cx, 2))
                     return false;
 
                 args2[0].set(key);
                 args2[1].set(val);
 
                 if (!fig.call(cx, adderVal, mapVal, &dummy))
                     return false;
             }
@@ -1168,17 +1168,17 @@ SetObject::construct(JSContext* cx, unsi
                 if (!key.setValue(cx, keyVal))
                     return false;
                 if (!set->put(key)) {
                     ReportOutOfMemory(cx);
                     return false;
                 }
                 WriteBarrierPost(cx->runtime(), set, keyVal);
             } else {
-                if (!args2.init(1))
+                if (!args2.init(cx, 1))
                     return false;
 
                 args2[0].set(keyVal);
 
                 if (!fig.call(cx, adderVal, setVal, &dummy))
                     return false;
             }
         }
--- a/js/src/builtin/Reflect.cpp
+++ b/js/src/builtin/Reflect.cpp
@@ -33,22 +33,17 @@ InitArgsFromArrayLike(JSContext* cx, Han
     if (!obj)
         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_ReportErrorNumber(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>
     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/builtin/WeakMapObject.cpp
+++ b/js/src/builtin/WeakMapObject.cpp
@@ -360,17 +360,17 @@ WeakMap_construct(JSContext* cx, unsigne
                     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
                     return false;
                 }
 
                 keyObject = &keyVal.toObject();
                 if (!SetWeakMapEntry(cx, obj, keyObject, val))
                     return false;
             } else {
-                if (!args2.init(2))
+                if (!args2.init(cx, 2))
                     return false;
 
                 args2[0].set(keyVal);
                 args2[1].set(val);
 
                 if (!fig.call(cx, adderVal, mapVal, &dummy))
                     return false;
             }
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -132,17 +132,17 @@ WeakSetObject::construct(JSContext* cx, 
                     JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
                     return false;
                 }
 
                 keyObject = &keyVal.toObject();
                 if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
                     return false;
             } else {
-                if (!args2.init(1))
+                if (!args2.init(cx, 1))
                     return false;
 
                 args2[0].set(keyVal);
 
                 if (!fig.call(cx, adderVal, setVal, &dummy))
                     return false;
             }
         }
--- 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
@@ -137,17 +137,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
@@ -1238,17 +1238,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());
 }
 
@@ -1278,17 +1278,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_ReportErrorNumber(cx, GetErrorMessage, nullptr,
@@ -1299,22 +1299,17 @@ 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_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
-            return false;
-        }
-
-        if (!args2.init(length))
+        if (!args2.init(cx, length))
             return false;
 
         // Steps 7-8.
         if (!GetElements(cx, aobj, length, args2.array()))
             return false;
     }
 
     // Step 9.
--- 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
@@ -1603,17 +1603,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);
 }
@@ -9723,17 +9723,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
@@ -4634,16 +4634,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_ReportErrorNumber(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
@@ -4669,29 +4671,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
@@ -208,17 +208,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>().isSelfHostedBuiltin());
 
     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);
@@ -1709,17 +1709,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());
 }
 
@@ -1926,17 +1926,17 @@ intrinsic_ConstructFunction(JSContext* c
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
     MOZ_ASSERT(args[0].toObject().is<JSFunction>());
     MOZ_ASSERT(args[1].toObject().is<ArrayObject>());
 
     RootedArrayObject argsList(cx, &args[1].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[0], &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 ScopeObject;
 class ScriptFrameIter;
 class SPSProfiler;
 class InterpreterFrame;
 class StaticBlockScope;
@@ -952,17 +952,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_ReportErrorNumber(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;
@@ -972,16 +977,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));
@@ -1028,17 +1035,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;
 }