Bug 1278089 - Add JS APIs for determining whether a function is bound and getting the target; r=jorendorff
authorEhsan Akhgari <ehsan@mozilla.com>
Sat, 04 Jun 2016 19:50:50 -0400
changeset 330294 49b8cf82bcfc1532675afb17dac15a1960d07d7d
parent 330293 e816e9199940ce2b4cbace056b9a849048bf4a63
child 330295 c0d8bd0a8dd60736fbafd047596f985801440865
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1278089
milestone50.0a1
Bug 1278089 - Add JS APIs for determining whether a function is bound and getting the target; r=jorendorff
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testBoundFunction.cpp
js/src/jsapi.cpp
js/src/jsapi.h
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -7,16 +7,17 @@
 GeckoProgram('jsapi-tests', linkage=None)
 
 UNIFIED_SOURCES += [
     'selfTest.cpp',
     'testAddPropertyPropcache.cpp',
     'testArgumentsObject.cpp',
     'testArrayBuffer.cpp',
     'testArrayBufferView.cpp',
+    'testBoundFunction.cpp',
     'testBug604087.cpp',
     'testCallArgs.cpp',
     'testCallNonGenericMethodOnProxy.cpp',
     'testChromeBuffer.cpp',
     'testClassGetter.cpp',
     'testCloneScript.cpp',
     'testDateToLocaleString.cpp',
     'testDebugger.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testBoundFunction.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi-tests/tests.h"
+
+BEGIN_TEST(testBoundFunction)
+{
+    EXEC("function foo() {}");
+    JS::RootedValue foo(cx);
+    EVAL("foo", &foo);
+    JS::RootedValue bound(cx);
+    EVAL("foo.bind(1)", &bound);
+
+    JS::RootedFunction foofun(cx, JS_ValueToFunction(cx, foo));
+    JS::RootedFunction boundfun(cx, JS_ValueToFunction(cx, bound));
+
+    CHECK(!JS_IsFunctionBound(foofun));
+    CHECK(JS_IsFunctionBound(boundfun));
+
+    CHECK(!JS_GetBoundFunctionTarget(foofun));
+    JSObject* target = JS_GetBoundFunctionTarget(boundfun);
+    CHECK(!!target);
+    CHECK(JS_ObjectIsFunction(cx, target));
+    JS::RootedValue targetVal(cx, JS::ObjectValue(*target));
+    CHECK_SAME(foo, targetVal);
+
+    return true;
+}
+END_TEST(testBoundFunction)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -427,16 +427,29 @@ JS_IsBuiltinEvalFunction(JSFunction* fun
 }
 
 JS_PUBLIC_API(bool)
 JS_IsBuiltinFunctionConstructor(JSFunction* fun)
 {
     return fun->isBuiltinFunctionConstructor();
 }
 
+JS_PUBLIC_API(bool)
+JS_IsFunctionBound(JSFunction* fun)
+{
+    return fun->isBoundFunction();
+}
+
+JS_PUBLIC_API(JSObject*)
+JS_GetBoundFunctionTarget(JSFunction* fun)
+{
+    return fun->isBoundFunction() ?
+               fun->getBoundFunctionTarget() : nullptr;
+}
+
 /************************************************************************/
 
 #ifdef DEBUG
 JS_FRIEND_API(bool)
 JS::isGCEnabled()
 {
     return !TlsPerThreadData.get()->suppressGC;
 }
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3546,16 +3546,22 @@ extern JS_PUBLIC_API(JSFunction*)
 JS_DefineUCFunction(JSContext* cx, JS::Handle<JSObject*> obj,
                     const char16_t* name, size_t namelen, JSNative call,
                     unsigned nargs, unsigned attrs);
 
 extern JS_PUBLIC_API(JSFunction*)
 JS_DefineFunctionById(JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, JSNative call,
                       unsigned nargs, unsigned attrs);
 
+extern JS_PUBLIC_API(bool)
+JS_IsFunctionBound(JSFunction* fun);
+
+extern JS_PUBLIC_API(JSObject*)
+JS_GetBoundFunctionTarget(JSFunction* fun);
+
 namespace JS {
 
 /**
  * Clone a top-level function into cx's global. This function will dynamically
  * fail if funobj was lexically nested inside some other function.
  */
 extern JS_PUBLIC_API(JSObject*)
 CloneFunctionObject(JSContext* cx, HandleObject funobj);