Bug 905989 - Fix a bogus assert and move the is-constructor check to getPolyCallTargets. r=h4writer
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 20 Aug 2013 09:19:35 +0200
changeset 156122 2872a52eb8a8845c61319411daf27862ce0c9a5c
parent 156121 0e046ece4b23e3af397ba84138bbdd92da78b741
child 156123 504839bcbddc592f47ccda9f9dba7a2d3f1990c1
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs905989
milestone26.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 905989 - Fix a bogus assert and move the is-constructor check to getPolyCallTargets. r=h4writer
js/src/jit-test/tests/ion/bug905989.js
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug905989.js
@@ -0,0 +1,10 @@
+function TestCase(n, d, e, a) {};
+function reportCompare() {
+  new TestCase();
+}
+reportCompare();
+TestCase = ParallelArray;
+try {
+  reportCompare();
+} catch(exc1) {}
+reportCompare();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -154,20 +154,18 @@ IonBuilder::getSingleCallTarget(types::S
     JSObject *obj = calleeTypes->getSingleton();
     if (!obj || !obj->is<JSFunction>())
         return NULL;
 
     return &obj->as<JSFunction>();
 }
 
 bool
-IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes,
-                               AutoObjectVector &targets,
-                               uint32_t maxTargets,
-                               bool *gotLambda)
+IonBuilder::getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
+                               AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda)
 {
     JS_ASSERT(targets.length() == 0);
     JS_ASSERT(gotLambda);
     *gotLambda = false;
 
     if (!calleeTypes)
         return true;
 
@@ -178,42 +176,48 @@ IonBuilder::getPolyCallTargets(types::St
 
     if (objCount == 0 || objCount > maxTargets)
         return true;
 
     if (!targets.reserve(objCount))
         return false;
     for(unsigned i = 0; i < objCount; i++) {
         JSObject *obj = calleeTypes->getSingleObject(i);
+        JSFunction *fun;
         if (obj) {
             if (!obj->is<JSFunction>()) {
                 targets.clear();
                 return true;
             }
-            if (obj->as<JSFunction>().isInterpreted() &&
-                !obj->as<JSFunction>().getOrCreateScript(cx))
-            {
-                return false;
-            }
-            DebugOnly<bool> appendOk = targets.append(obj);
-            JS_ASSERT(appendOk);
+            fun = &obj->as<JSFunction>();
         } else {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
             JS_ASSERT(typeObj);
             if (!typeObj->isFunction() || !typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
             }
-            if (!typeObj->interpretedFunction->getOrCreateScript(cx))
-                return false;
-            DebugOnly<bool> appendOk = targets.append(typeObj->interpretedFunction);
-            JS_ASSERT(appendOk);
-
+
+            fun = typeObj->interpretedFunction;
             *gotLambda = true;
         }
+
+        if (fun->isInterpreted() && !fun->getOrCreateScript(cx))
+            return false;
+
+        // Don't optimize if we're constructing and the callee is not a
+        // constructor, so that CallKnown does not have to handle this case
+        // (it should always throw).
+        if (constructing && !fun->isInterpretedConstructor() && !fun->isNativeConstructor()) {
+            targets.clear();
+            return true;
+        }
+
+        DebugOnly<bool> appendOk = targets.append(fun);
+        JS_ASSERT(appendOk);
     }
 
     // For now, only inline "singleton" lambda calls
     if (*gotLambda && targets.length() > 1)
         targets.clear();
 
     return true;
 }
@@ -4942,17 +4946,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
 
     int calleeDepth = -((int)argc + 2);
 
     // Acquire known call target if existent.
     AutoObjectVector originals(cx);
     bool gotLambda = false;
     types::StackTypeSet *calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     if (calleeTypes) {
-        if (!getPolyCallTargets(calleeTypes, originals, 4, &gotLambda))
+        if (!getPolyCallTargets(calleeTypes, constructing, originals, 4, &gotLambda))
             return false;
     }
     JS_ASSERT_IF(gotLambda, originals.length() <= 1);
 
     // If any call targets need to be cloned, clone them. Keep track of the
     // originals as we need to case on them for poly inline.
     bool hasClones = false;
     AutoObjectVector targets(cx);
@@ -4978,26 +4982,19 @@ IonBuilder::jsop_call(uint32_t argc, boo
     InliningStatus status = inlineCallsite(targets, originals, gotLambda, callInfo);
     if (status == InliningStatus_Inlined)
         return true;
     if (status == InliningStatus_Error)
         return false;
 
     // No inline, just make the call.
     RootedFunction target(cx, NULL);
-    if (targets.length() == 1) {
+    if (targets.length() == 1)
         target = &targets[0]->as<JSFunction>();
 
-        // Don't optimize if we're constructing and the callee is not an
-        // interpreted constructor, so that CallKnown does not have to
-        // handle this case (it should always throw).
-        if (constructing && !target->isInterpretedConstructor())
-            target = NULL;
-    }
-
     return makeCall(target, callInfo, hasClones);
 }
 
 MDefinition *
 IonBuilder::makeCallsiteClone(HandleFunction target, MDefinition *fun)
 {
     // Bake in the clone eagerly if we have a known target. We have arrived here
     // because TI told us that the known target is a should-clone-at-callsite
@@ -5261,17 +5258,18 @@ DOMCallNeedsBarrier(const JSJitInfo* jit
     return jitinfo->returnType != types->getKnownTypeTag();
 }
 
 bool
 IonBuilder::makeCall(HandleFunction target, CallInfo &callInfo, bool cloneAtCallsite)
 {
     // Constructor calls to non-constructors should throw. We don't want to use
     // CallKnown in this case.
-    JS_ASSERT_IF(callInfo.constructing() && target, target->isInterpretedConstructor());
+    JS_ASSERT_IF(callInfo.constructing() && target,
+                 target->isInterpretedConstructor() || target->isNativeConstructor());
 
     MCall *call = makeCallHelper(target, callInfo, cloneAtCallsite);
     if (!call)
         return false;
 
     current->push(call);
     if (!resumeAfter(call))
         return false;
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -220,20 +220,18 @@ class IonBuilder : public MIRGenerator
     bool abort(const char *message, ...);
     void spew(const char *message);
 
     static bool inliningEnabled() {
         return js_IonOptions.inlining;
     }
 
     JSFunction *getSingleCallTarget(types::StackTypeSet *calleeTypes);
-    bool getPolyCallTargets(types::StackTypeSet *calleeTypes,
-                            AutoObjectVector &targets,
-                            uint32_t maxTargets,
-                            bool *gotLambda);
+    bool getPolyCallTargets(types::StackTypeSet *calleeTypes, bool constructing,
+                            AutoObjectVector &targets, uint32_t maxTargets, bool *gotLambda);
     bool canInlineTarget(JSFunction *target, bool constructing);
 
     void popCfgStack();
     DeferredEdge *filterDeadDeferredEdges(DeferredEdge *edge);
     bool processDeferredContinues(CFGState &state);
     ControlStatus processControlEnd();
     ControlStatus processCfgStack();
     ControlStatus processCfgEntry(CFGState &state);