Bug 1338920 - Support JSOP_SPREADCALL in Ion draft
authorTed Campbell <tcampbell@mozilla.com>
Tue, 21 Mar 2017 18:38:54 -0400
changeset 555108 87355b7529a0ca14a17bde56d386c6c72826b014
parent 554510 2b5053942f66f363a19e3c435f4494c589bda37c
child 622533 49312d725c3b37b73e8cb3fad3a3c89b534981fd
push id52155
push userbmo:tcampbell@mozilla.com
push dateMon, 03 Apr 2017 17:09:58 +0000
bugs1338920
milestone55.0a1
Bug 1338920 - Support JSOP_SPREADCALL in Ion MozReview-Commit-ID: 1WOhrGAedLi
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2008,16 +2008,19 @@ IonBuilder::inspectOpcode(JSOp op)
         return jsop_initelem_getter_setter();
 
       case JSOP_FUNCALL:
         return jsop_funcall(GET_ARGC(pc));
 
       case JSOP_FUNAPPLY:
         return jsop_funapply(GET_ARGC(pc));
 
+      case JSOP_SPREADCALL:
+        return jsop_spreadcall();
+
       case JSOP_CALL:
       case JSOP_CALL_IGNORES_RV:
       case JSOP_CALLITER:
       case JSOP_NEW:
       case JSOP_SUPERCALL:
         MOZ_TRY(jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL,
                           (JSOp)*pc == JSOP_CALL_IGNORES_RV));
         if (op == JSOP_CALLITER) {
@@ -5047,16 +5050,55 @@ IonBuilder::jsop_funapply(uint32_t argc)
         return abort(AbortReason::Disable, "fun.apply speculation failed");
     }
 
     // Use funapply that definitely uses |arguments|
     return jsop_funapplyarguments(argc);
 }
 
 AbortReasonOr<Ok>
+IonBuilder::jsop_spreadcall()
+{
+    // The arguments array is constructed by a JSOP_SPREADCALLARRAY and not
+    // leaked to user. The complications of spread call iterator behaviour are
+    // handled when the user objects are expanded and copied into this hidden
+    // array.
+
+#ifdef DEBUG
+    // If we know class, ensure it is what we expected
+    MDefinition* argument = current->peek(-1);
+    if (TemporaryTypeSet* objTypes = argument->resultTypeSet())
+        if (const Class* clasp = objTypes->getKnownClass(constraints()))
+            MOZ_ASSERT(clasp == &ArrayObject::class_);
+#endif
+
+    MDefinition* argArr = current->pop();
+    MDefinition* argThis = current->pop();
+    MDefinition* argFunc = current->pop();
+
+    // Extract call target.
+    TemporaryTypeSet* funTypes = argFunc->resultTypeSet();
+    JSFunction* target = getSingleCallTarget(funTypes);
+    WrappedFunction* wrappedTarget = target ? new(alloc()) WrappedFunction(target) : nullptr;
+
+    // Dense elements of argument array
+    MElements* elements = MElements::New(alloc(), argArr);
+    current->add(elements);
+
+    MApplyArray* apply = MApplyArray::New(alloc(), wrappedTarget, argFunc, elements, argThis);
+    current->add(apply);
+    current->push(apply);
+    MOZ_TRY(resumeAfter(apply));
+
+    // TypeBarrier the call result
+    TemporaryTypeSet* types = bytecodeTypes(pc);
+    return pushTypeBarrier(apply, types, BarrierKind::TypeSet);
+}
+
+AbortReasonOr<Ok>
 IonBuilder::jsop_funapplyarray(uint32_t argc)
 {
     MOZ_ASSERT(argc == 2);
 
     int funcDepth = -((int)argc + 1);
 
     // Extract call target.
     TemporaryTypeSet* funTypes = current->peek(funcDepth)->resultTypeSet();
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -499,16 +499,17 @@ class IonBuilder
     AbortReasonOr<Ok> jsop_notearg();
     AbortReasonOr<Ok> jsop_throwsetconst();
     AbortReasonOr<Ok> jsop_checklexical();
     AbortReasonOr<Ok> jsop_checkaliasedlexical(EnvironmentCoordinate ec);
     AbortReasonOr<Ok> jsop_funcall(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapply(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapplyarguments(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapplyarray(uint32_t argc);
+    AbortReasonOr<Ok> jsop_spreadcall();
     AbortReasonOr<Ok> jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue);
     AbortReasonOr<Ok> jsop_eval(uint32_t argc);
     AbortReasonOr<Ok> jsop_label();
     AbortReasonOr<Ok> jsop_andor(JSOp op);
     AbortReasonOr<Ok> jsop_dup2();
     AbortReasonOr<Ok> jsop_loophead(jsbytecode* pc);
     AbortReasonOr<Ok> jsop_compare(JSOp op);
     AbortReasonOr<Ok> jsop_compare(JSOp op, MDefinition* left, MDefinition* right);