Revision: 6037
Author: [email protected]
Date: Wed Dec 15 09:11:11 2010
Log: Deoptimize non-smi switch cases if they are reached.

This way if the type oracle says an unreachable clause has a non-smi
type, we can still emit optimized code instead of doing an early
bailout.

This change depends of Florian's r5970.

Review URL: http://codereview.chromium.org/5812005
http://code.google.com/p/v8/source/detail?r=6037

Modified:
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/runtime.cc

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Wed Dec 15 08:12:55 2010
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Dec 15 09:11:11 2010
@@ -2574,6 +2574,8 @@

 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
   VISIT_FOR_VALUE(stmt->tag());
+  // TODO(3168478): simulate added for tag should be enough.
+  AddSimulate(stmt->EntryId());
   HValue* switch_value = Pop();

   ZoneList<CaseClause*>* clauses = stmt->cases();
@@ -2581,11 +2583,17 @@
   if (num_clauses == 0) return;
   if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses");

+  int num_smi_clauses = num_clauses;
   for (int i = 0; i < num_clauses; i++) {
     CaseClause* clause = clauses->at(i);
     if (clause->is_default()) continue;
     clause->RecordTypeFeedback(oracle());
- if (!clause->IsSmiCompare()) BAILOUT("SwitchStatement: non-smi compare");
+    if (!clause->IsSmiCompare()) {
+      if (i == 0) BAILOUT("SwitchStatement: no smi compares");
+      // We will deoptimize if the first non-smi compare is reached.
+      num_smi_clauses = i;
+      break;
+    }
     if (!clause->label()->IsSmiLiteral()) {
       BAILOUT("SwitchStatement: non-literal switch label");
     }
@@ -2596,17 +2604,18 @@

   // Build a series of empty subgraphs for the comparisons.
   // The default clause does not have a comparison subgraph.
-  ZoneList<HSubgraph*> compare_graphs(num_clauses);
-  for (int i = 0; i < num_clauses; i++) {
-    HSubgraph* subgraph = !clauses->at(i)->is_default()
-        ? CreateEmptySubgraph()
-        : NULL;
-    compare_graphs.Add(subgraph);
+  ZoneList<HSubgraph*> compare_graphs(num_smi_clauses);
+  for (int i = 0; i < num_smi_clauses; i++) {
+    if (clauses->at(i)->is_default()) {
+      compare_graphs.Add(NULL);
+    } else {
+      compare_graphs.Add(CreateEmptySubgraph());
+    }
   }

   HSubgraph* prev_graph = current_subgraph_;
   HCompare* prev_compare_inst = NULL;
-  for (int i = 0; i < num_clauses; i++) {
+  for (int i = 0; i < num_smi_clauses; i++) {
     CaseClause* clause = clauses->at(i);
     if (clause->is_default()) continue;

@@ -2623,6 +2632,7 @@
     }

     // Build instructions for current subgraph.
+    ASSERT(clause->IsSmiCompare());
     prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause);
     if (HasStackOverflow()) return;

@@ -2641,34 +2651,53 @@
                                                  last_false_block,
                                                  prev_compare_inst));
   }
+
+  // If we have a non-smi compare clause, we deoptimize after trying
+  // all the previous compares.
+  if (num_smi_clauses < num_clauses) {
+    last_false_block->Finish(new HDeoptimize);
+  }

   // Build statement blocks, connect them to their comparison block and
   // to the previous statement block, if there is a fall-through.
   HSubgraph* previous_subgraph = NULL;
   for (int i = 0; i < num_clauses; i++) {
     CaseClause* clause = clauses->at(i);
-    HSubgraph* subgraph = CreateEmptySubgraph();
-
-    if (clause->is_default()) {
-      // Default clause: Connect it to the last false block.
-      last_false_block->Finish(new HGoto(subgraph->entry_block()));
-    } else {
-      // Connect with the corresponding comparison.
-      HBasicBlock* empty =
-          compare_graphs.at(i)->exit_block()->end()->FirstSuccessor();
-      empty->Finish(new HGoto(subgraph->entry_block()));
+    // Subgraph for the statements of the clause is only created when
+    // it's reachable either from the corresponding compare or as a
+    // fall-through from previous statements.
+    HSubgraph* subgraph = NULL;
+
+    if (i < num_smi_clauses) {
+      if (clause->is_default()) {
+        if (!last_false_block->IsFinished()) {
+          // Default clause: Connect it to the last false block.
+          subgraph = CreateEmptySubgraph();
+          last_false_block->Finish(new HGoto(subgraph->entry_block()));
+        }
+      } else {
+        ASSERT(clause->IsSmiCompare());
+        // Connect with the corresponding comparison.
+        subgraph = CreateEmptySubgraph();
+        HBasicBlock* empty =
+            compare_graphs.at(i)->exit_block()->end()->FirstSuccessor();
+        empty->Finish(new HGoto(subgraph->entry_block()));
+      }
     }

     // Check for fall-through from previous statement block.
     if (previous_subgraph != NULL && previous_subgraph->HasExit()) {
+      if (subgraph == NULL) subgraph = CreateEmptySubgraph();
       previous_subgraph->exit_block()->
           Finish(new HGoto(subgraph->entry_block()));
     }

-    ADD_TO_SUBGRAPH(subgraph, clause->statements());
-    HBasicBlock* break_block = subgraph->BundleBreak(stmt);
-    if (break_block != NULL) {
-      break_block->Finish(new HGoto(single_exit_block));
+    if (subgraph != NULL) {
+      ADD_TO_SUBGRAPH(subgraph, clause->statements());
+      HBasicBlock* break_block = subgraph->BundleBreak(stmt);
+      if (break_block != NULL) {
+        break_block->Finish(new HGoto(single_exit_block));
+      }
     }

     previous_subgraph = subgraph;
@@ -2676,7 +2705,7 @@

   // If the last statement block has a fall-through, connect it to the
   // single exit block.
-  if (previous_subgraph->HasExit()) {
+  if (previous_subgraph != NULL && previous_subgraph->HasExit()) {
     previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
   }

=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Dec 15 08:14:29 2010 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Dec 15 09:11:11 2010
@@ -745,10 +745,9 @@
   Breakable nested_statement(this, stmt);
   SetStatementPosition(stmt);

-  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
-
   // Keep the switch value on the stack until a case matches.
   VisitForStackValue(stmt->tag());
+  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);

   ZoneList<CaseClause*>* clauses = stmt->cases();
   CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Tue Dec 14 10:53:48 2010
+++ /branches/bleeding_edge/src/runtime.cc      Wed Dec 15 09:11:11 2010
@@ -6876,12 +6876,17 @@
     if (CompileOptimized(function, ast_id) && function->IsOptimized()) {
       DeoptimizationInputData* data = DeoptimizationInputData::cast(
           function->code()->deoptimization_data());
-      if (FLAG_trace_osr) {
-        PrintF("[on-stack replacement offset %d in optimized code]\n",
+      if (data->OsrPcOffset()->value() >= 0) {
+        if (FLAG_trace_osr) {
+          PrintF("[on-stack replacement offset %d in optimized code]\n",
                data->OsrPcOffset()->value());
-      }
-      ASSERT(data->OsrAstId()->value() == ast_id);
-      ASSERT(data->OsrPcOffset()->value() >= 0);
+        }
+        ASSERT(data->OsrAstId()->value() == ast_id);
+      } else {
+        // We may never generate the desired OSR entry if we emit an
+        // early deoptimize.
+        succeeded = false;
+      }
     } else {
       succeeded = false;
     }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to