[vm,dyn_modules] Support implicit dynamic calls in bytecode

TEST=ci (co19/Language/Expressions/Function_Invocation/Function_Expression_Invocation/call_A04_t01)

Change-Id: I49faf7c6f8d8f9353683dd94e9aa9a7ac7d30921
Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/443882
Reviewed-by: Tess Strickland <sstrickl@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/dart2bytecode/lib/bytecode_generator.dart b/pkg/dart2bytecode/lib/bytecode_generator.dart
index c8b356f..37a74c6 100644
--- a/pkg/dart2bytecode/lib/bytecode_generator.dart
+++ b/pkg/dart2bytecode/lib/bytecode_generator.dart
@@ -1039,6 +1039,10 @@
 
   late Library? dartFfiLibrary = libraryIndex.tryGetLibrary('dart:ffi');
 
+  // Selector for implicit dynamic calls 'foo(...)' where
+  // variable 'foo' has type 'dynamic'.
+  late final implicitCallName = Name('implicit:call');
+
   void _recordSourcePosition(int fileOffset) {
     asm.currentSourcePosition = fileOffset;
     maxSourcePosition = math.max(maxSourcePosition, fileOffset);
@@ -3128,12 +3132,13 @@
 
   @override
   void visitDynamicInvocation(DynamicInvocation node) {
-    _genMethodInvocation(node, null);
+    final targetName = node.isImplicitCall ? implicitCallName : node.name;
+    _genMethodInvocation(node, null, targetName);
   }
 
   @override
   void visitInstanceInvocation(InstanceInvocation node) {
-    _genMethodInvocation(node, node.interfaceTarget);
+    _genMethodInvocation(node, node.interfaceTarget, node.name);
   }
 
   @override
@@ -3151,8 +3156,8 @@
     asm.emitSpecializedBytecode(Opcode.kEqualsNull);
   }
 
-  void _genMethodInvocation(
-      InstanceInvocationExpression node, Procedure? interfaceTarget) {
+  void _genMethodInvocation(InstanceInvocationExpression node,
+      Procedure? interfaceTarget, Name targetName) {
     final Opcode? opcode = recognizedMethods.specializedBytecodeFor(node);
     if (opcode != null) {
       _genMethodInvocationUsingSpecializedBytecode(opcode, node);
@@ -3172,7 +3177,7 @@
     final argDesc =
         objectTable.getArgDescHandleByArguments(args, hasReceiver: true);
 
-    _genInstanceCall(node, InvocationKind.method, interfaceTarget, node.name,
+    _genInstanceCall(node, InvocationKind.method, interfaceTarget, targetName,
         node.receiver, totalArgCount, argDesc);
   }
 
diff --git a/pkg/dart2bytecode/testcases/super_calls.dart.expect b/pkg/dart2bytecode/testcases/super_calls.dart.expect
index 509e7b9..2ace24c 100644
--- a/pkg/dart2bytecode/testcases/super_calls.dart.expect
+++ b/pkg/dart2bytecode/testcases/super_calls.dart.expect
@@ -184,7 +184,7 @@
   [1] = DirectCall 'DART_SDK/pkg/dart2bytecode/testcases/super_calls.dart::Base1::get:bar', ArgDesc num-args 1, num-type-args 0, names []
   [2] = Reserved
   [3] = ObjectRef 'param'
-  [4] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+  [4] = DynamicCall 'implicit:call', ArgDesc num-args 2, num-type-args 1, names []
   [5] = Reserved
 }
 
@@ -404,7 +404,7 @@
   [6] = DirectCall 'dart:core::Object::noSuchMethod', ArgDesc num-args 2, num-type-args 0, names []
   [7] = Reserved
   [8] = ObjectRef 'param'
-  [9] = DynamicCall 'call', ArgDesc num-args 2, num-type-args 1, names []
+  [9] = DynamicCall 'implicit:call', ArgDesc num-args 2, num-type-args 1, names []
   [10] = Reserved
 }
 
diff --git a/pkg/dart2bytecode/testcases/try_blocks.dart.expect b/pkg/dart2bytecode/testcases/try_blocks.dart.expect
index c07bdbc..8396252 100644
--- a/pkg/dart2bytecode/testcases/try_blocks.dart.expect
+++ b/pkg/dart2bytecode/testcases/try_blocks.dart.expect
@@ -762,7 +762,7 @@
   [6] = Type dynamic
   [7] = ObjectRef 'try 2'
   [8] = EndClosureFunctionScope
-  [9] = DynamicCall 'call', ArgDesc num-args 1, num-type-args 0, names []
+  [9] = DynamicCall 'implicit:call', ArgDesc num-args 1, num-type-args 0, names []
   [10] = Reserved
 }
 Closure DART_SDK/pkg/dart2bytecode/testcases/try_blocks.dart::testTryFinally3::'<anonymous closure>' () -> dart:core::int
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 1bff4dd..013aba7 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -3194,7 +3194,8 @@
     // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong
     // number of arguments, or try (o.foo).call(...)
 
-    if ((target_name.ptr() == Symbols::call().ptr()) && receiver.IsClosure()) {
+    if ((demangled_target_name.ptr() == Symbols::call().ptr()) &&
+        receiver.IsClosure()) {
       // Special case: closures are implemented with a call getter instead of a
       // call method and with lazy dispatchers the field-invocation-dispatcher
       // would perform the closure call.