Revision: 18348
Author:   [email protected]
Date:     Wed Dec 18 11:58:58 2013 UTC
Log: Hydrogen: Re-use regular comparisons infrastructure for switch statements

[email protected]

Review URL: https://codereview.chromium.org/111573003
http://code.google.com/p/v8/source/detail?r=18348

Modified:
 /branches/bleeding_edge/src/ast.h
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/hydrogen.h
 /branches/bleeding_edge/src/type-info.cc
 /branches/bleeding_edge/src/type-info.h
 /branches/bleeding_edge/src/typing.cc

=======================================
--- /branches/bleeding_edge/src/ast.h   Wed Dec 18 11:44:38 2013 UTC
+++ /branches/bleeding_edge/src/ast.h   Wed Dec 18 11:58:58 2013 UTC
@@ -1144,15 +1144,10 @@
   void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
     tag_ = tag;
     cases_ = cases;
-    switch_type_ = UNKNOWN_SWITCH;
   }

   Expression* tag() const { return tag_; }
   ZoneList<CaseClause*>* cases() const { return cases_; }
-
- enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH, GENERIC_SWITCH };
-  SwitchType switch_type() const { return switch_type_; }
- void set_switch_type(SwitchType switch_type) { switch_type_ = switch_type; }

  protected:
   SwitchStatement(Isolate* isolate, ZoneStringList* labels, int pos)
@@ -1163,7 +1158,6 @@
  private:
   Expression* tag_;
   ZoneList<CaseClause*>* cases_;
-  SwitchType switch_type_;
 };


=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Wed Dec 18 10:40:26 2013 UTC
+++ /branches/bleeding_edge/src/code-stubs.h    Wed Dec 18 11:58:58 2013 UTC
@@ -1176,10 +1176,6 @@
                              CompareIC::State* handler_state,
                              Token::Value* op);

-  static CompareIC::State CompareState(int minor_key) {
- return static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
-  }
-
   virtual InlineCacheState GetICState();

  private:
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Wed Dec 18 11:44:38 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Wed Dec 18 11:58:58 2013 UTC
@@ -4136,8 +4136,7 @@
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());

-  // We only optimize switch statements with smi-literal smi comparisons,
-  // with a bounded number of clauses.
+  // We only optimize switch statements with a bounded number of clauses.
   const int kCaseClauseLimit = 128;
   ZoneList<CaseClause*>* clauses = stmt->cases();
   int clause_count = clauses->length();
@@ -4145,29 +4144,11 @@
   if (clause_count > kCaseClauseLimit) {
     return Bailout(kSwitchStatementTooManyClauses);
   }
-
-  ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH);

   CHECK_ALIVE(VisitForValue(stmt->tag()));
   Add<HSimulate>(stmt->EntryId());
   HValue* tag_value = Top();
-
-  HUnaryControlInstruction* string_check = NULL;
-  HBasicBlock* not_string_block = NULL;
-
-  // Test switch's tag value if all clauses are string literals
-  if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
-    HBasicBlock* first_test_block = graph()->CreateBasicBlock();
-    not_string_block = graph()->CreateBasicBlock();
-    string_check = New<HIsStringAndBranch>(
-        tag_value, first_test_block, not_string_block);
-    FinishCurrentBlock(string_check);
-
-    set_current_block(not_string_block);
-    Drop(1);  // tag_value
-
-    set_current_block(first_test_block);
-  }
+  Handle<Type> tag_type = stmt->tag()->bounds().lower;

   // 1. Build all the tests, with dangling true branches
   BailoutId default_id = BailoutId::None();
@@ -4183,35 +4164,12 @@
     CHECK_ALIVE(VisitForValue(clause->label()));
     HValue* label_value = Pop();

-    HControlInstruction* compare;
-
-    if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) {
-      if (!clause->compare_type()->Is(Type::Smi())) {
-        Add<HDeoptimize>("Non-smi switch type", Deoptimizer::SOFT);
-      }
-
-      HCompareNumericAndBranch* compare_ =
-          New<HCompareNumericAndBranch>(tag_value,
-                                        label_value,
-                                        Token::EQ_STRICT);
-      compare_->set_observed_input_representation(
-          Representation::Smi(), Representation::Smi());
-      compare = compare_;
-    } else if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
-      compare = New<HStringCompareAndBranch>(tag_value,
-                                             label_value,
-                                             Token::EQ_STRICT);
-    } else {
-      HValue* test = Add<HCompareGeneric>(tag_value,
-                                          label_value,
-                                          Token::EQ_STRICT);
-      if (test->HasObservableSideEffects()) {
-        Push(test);
-        Add<HSimulate>(clause->id(), REMOVABLE_SIMULATE);
-        Drop(1);
-      }
-      compare = New<HBranch>(test);
-    }
+    Handle<Type> label_type = clause->label()->bounds().lower;
+    Handle<Type> combined_type = clause->compare_type();
+    HControlInstruction* compare = BuildCompareInstruction(
+        Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
+ combined_type, stmt->tag()->position(), clause->label()->position(),
+        clause->id());

     HBasicBlock* next_test_block = graph()->CreateBasicBlock();
     HBasicBlock* body_block = graph()->CreateBasicBlock();
@@ -4231,11 +4189,6 @@
   HBasicBlock* last_block = current_block();
   Drop(1);  // tag_value

-  if (not_string_block != NULL) {
-    BailoutId join_id = !default_id.IsNone() ? default_id : stmt->ExitId();
-    last_block = CreateJoin(last_block, not_string_block, join_id);
-  }
-
   // 2. Loop over the clauses and the linked list of tests in lockstep,
   // translating the clause bodies.
   HBasicBlock* fall_through_block = NULL;
@@ -9142,9 +9095,6 @@
   Handle<Type> left_type = expr->left()->bounds().lower;
   Handle<Type> right_type = expr->right()->bounds().lower;
   Handle<Type> combined_type = expr->combined_type();
-  Representation combined_rep = Representation::FromType(combined_type);
-  Representation left_rep = Representation::FromType(left_type);
-  Representation right_rep = Representation::FromType(right_type);

   CHECK_ALIVE(VisitForValue(expr->left()));
   CHECK_ALIVE(VisitForValue(expr->right()));
@@ -9217,35 +9167,55 @@
                      Deoptimizer::SOFT);
combined_type = left_type = right_type = handle(Type::Any(), isolate());
   }
+
+  HControlInstruction* compare = BuildCompareInstruction(
+      op, left, right, left_type, right_type, combined_type,
+      expr->left()->position(), expr->right()->position(), expr->id());
+  if (compare == NULL) return;  // Bailed out.
+  return ast_context()->ReturnControl(compare, expr->id());
+}
+
+
+HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction(
+    Token::Value op,
+    HValue* left,
+    HValue* right,
+    Handle<Type> left_type,
+    Handle<Type> right_type,
+    Handle<Type> combined_type,
+    int left_position,
+    int right_position,
+    BailoutId bailout_id) {
+  Representation left_rep = Representation::FromType(left_type);
+  Representation right_rep = Representation::FromType(right_type);
+  Representation combined_rep = Representation::FromType(combined_type);

   if (combined_type->Is(Type::Receiver())) {
-    switch (op) {
-      case Token::EQ:
-      case Token::EQ_STRICT: {
-        // Can we get away with map check and not instance type check?
-        if (combined_type->IsClass()) {
-          Handle<Map> map = combined_type->AsClass();
-          AddCheckMap(left, map);
-          AddCheckMap(right, map);
-          HCompareObjectEqAndBranch* result =
-              New<HCompareObjectEqAndBranch>(left, right);
-          if (FLAG_emit_opt_code_positions) {
- result->set_operand_position(zone(), 0, expr->left()->position()); - result->set_operand_position(zone(), 1, expr->right()->position());
-          }
-          return ast_context()->ReturnControl(result, expr->id());
-        } else {
-          BuildCheckHeapObject(left);
- Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT);
-          BuildCheckHeapObject(right);
- Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT);
-          HCompareObjectEqAndBranch* result =
-              New<HCompareObjectEqAndBranch>(left, right);
-          return ast_context()->ReturnControl(result, expr->id());
+    if (Token::IsEqualityOp(op)) {
+      // Can we get away with map check and not instance type check?
+      if (combined_type->IsClass()) {
+        Handle<Map> map = combined_type->AsClass();
+        AddCheckMap(left, map);
+        AddCheckMap(right, map);
+        HCompareObjectEqAndBranch* result =
+            New<HCompareObjectEqAndBranch>(left, right);
+        if (FLAG_emit_opt_code_positions) {
+          result->set_operand_position(zone(), 0, left_position);
+          result->set_operand_position(zone(), 1, right_position);
         }
+        return result;
+      } else {
+        BuildCheckHeapObject(left);
+        Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT);
+        BuildCheckHeapObject(right);
+        Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT);
+        HCompareObjectEqAndBranch* result =
+            New<HCompareObjectEqAndBranch>(left, right);
+        return result;
       }
-      default:
-        return Bailout(kUnsupportedNonPrimitiveCompare);
+    } else {
+      Bailout(kUnsupportedNonPrimitiveCompare);
+      return NULL;
     }
   } else if (combined_type->Is(Type::InternalizedString()) &&
              Token::IsEqualityOp(op)) {
@@ -9255,7 +9225,7 @@
Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
     HCompareObjectEqAndBranch* result =
         New<HCompareObjectEqAndBranch>(left, right);
-    return ast_context()->ReturnControl(result, expr->id());
+    return result;
   } else if (combined_type->Is(Type::String())) {
     BuildCheckHeapObject(left);
     Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
@@ -9263,23 +9233,28 @@
     Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
     HStringCompareAndBranch* result =
         New<HStringCompareAndBranch>(left, right, op);
-    return ast_context()->ReturnControl(result, expr->id());
+    return result;
   } else {
     if (combined_rep.IsTagged() || combined_rep.IsNone()) {
-      HCompareGeneric* result = New<HCompareGeneric>(left, right, op);
+      HCompareGeneric* result = Add<HCompareGeneric>(left, right, op);
       result->set_observed_input_representation(1, left_rep);
       result->set_observed_input_representation(2, right_rep);
-      return ast_context()->ReturnInstruction(result, expr->id());
+      if (result->HasObservableSideEffects()) {
+        Push(result);
+        AddSimulate(bailout_id, REMOVABLE_SIMULATE);
+        Drop(1);
+      }
+      // TODO(jkummerow): Can we make this more efficient?
+      HBranch* branch = New<HBranch>(result);
+      return branch;
     } else {
       HCompareNumericAndBranch* result =
           New<HCompareNumericAndBranch>(left, right, op);
       result->set_observed_input_representation(left_rep, right_rep);
       if (FLAG_emit_opt_code_positions) {
-        result->SetOperandPositions(zone(),
-                                    expr->left()->position(),
-                                    expr->right()->position());
+        result->SetOperandPositions(zone(), left_position, right_position);
       }
-      return ast_context()->ReturnControl(result, expr->id());
+      return result;
     }
   }
 }
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Wed Dec  4 09:27:48 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.h      Wed Dec 18 11:58:58 2013 UTC
@@ -2323,6 +2323,15 @@
   void HandleLiteralCompareNil(CompareOperation* expr,
                                Expression* sub_expr,
                                NilValue nil);
+  HControlInstruction* BuildCompareInstruction(Token::Value op,
+                                               HValue* left,
+                                               HValue* right,
+                                               Handle<Type> left_type,
+                                               Handle<Type> right_type,
+                                               Handle<Type> combined_type,
+                                               int left_position,
+                                               int right_position,
+                                               BailoutId bailout_id);

   HInstruction* BuildStringCharCodeAt(HValue* string,
                                       HValue* index);
=======================================
--- /branches/bleeding_edge/src/type-info.cc    Thu Dec 12 14:57:00 2013 UTC
+++ /branches/bleeding_edge/src/type-info.cc    Wed Dec 18 11:58:58 2013 UTC
@@ -318,18 +318,6 @@
   *result = state.GetResultType(isolate());
   *fixed_right_arg = state.fixed_right_arg();
 }
-
-
-Handle<Type> TypeFeedbackOracle::ClauseType(TypeFeedbackId id) {
-  Handle<Object> info = GetInfo(id);
-  Handle<Type> result(Type::None(), isolate_);
-  if (info->IsCode() && Handle<Code>::cast(info)->is_compare_ic_stub()) {
-    Handle<Code> code = Handle<Code>::cast(info);
- CompareIC::State state = ICCompareStub::CompareState(code->stub_info());
-    result = CompareIC::StateToType(isolate_, state);
-  }
-  return result;
-}


 Handle<Type> TypeFeedbackOracle::CountType(TypeFeedbackId id) {
=======================================
--- /branches/bleeding_edge/src/type-info.h     Thu Dec 12 14:57:00 2013 UTC
+++ /branches/bleeding_edge/src/type-info.h     Wed Dec 18 11:58:58 2013 UTC
@@ -303,8 +303,6 @@

   Handle<Type> CountType(TypeFeedbackId id);

-  Handle<Type> ClauseType(TypeFeedbackId id);
-
   Zone* zone() const { return zone_; }
   Isolate* isolate() const { return isolate_; }

=======================================
--- /branches/bleeding_edge/src/typing.cc       Wed Dec 18 10:38:58 2013 UTC
+++ /branches/bleeding_edge/src/typing.cc       Wed Dec 18 11:58:58 2013 UTC
@@ -222,24 +222,23 @@
   RECURSE(Visit(stmt->tag()));

   ZoneList<CaseClause*>* clauses = stmt->cases();
-  SwitchStatement::SwitchType switch_type = stmt->switch_type();
   Effects local_effects(zone());
   bool complex_effects = false;  // True for label effects or fall-through.

   for (int i = 0; i < clauses->length(); ++i) {
     CaseClause* clause = clauses->at(i);
+
     Effects clause_effects = EnterEffects();

     if (!clause->is_default()) {
       Expression* label = clause->label();
-      SwitchStatement::SwitchType label_switch_type =
-          label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH :
-          label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH :
-              SwitchStatement::GENERIC_SWITCH;
-      if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
-        switch_type = label_switch_type;
-      else if (switch_type != label_switch_type)
-        switch_type = SwitchStatement::GENERIC_SWITCH;
+      // Collect type feedback.
+      Handle<Type> tag_type, label_type, combined_type;
+      oracle()->CompareType(clause->CompareId(),
+                            &tag_type, &label_type, &combined_type);
+      NarrowLowerType(stmt->tag(), tag_type);
+      NarrowLowerType(label, label_type);
+      clause->set_compare_type(combined_type);

       RECURSE(Visit(label));
       if (!clause_effects.IsEmpty()) complex_effects = true;
@@ -260,20 +259,6 @@
   } else {
     store_.Seq(local_effects);
   }
-
-  if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
-    switch_type = SwitchStatement::GENERIC_SWITCH;
-  stmt->set_switch_type(switch_type);
-
-  // Collect type feedback.
-  // TODO(rossberg): can we eliminate this special case and extra loop?
-  if (switch_type == SwitchStatement::SMI_SWITCH) {
-    for (int i = 0; i < clauses->length(); ++i) {
-      CaseClause* clause = clauses->at(i);
-      if (!clause->is_default())
- clause->set_compare_type(oracle()->ClauseType(clause->CompareId()));
-    }
-  }
 }


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to