Bug 1533890: Add megamorphic native stubs to CacheIR r=mgaudet
authorIain Ireland <iireland@mozilla.com>
Mon, 08 Apr 2019 15:29:03 +0000
changeset 468394 190f9fd0c2a7d6f6a411646ba1c25194b8574a01
parent 468393 8664fa8a8a10098284899e8ca8e843072fcce9ab
child 468395 90f3b654d3ac69515e688942af08bf5480b5f0fa
push id35835
push useraciure@mozilla.com
push dateMon, 08 Apr 2019 19:00:29 +0000
treeherdermozilla-central@40456af7da1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmgaudet
bugs1533890
milestone68.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 1533890: Add megamorphic native stubs to CacheIR r=mgaudet This patch extends megamorphic support to native functions, which were not previously supported. Differential Revision: https://phabricator.services.mozilla.com/D25874
js/src/jit-test/tests/cacheir/call-any-native.js
js/src/jit/CacheIR.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/call-any-native.js
@@ -0,0 +1,59 @@
+// Test non-constructor calls
+
+var funcs = [Math.max, Math.min, Math.floor, Math.ceil, Math.sin,
+             Math.cos, Math.tan, Math.log, Math.acos, Math.asin];
+
+// Calculate expected values
+var expected = [Math.max(0.5, 2), Math.min(0.5, 2),
+                Math.floor(0.5, 2), Math.ceil(0.5, 2),
+                Math.sin(0.5, 2), Math.cos(0.5, 2),
+                Math.tan(0.5, 2), Math.log(0.5, 2),
+                Math.acos(0.5, 2), Math.asin(0.5, 2)];
+
+// Test a polymorphic call site
+for (var n = 0; n < 50; n++) {
+    for (var i = 0; i < funcs.length; i++) {
+        assertEq(funcs[i](0.5, 2), expected[i]);
+    }
+}
+
+// Test a polymorphic spread call site
+var spreadinput = [0.5, 2];
+for (var n = 0; n < 50; n++) {
+    for (var i = 0; i < funcs.length; i++) {
+        assertEq(funcs[i](...spreadinput), expected[i]);
+    }
+}
+
+// Test constructors
+
+function f1(x) {this[0] = x; this.length = 3;}
+function f2(x) {this[0] = x; this.length = 3;}
+function f3(x) {this[0] = x; this.length = 3;}
+function f4(x) {this[0] = x; this.length = 3;}
+function f5(x) {this[0] = x; this.length = 3;}
+function f6(x) {this[0] = x; this.length = 3;}
+function f7(x) {this[0] = x; this.length = 3;}
+function f8(x) {this[0] = x; this.length = 3;}
+function f9(x) {this[0] = x; this.length = 3;}
+
+var constructors = [f1,f2,f3,f4,f5,f6,f7,f8,f9,Array];
+
+// Test a polymorphic constructor site
+for (var n = 0; n < 50; n++) {
+    for (var i = 0; i < constructors.length; i++) {
+        let x = new constructors[i](1,2,3);
+        assertEq(x.length, 3);
+        assertEq(x[0], 1);
+    }
+}
+
+var constructorinput = [1,2,3];
+// Test a polymorphic spread constructor site
+for (var n = 0; n < 50; n++) {
+    for (var i = 0; i < constructors.length; i++) {
+        let x = new constructors[i](...constructorinput);
+        assertEq(x.length, 3);
+        assertEq(x[0], 1);
+    }
+}
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -5345,63 +5345,81 @@ bool CallIRGenerator::getTemplateObjectF
       return true;
   }
 }
 
 bool CallIRGenerator::tryAttachCallNative(HandleFunction calleeFunc) {
   MOZ_ASSERT(calleeFunc->isNative());
 
   bool isSpecialized = mode_ == ICState::Mode::Specialized;
-  if (!isSpecialized) {
-    return false;
-  }
 
   bool isSpread = IsSpreadCallPC(pc_);
-  bool isSameRealm = cx_->realm() == calleeFunc->realm();
+  bool isSameRealm = isSpecialized && cx_->realm() == calleeFunc->realm();
   bool isConstructing = IsConstructorCallPC(pc_);
   CallFlags flags(isConstructing, isSpread, isSameRealm);
 
   if (isConstructing && !calleeFunc->isConstructor()) {
     return false;
   }
 
   // Check for specific native-function optimizations.
-  if (tryAttachSpecialCaseCallNative(calleeFunc)) {
+  if (isSpecialized && tryAttachSpecialCaseCallNative(calleeFunc)) {
     return true;
   }
   if (JitOptions.disableCacheIRCalls) {
     return false;
   }
 
   RootedObject templateObj(cx_);
-  if (isConstructing && !getTemplateObjectForNative(calleeFunc, &templateObj)) {
+  if (isConstructing && isSpecialized &&
+      !getTemplateObjectForNative(calleeFunc, &templateObj)) {
     return false;
   }
 
   // Load argc.
   Int32OperandId argcId(writer.setInputOperandId(0));
 
   // Load the callee and ensure it is an object
   ValOperandId calleeValId =
       writer.loadArgumentDynamicSlot(ArgumentKind::Callee, argcId, flags);
   ObjOperandId calleeObjId = writer.guardIsObject(calleeValId);
 
-  // Ensure callee matches this stub's callee
-  FieldOffset calleeOffset =
-      writer.guardSpecificObject(calleeObjId, calleeFunc);
-
-  writer.callNativeFunction(calleeObjId, argcId, op_, calleeFunc, flags);
+  FieldOffset calleeOffset = 0;
+  if (isSpecialized) {
+    // Ensure callee matches this stub's callee
+    calleeOffset = writer.guardSpecificObject(calleeObjId, calleeFunc);
+    writer.callNativeFunction(calleeObjId, argcId, op_, calleeFunc, flags);
+  } else {
+    // Guard that object is a native function
+    writer.guardClass(calleeObjId, GuardClassKind::JSFunction);
+    writer.guardFunctionIsNative(calleeObjId);
+
+    if (isConstructing) {
+      // If callee is not a constructor, we have to throw.
+      writer.guardFunctionIsConstructor(calleeObjId);
+    } else {
+      // If callee is a class constructor, we have to throw.
+      writer.guardNotClassConstructor(calleeObjId);
+    }
+    writer.callAnyNativeFunction(calleeObjId, argcId, flags);
+  }
+
   writer.typeMonitorResult();
 
   if (templateObj) {
+    MOZ_ASSERT(isSpecialized);
     writer.metaNativeTemplateObject(templateObj, calleeOffset);
   }
 
   cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored;
-  trackAttached("Call native func");
+  if (isSpecialized) {
+    trackAttached("Call native func");
+  } else {
+    trackAttached("Call any native func");
+  }
 
   return true;
 }
 
 bool CallIRGenerator::getTemplateObjectForClassHook(
     HandleObject calleeObj, MutableHandleObject result) {
   MOZ_ASSERT(IsConstructorCallPC(pc_));
   JSNative hook = calleeObj->constructHook();