Share ic data between unoptimized and optimized static calls.
This prevents duplicated javascript compatibility warnings.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//322633002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@37103 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 158631d..4c240e8 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -888,21 +888,32 @@
                                            const Function& function,
                                            intptr_t argument_count,
                                            const Array& argument_names,
-                                           LocationSummary* locs) {
-  const Array& arguments_descriptor =
-      Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
-                                                 argument_names));
+                                           LocationSummary* locs,
+                                           const ICData& ic_data) {
+  const Array& arguments_descriptor = Array::ZoneHandle(
+      ic_data.IsNull() ? ArgumentsDescriptor::New(argument_count,
+                                                  argument_names)
+                       : ic_data.arguments_descriptor());
   // Proper reporting of Javascript incompatibilities requires icdata and
   // may therefore prevent the optimization of some static calls.
   if (is_optimizing() &&
       !(FLAG_warn_on_javascript_compatibility &&
         (MethodRecognizer::RecognizeKind(function) ==
          MethodRecognizer::kObjectIdentical))) {
-    EmitOptimizedStaticCall(function, arguments_descriptor, argument_count,
-                            deopt_id, token_pos, locs);
+    EmitOptimizedStaticCall(function, arguments_descriptor,
+                            argument_count, deopt_id, token_pos, locs);
   } else {
-    EmitUnoptimizedStaticCall(function, arguments_descriptor, argument_count,
-                              deopt_id, token_pos, locs);
+    ICData& call_ic_data = ICData::ZoneHandle(ic_data.raw());
+    if (call_ic_data.IsNull()) {
+      call_ic_data = ICData::New(parsed_function().function(),  // Caller fun.
+                                 String::Handle(function.name()),
+                                 arguments_descriptor,
+                                 deopt_id,
+                                 0);  // No arguments checked.
+      call_ic_data.AddTarget(function);
+    }
+    EmitUnoptimizedStaticCall(argument_count, deopt_id, token_pos, locs,
+                              call_ic_data);
   }
 }
 
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 6546ff8..1d9a443 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -331,7 +331,8 @@
                           const Function& function,
                           intptr_t argument_count,
                           const Array& argument_names,
-                          LocationSummary* locs);
+                          LocationSummary* locs,
+                          const ICData& ic_data);
 
   void GenerateNumberTypeCheck(Register kClassIdReg,
                                const AbstractType& type,
@@ -475,12 +476,11 @@
                                intptr_t token_pos,
                                LocationSummary* locs);
 
-  void EmitUnoptimizedStaticCall(const Function& function,
-                                 const Array& arguments_descriptor,
-                                 intptr_t argument_count,
+  void EmitUnoptimizedStaticCall(intptr_t argument_count,
                                  intptr_t deopt_id,
                                  intptr_t token_pos,
-                                 LocationSummary* locs);
+                                 LocationSummary* locs,
+                                 const ICData& ic_data);
 
   // Type checking helper methods.
   void CheckClassIds(Register class_id_reg,
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 55d6f8e..d22fc67 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1281,27 +1281,11 @@
 
 
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
     intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
+    LocationSummary* locs,
+    const ICData& ic_data) {
   uword label_address = 0;
   if (ic_data.NumArgsTested() == 0) {
     label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 9e4cb4e..66a29de 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -1287,27 +1287,11 @@
 
 
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
     intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
+    LocationSummary* locs,
+    const ICData& ic_data) {
   uword label_address = 0;
   if (ic_data.NumArgsTested() == 0) {
     label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 1f14dc6..1c4bfd3 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1169,27 +1169,11 @@
 
 
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
     intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
+    LocationSummary* locs,
+    const ICData& ic_data) {
   uword label_address = 0;
   if (ic_data.NumArgsTested() == 0) {
     label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 8a75aef..0a69efa 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1323,27 +1323,11 @@
 
 
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
     intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
+    LocationSummary* locs,
+    const ICData& ic_data) {
   uword label_address = 0;
   if (ic_data.NumArgsTested() == 0) {
     label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index d566e4e..0f5a1e5 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1207,27 +1207,11 @@
 
 
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
     intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
+    LocationSummary* locs,
+    const ICData& ic_data) {
   uword label_address = 0;
   if (ic_data.NumArgsTested() == 0) {
     label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index a87ac3a..5283cea 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2336,6 +2336,26 @@
 
 
 void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  ICData& call_ic_data = ICData::ZoneHandle(ic_data()->raw());
+  if (!FLAG_propagate_ic_data || !compiler->is_optimizing()) {
+    const Array& arguments_descriptor =
+        Array::Handle(ArgumentsDescriptor::New(ArgumentCount(),
+                                               argument_names()));
+    // TODO(srdjan): Improve performance of function recognition.
+    MethodRecognizer::Kind recognized_kind =
+        MethodRecognizer::RecognizeKind(function());
+    int num_args_checked = 0;
+    if ((recognized_kind == MethodRecognizer::kMathMin) ||
+        (recognized_kind == MethodRecognizer::kMathMax)) {
+      num_args_checked = 2;
+    }
+    call_ic_data = ICData::New(compiler->parsed_function().function(),
+                               String::Handle(function().name()),
+                               arguments_descriptor,
+                               deopt_id(),
+                               num_args_checked);  // No arguments checked.
+    call_ic_data.AddTarget(function());
+  }
   if (!compiler->is_optimizing()) {
     // Some static calls can be optimized by the optimizing compiler (e.g. sqrt)
     // and therefore need a deoptimization descriptor.
@@ -2348,7 +2368,8 @@
                                function(),
                                ArgumentCount(),
                                argument_names(),
-                               locs());
+                               locs(),
+                               call_ic_data);
 }
 
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index ebc5e5c..b8c98bd 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1021,7 +1021,8 @@
                                CallFunction(),
                                kNumberOfArguments,
                                kNoArgumentNames,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   ASSERT(locs()->out(0).reg() == R0);
 }
 
@@ -5141,7 +5142,8 @@
                                target,
                                kNumberOfArguments,
                                Object::null_array(),  // No argument names.,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   __ Bind(&done);
 }
 
@@ -5573,7 +5575,8 @@
                                  target,
                                  instance_call()->ArgumentCount(),
                                  instance_call()->argument_names(),
-                                 locs());
+                                 locs(),
+                                 ICData::Handle());
     return;
   }
 
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index ec073f7..da4e8b8 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -869,7 +869,8 @@
                                CallFunction(),
                                kNumberOfArguments,
                                kNoArgumentNames,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   ASSERT(locs()->out(0).reg() == R0);
 }
 
@@ -4500,7 +4501,8 @@
                                target,
                                kNumberOfArguments,
                                Object::null_array(),  // No argument names.,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   __ Bind(&done);
 }
 
@@ -4882,7 +4884,8 @@
                                  target,
                                  instance_call()->ArgumentCount(),
                                  instance_call()->argument_names(),
-                                 locs());
+                                 locs(),
+                                 ICData::Handle());
     return;
   }
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 83e6f5d..fbf3eba 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -907,7 +907,8 @@
                                CallFunction(),
                                kNumberOfArguments,
                                kNoArgumentNames,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   ASSERT(locs()->out(0).reg() == EAX);
 }
 
@@ -4945,8 +4946,9 @@
                                instance_call()->token_pos(),
                                target,
                                kNumberOfArguments,
-                               Object::null_array(),  // No argument names.,
-                               locs());
+                               Object::null_array(),  // No argument names.
+                               locs(),
+                               ICData::Handle());
   __ Bind(&done);
 }
 
@@ -5422,7 +5424,8 @@
                                  target,
                                  instance_call()->ArgumentCount(),
                                  instance_call()->argument_names(),
-                                 locs());
+                                 locs(),
+                                 ICData::Handle());
     return;
   }
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index bec3d41..92b090d 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -987,7 +987,8 @@
                                CallFunction(),
                                kNumberOfArguments,
                                kNoArgumentNames,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   ASSERT(locs()->out(0).reg() == V0);
 }
 
@@ -3860,7 +3861,8 @@
                                target,
                                kNumberOfArguments,
                                Object::null_array(),  // No argument names.,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   __ Bind(&done);
 }
 
@@ -4236,7 +4238,8 @@
                                  target,
                                  instance_call()->ArgumentCount(),
                                  instance_call()->argument_names(),
-                                 locs());
+                                 locs(),
+                                 ICData::Handle());
     return;
   }
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 6ce429c..0a82178 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -836,7 +836,8 @@
                                CallFunction(),
                                kNumberOfArguments,
                                kNoArgumentNames,
-                               locs());
+                               locs(),
+                               ICData::Handle());
   ASSERT(locs()->out(0).reg() == RAX);
 }
 
@@ -4791,7 +4792,8 @@
                                target,
                                kNumberOfArguments,
                                Object::null_array(),  // No argument names.
-                               locs());
+                               locs(),
+                               ICData::Handle());
   __ Bind(&done);
 }
 
@@ -5324,7 +5326,8 @@
                                  target,
                                  instance_call()->ArgumentCount(),
                                  instance_call()->argument_names(),
-                                 locs());
+                                 locs(),
+                                 ICData::Handle());
     return;
   }
 
diff --git a/tests/standalone/javascript_compatibility_errors_test.dart b/tests/standalone/javascript_compatibility_errors_test.dart
index a9420b3..a384274 100644
--- a/tests/standalone/javascript_compatibility_errors_test.dart
+++ b/tests/standalone/javascript_compatibility_errors_test.dart
@@ -158,16 +158,18 @@
     e is Error && "$e".contains("Javascript Compatibility Error");
 
 main() {
-  // Since the warning (or error in case of --warning_as_error) is issued at
-  // most once per location, the Expect.throw must guard the whole loop.
-  Expect.throws(
-      () {
-        for (var i = 0; i < 20; i++) {
-          h(i, i * 1.0);
-        }
-      },
-      isJavascriptCompatibilityError);
-
+  // The warning (or error in case of --warning_as_error) is issued at
+  // most once per location.
+  var numWarnings = 0;
+  for (var i = 0; i < 20; i++) {
+    try {
+      h(i, i * 1.0);
+    } catch(e) {
+      Expect.isTrue(isJavascriptCompatibilityError(e));
+      numWarnings++;
+    }
+  }
+  Expect.equals(1, numWarnings);
   // No warnings (errors) should be issued after this point.
   for (var i = 0; i < 20; i++) {
     k(i * 1.0, i);