Bug 945566 - Make calling Proxy without 'new' keyword a TypeError. (r=jorendorff)
authorEric Faust <efaustbmo@gmail.com>
Wed, 07 Jan 2015 16:35:18 -0800
changeset 239199 8b26ea0c66f3760066bae3b79d161da16ffcefd1
parent 239198 118f9b8a5b92606a96aa6f56fef70e0a9c45a30c
child 239200 f7f224c79675560bf09fedf77c2aad82b30849aa
push id489
push usermcmanus@ducksong.com
push dateTue, 27 Jan 2015 01:44:53 +0000
reviewersjorendorff
bugs945566
milestone38.0a1
Bug 945566 - Make calling Proxy without 'new' keyword a TypeError. (r=jorendorff)
js/src/jit-test/tests/proxy/testDirectProxyConstructor.js
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/tests/ecma_6/Generators/delegating-yield-7.js
--- a/js/src/jit-test/tests/proxy/testDirectProxyConstructor.js
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstructor.js
@@ -1,23 +1,19 @@
 load(libdir + "asserts.js");
 
+// Throw a TypeError if Proxy is not called as a constructor
+assertThrowsInstanceOf(function () { Proxy({}, {}); }, TypeError);
+
 // Throw a TypeError if Proxy is called with less than two arguments
-assertThrowsInstanceOf(function () { Proxy(); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy(); }, TypeError);
-assertThrowsInstanceOf(function () { Proxy({}); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy({}); }, TypeError);
 
 // Throw a TypeError if the first argument is not a non-null object
-assertThrowsInstanceOf(function () { Proxy(0, {}); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy(0, {}); }, TypeError);
-assertThrowsInstanceOf(function () { Proxy(null, {}); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy(null, {}); }, TypeError);
 
 // Throw a TypeError if the second argument is not a non-null object
-assertThrowsInstanceOf(function () { Proxy({}, 0); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy({}, 0); }, TypeError);
-assertThrowsInstanceOf(function () { Proxy({}, null); }, TypeError);
 assertThrowsInstanceOf(function () { new Proxy({}, null); }, TypeError);
 
 // Result of the call should be an object
-assertEq(typeof Proxy({}, {}), 'object');
 assertEq(typeof new Proxy({}, {}), 'object');
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1152,23 +1152,22 @@ ScriptedDirectProxyHandler::isConstructo
     MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedDirectProxyHandler::singleton);
     uint32_t callConstruct = obj->as<ProxyObject>().extra(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
     return !!(callConstruct & IS_CONSTRUCTOR);
 }
 
 const char ScriptedDirectProxyHandler::family = 0;
 const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
 
-bool
-js::proxy(JSContext *cx, unsigned argc, jsval *vp)
+static bool
+NewScriptedProxy(JSContext *cx, CallArgs &args, const char *callerName)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
-                             "Proxy", "1", "s");
+                             callerName, "1", "s");
         return false;
     }
     RootedObject target(cx, NonNullObject(cx, args[0]));
     if (!target)
         return false;
     RootedObject handler(cx, NonNullObject(cx, args[1]));
     if (!handler)
         return false;
@@ -1185,16 +1184,29 @@ js::proxy(JSContext *cx, unsigned argc, 
     uint32_t callable = target->isCallable() ? ScriptedDirectProxyHandler::IS_CALLABLE : 0;
     uint32_t constructor = target->isConstructor() ? ScriptedDirectProxyHandler::IS_CONSTRUCTOR : 0;
     proxy->as<ProxyObject>().setExtra(ScriptedDirectProxyHandler::IS_CALLCONSTRUCT_EXTRA,
                                       PrivateUint32Value(callable | constructor));
     args.rval().setObject(*proxy);
     return true;
 }
 
+bool
+js::proxy(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!args.isConstructing()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, "Proxy");
+        return false;
+    }
+
+    return NewScriptedProxy(cx, args, "Proxy");
+}
+
 static bool
 RevokeProxy(JSContext *cx, unsigned argc, Value *vp)
 {
     CallReceiver rec = CallReceiverFromVp(vp);
 
     RootedFunction func(cx, &rec.callee().as<JSFunction>());
     RootedObject p(cx, func->getExtendedSlot(ScriptedDirectProxyHandler::REVOKE_SLOT).toObjectOrNull());
 
@@ -1209,19 +1221,19 @@ RevokeProxy(JSContext *cx, unsigned argc
 
     rec.rval().setUndefined();
     return true;
 }
 
 bool
 js::proxy_revocable(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallReceiver args = CallReceiverFromVp(vp);
+    CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!proxy(cx, argc, vp))
+    if (!NewScriptedProxy(cx, args, "Proxy.revocable"))
         return false;
 
     RootedValue proxyVal(cx, args.rval());
     MOZ_ASSERT(proxyVal.toObject().is<ProxyObject>());
 
     RootedObject revoker(cx, NewFunctionByIdWithReserved(cx, RevokeProxy, 0, 0, cx->global(),
                          AtomToId(cx->names().revoke)));
     if (!revoker)
--- a/js/src/tests/ecma_6/Generators/delegating-yield-7.js
+++ b/js/src/tests/ecma_6/Generators/delegating-yield-7.js
@@ -9,17 +9,17 @@ function results(results) {
         return results[i++];
     }
     var ret = { next: next }
     ret[std_iterator] = iterator;
     return ret;
 }
 
 function* yield_results(expected) {
-    return yield* Proxy(results(expected), {});
+    return yield* new Proxy(results(expected), {});
 }
 
 function collect_results(iter) {
     var ret = [];
     var result;
     do {
         result = iter.next();
         ret.push(result);