Bug 1611777 - Part 15: Support FunCall/FunApply optimisations for optional chaining. r=yulia
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 29 Jan 2020 16:31:20 +0000
changeset 512106 075c4404c2c81312c55db4c3e04ab4d1ddef8aa8
parent 512105 46d27864b908bd0926d6ec0b25ee165917cd9887
child 512107 65c1c7d322edbbd45fb945b1d1055d3d5716e20f
push id37072
push usercsabou@mozilla.com
push dateThu, 30 Jan 2020 15:44:43 +0000
treeherdermozilla-central@f97c48da9cee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyulia
bugs1611777
milestone74.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 1611777 - Part 15: Support FunCall/FunApply optimisations for optional chaining. r=yulia This change allows the bytecode emitter to use `JSOp::FunCall` resp. `JSOp::FunApply` for calls in optional chain expressions. Differential Revision: https://phabricator.services.mozilla.com/D61162
js/src/frontend/FullParseHandler.h
js/src/frontend/SyntaxParseHandler.h
js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -1061,18 +1061,18 @@ class FullParseHandler {
 
   bool isAsyncKeyword(Node node, JSContext* cx) {
     return node->isKind(ParseNodeKind::Name) &&
            node->pn_pos.begin + strlen("async") == node->pn_pos.end &&
            node->as<NameNode>().atom() == cx->names().async;
   }
 
   PropertyName* maybeDottedProperty(Node pn) {
-    return pn->is<PropertyAccess>() ? &pn->as<PropertyAccess>().name()
-                                    : nullptr;
+    return pn->is<PropertyAccessBase>() ? &pn->as<PropertyAccessBase>().name()
+                                        : nullptr;
   }
   JSAtom* isStringExprStatement(Node pn, TokenPos* pos) {
     if (pn->is<UnaryNode>()) {
       UnaryNode* unary = &pn->as<UnaryNode>();
       if (JSAtom* atom = unary->isStringExprStatement()) {
         *pos = unary->kid()->pn_pos;
         return atom;
       }
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -689,17 +689,17 @@ class SyntaxParseHandler {
   }
 
   PropertyName* maybeDottedProperty(Node node) {
     // Note: |super.apply(...)| is a special form that calls an "apply"
     // method retrieved from one value, but using a *different* value as
     // |this|.  It's not really eligible for the funapply/funcall
     // optimizations as they're currently implemented (assuming a single
     // value is used for both retrieval and |this|).
-    if (node != NodeDottedProperty) {
+    if (node != NodeDottedProperty && node != NodeOptionalDottedProperty) {
       return nullptr;
     }
     return lastAtom->asPropertyName();
   }
 
   JSAtom* isStringExprStatement(Node pn, TokenPos* pos) {
     if (pn == NodeStringExprStatement) {
       *pos = lastStringPos;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/optional-chain/fun-call-or-apply.js
@@ -0,0 +1,60 @@
+// Tests for JSOp::FunCall and JSOp::FunApply in optional calls.
+
+function f1() {
+  return 0;
+}
+function f2(a) {
+  return a * 2;
+}
+
+function funCall(fn) {
+  // Without arguments.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.call(), 0);
+  }
+
+  // Only this-arg.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.call(null), 0);
+  }
+
+  // With one arg.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.call(null, 1), 0);
+    assertEq(f2?.call(null, 5), 10);
+  }
+
+  // With multiple args.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.call(null, 1, 2, 3), 0);
+    assertEq(f2?.call(null, 4, 5, 6), 8);
+  }
+}
+
+for (var i = 0; i < 5; ++i) { funCall(); }
+
+function funApply(fn) {
+  // Without arguments.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.apply(), 0);
+  }
+
+  // Only this-arg.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.apply(null), 0);
+  }
+
+  // With one arg.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.apply(null, [1]), 0);
+    assertEq(f2?.apply(null, [5]), 10);
+  }
+
+  // With multiple args.
+  for (var i = 0; i < 100; ++i) {
+    assertEq(f1?.apply(null, [1, 2, 3]), 0);
+    assertEq(f2?.apply(null, [4, 5, 6]), 8);
+  }
+}
+
+for (var i = 0; i < 5; ++i) { funApply(); }