[vm/interpreter] Fix return value and type arguments in constructor tear-offs

TEST=ci

Change-Id: Ibe1ede1bc1c4e044285ee3b3f75ca138d7596e8a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/384682
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/runtime/vm/constants_kbc.cc b/runtime/vm/constants_kbc.cc
index b4ae664..314a9c3 100644
--- a/runtime/vm/constants_kbc.cc
+++ b/runtime/vm/constants_kbc.cc
@@ -34,12 +34,26 @@
 #undef SIZE
 };
 
+static const KBCInstr kVMInternal_ImplicitConstructorClosureInstructions[] = {
+    KernelBytecode::kVMInternal_ImplicitConstructorClosure,
+    0,
+    0,
+    KernelBytecode::kPush,
+    0,
+    KernelBytecode::kReturnTOS,
+};
+
+static const KBCInstr
+    kVMInternal_ImplicitConstructorClosure_WideInstructions[] = {
+        KernelBytecode::kTrap,
+};
+
 #define DECLARE_INSTRUCTIONS(name, fmt, kind, fmta, fmtb, fmtc)                \
   static const KBCInstr k##name##Instructions[] = {                            \
       KernelBytecode::k##name,                                                 \
       KernelBytecode::kReturnTOS,                                              \
   };
-INTERNAL_KERNEL_BYTECODES_LIST(DECLARE_INSTRUCTIONS)
+INTERNAL_KERNEL_BYTECODES_WITH_DEFAULT_CODE(DECLARE_INSTRUCTIONS)
 #undef DECLARE_INSTRUCTIONS
 
 void KernelBytecode::GetVMInternalBytecodeInstructions(
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index 3385e39..8123580 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -204,19 +204,29 @@
 
   // These bytecodes are only generated within the VM. Reassigning their
   // opcodes is not a breaking change.
+#define INTERNAL_KERNEL_BYTECODES_WITH_CUSTOM_CODE(V) \
+  /* VMInternal_ImplicitConstructorClosure uses D_F encoding as it calls  */   \
+  /* constructor and should be compatible with other ***Call instructions */   \
+  /* in order to support DecodeArgc when returning from a call.           */   \
+  V(VMInternal_ImplicitConstructorClosure,      D_F, ORDN, num, num, ___)      \
+  V(VMInternal_ImplicitConstructorClosure_Wide, D_F, ORDN, num, num, ___)      \
+
+#define INTERNAL_KERNEL_BYTECODES_WITH_DEFAULT_CODE(V)                         \
+  V(VMInternal_ImplicitGetter,                    0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ImplicitSetter,                    0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ImplicitStaticGetter,              0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ImplicitStaticSetter,              0, ORDN, ___, ___, ___)      \
+  V(VMInternal_MethodExtractor,                   0, ORDN, ___, ___, ___)      \
+  V(VMInternal_InvokeClosure,                     0, ORDN, ___, ___, ___)      \
+  V(VMInternal_InvokeField,                       0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ForwardDynamicInvocation,          0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ImplicitStaticClosure,             0, ORDN, ___, ___, ___)      \
+  V(VMInternal_ImplicitInstanceClosure,           0, ORDN, ___, ___, ___)      \
+  V(VMInternal_NoSuchMethodDispatcher,            0, ORDN, ___, ___, ___)      \
+
 #define INTERNAL_KERNEL_BYTECODES_LIST(V)                                      \
-  V(VMInternal_ImplicitGetter,             0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitSetter,             0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitStaticGetter,       0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitStaticSetter,       0, ORDN, ___, ___, ___)             \
-  V(VMInternal_MethodExtractor,            0, ORDN, ___, ___, ___)             \
-  V(VMInternal_InvokeClosure,              0, ORDN, ___, ___, ___)             \
-  V(VMInternal_InvokeField,                0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ForwardDynamicInvocation,   0, ORDN, ___, ___, ___)             \
-  V(VMInternal_NoSuchMethodDispatcher,     0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitStaticClosure,      0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitInstanceClosure,    0, ORDN, ___, ___, ___)             \
-  V(VMInternal_ImplicitConstructorClosure, 0, ORDN, ___, ___, ___)             \
+  INTERNAL_KERNEL_BYTECODES_WITH_CUSTOM_CODE(V)                                \
+  INTERNAL_KERNEL_BYTECODES_WITH_DEFAULT_CODE(V)
 
 #define KERNEL_BYTECODES_LIST(V)                                               \
   PUBLIC_KERNEL_BYTECODES_LIST(V)                                              \
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index f0675c7..e5877e7 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -3626,7 +3626,8 @@
   }
 
   {
-    BYTECODE(VMInternal_ImplicitConstructorClosure, 0);
+    BYTECODE(VMInternal_ImplicitConstructorClosure, D_F);
+
     FunctionPtr function = FrameFunction(FP);
     ASSERT(Function::KindOf(function) ==
            UntaggedFunction::kImplicitClosureFunction);
@@ -3641,13 +3642,51 @@
         InterpreterHelpers::ArgDescArgCount(argdesc_) + receiver_idx;
     ObjectPtr* argv = FrameArguments(FP, argc);
 
+    // Reserve space for the result (instance).
+    *++SP = null_value;
+    ASSERT(SP == FP);
+
+    // Reserve space for receiver.
+    *++SP = null_value;
+    ObjectPtr* call_base = SP;
+    // Copy arguments.
+    for (intptr_t i = receiver_idx + 1; i < argc; i++) {
+      *++SP = argv[i];
+    }
+
     ClassPtr cls = Function::Owner(target);
     TypeParametersPtr type_params = cls->untag()->type_parameters();
-    TypeArgumentsPtr type_args =
-        (type_params == null_value)
-            ? TypeArguments::null()
-            : ((type_args_len > 0) ? TypeArguments::RawCast(argv[0])
-                                   : type_params->untag()->defaults());
+    TypeArgumentsPtr type_args;
+    if (type_params == null_value) {
+      if (type_args_len > 0) {
+        SP[1] = function;
+        goto NoSuchMethodFromPrologue;
+      }
+      type_args = TypeArguments::null();
+    } else {
+      TypeArgumentsPtr delayed_type_arguments =
+          Closure::RawCast(argv[receiver_idx])
+              ->untag()
+              ->delayed_type_arguments();
+      if (delayed_type_arguments != Object::empty_type_arguments().ptr()) {
+        if (type_args_len > 0) {
+          SP[1] = function;
+          goto NoSuchMethodFromPrologue;
+        }
+        type_args = delayed_type_arguments;
+      } else {
+        if (type_args_len > 0) {
+          if (type_args_len !=
+              Smi::Value(type_params->untag()->names()->untag()->length())) {
+            SP[1] = function;
+            goto NoSuchMethodFromPrologue;
+          }
+          type_args = TypeArguments::RawCast(argv[0]);
+        } else {
+          type_args = type_params->untag()->defaults();
+        }
+      }
+    }
 
     SP[1] = target;    // Save target.
     SP[2] = argdesc_;  // Save arguments descriptor.
@@ -3656,9 +3695,8 @@
     SP[3] = cls;
     SP[4] = type_args;
     Exit(thread, FP, SP + 5, pc);
-    INVOKE_RUNTIME(DRT_AllocateObject,
-                   NativeArguments(thread, 2, SP + 3, argv + receiver_idx));
-
+    INVOKE_RUNTIME(DRT_AllocateObject, NativeArguments(thread, 2, SP + 3, FP));
+    call_base[0] = FP[0];  // Copy receiver.
     argdesc_ = Array::RawCast(SP[2]);
 
     if (type_args_len > 0) {
@@ -3672,7 +3710,12 @@
       argdesc_ = Array::RawCast(SP[2]);
     }
 
-    goto TailCallSP1;
+    ObjectPtr* call_top = SP + 1;
+    if (!Invoke(thread, call_base, call_top, &pc, &FP, &SP)) {
+      HANDLE_EXCEPTION;
+    }
+
+    DISPATCH();
   }
 
   {