Collect type feedback in separate pass and store it in AST
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 27 May 2013 13:59:20 +0000 (13:59 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 27 May 2013 13:59:20 +0000 (13:59 +0000)
Notes:

- For now, just adds the missing type info fields to the AST nodes directly.
  I'd like to factor that out more nicely in a follow-up CL.

- All type feedback now is uniformly collected through AST nodes'
  RecordTypeFeedback functions. At some point, this logic should be moved
  out of ast.cc.

- The typing pass currently simulates the exact same conditions under
  which feedback was collected in Hydrogen before. That also should be
  made more generic in the future.

- Type information itself is unchanged. Making it more regular is
  yet more future work.

Some additional cleanups:

- Lifted out nested class ObjectLiteral::Property, to enable forward declaration.
- Moved around some auxiliary enums.

R=svenpanne@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14825 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/ast.cc
src/ast.h
src/code-stubs.h
src/compiler.cc
src/compiler.h
src/hydrogen.cc
src/hydrogen.h
src/type-info.cc
src/type-info.h
src/typing.cc [new file with mode: 0644]
src/typing.h [new file with mode: 0644]
tools/gyp/v8.gyp

index d241355fc1b8bf4aa654f790db2cc8bcd2f9efb5..e27feec1a63dbed8f1882d347144ff867664a859 100644 (file)
@@ -30,6 +30,7 @@
 #include <cmath>  // For isfinite.
 #include "builtins.h"
 #include "code-stubs.h"
+#include "contexts.h"
 #include "conversions.h"
 #include "hashmap.h"
 #include "parser.h"
@@ -181,9 +182,9 @@ LanguageMode FunctionLiteral::language_mode() const {
 }
 
 
-ObjectLiteral::Property::Property(Literal* key,
-                                  Expression* value,
-                                  Isolate* isolate) {
+ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
+                                             Expression* value,
+                                             Isolate* isolate) {
   emit_store_ = true;
   key_ = key;
   value_ = value;
@@ -201,7 +202,8 @@ ObjectLiteral::Property::Property(Literal* key,
 }
 
 
-ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
+ObjectLiteralProperty::ObjectLiteralProperty(bool is_getter,
+                                             FunctionLiteral* value) {
   emit_store_ = true;
   value_ = value;
   kind_ = is_getter ? GETTER : SETTER;
@@ -415,6 +417,16 @@ bool FunctionDeclaration::IsInlineable() const {
 // ----------------------------------------------------------------------------
 // Recording of type feedback
 
+void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
+  for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
+}
+
+
+void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
+  to_boolean_types_ = oracle->ToBooleanTypes(test_id());
+}
+
+
 void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle,
                                   Zone* zone) {
   // Record type feedback from the oracle in the AST.
@@ -486,6 +498,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle,
     oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
   }
   store_mode_ = oracle->GetStoreMode(id);
+  type_ = oracle->IncrementType(this);
 }
 
 
@@ -575,6 +588,32 @@ bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
 }
 
 
+Handle<JSObject> Call::GetPrototypeForPrimitiveCheck(
+    CheckType check, Isolate* isolate) {
+  v8::internal::Context* native_context = isolate->context()->native_context();
+  JSFunction* function = NULL;
+  switch (check) {
+    case RECEIVER_MAP_CHECK:
+      UNREACHABLE();
+      break;
+    case STRING_CHECK:
+      function = native_context->string_function();
+      break;
+    case SYMBOL_CHECK:
+      function = native_context->symbol_function();
+      break;
+    case NUMBER_CHECK:
+      function = native_context->number_function();
+      break;
+    case BOOLEAN_CHECK:
+      function = native_context->boolean_function();
+      break;
+  }
+  ASSERT(function != NULL);
+  return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
+}
+
+
 void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
                               CallKind call_kind) {
   is_monomorphic_ = oracle->CallIsMonomorphic(this);
@@ -606,8 +645,7 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
         map = receiver_types_.at(0);
       } else {
         ASSERT(check_type_ != RECEIVER_MAP_CHECK);
-        holder_ = Handle<JSObject>(
-            oracle->GetPrototypeForPrimitiveCheck(check_type_));
+        holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
         map = Handle<Map>(holder_->map());
       }
       is_monomorphic_ = ComputeTarget(map, name);
@@ -622,6 +660,12 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
     target_ = oracle->GetCallNewTarget(this);
     elements_kind_ = oracle->GetCallNewElementsKind(this);
   }
+  Handle<Object> alloc_elements_kind = oracle->GetInfo(CallNewFeedbackId());
+//  if (alloc_elements_kind->IsSmi())
+//    alloc_elements_kind_ = Handle<Smi>::cast(alloc_elements_kind);
+  alloc_elements_kind_ = alloc_elements_kind->IsSmi()
+      ? Handle<Smi>::cast(alloc_elements_kind)
+      : handle(Smi::FromInt(GetInitialFastElementsKind()), oracle->isolate());
 }
 
 
@@ -632,6 +676,30 @@ void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
 }
 
 
+void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
+  type_ = oracle->UnaryType(this);
+}
+
+
+void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
+  oracle->BinaryType(this, &left_type_, &right_type_, &result_type_);
+}
+
+
+void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
+  oracle->CompareType(this, &left_type_, &right_type_, &overall_type_);
+  if (!overall_type_.IsUninitialized() && overall_type_.IsNonPrimitive() &&
+      (op_ == Token::EQ || op_ == Token::EQ_STRICT)) {
+    map_ = oracle->GetCompareMap(this);
+  } else {
+    // May be a compare to nil.
+    map_ = oracle->CompareNilMonomorphicReceiverType(this);
+    if (op_ != Token::EQ_STRICT)
+      compare_nil_types_ = oracle->CompareNilTypes(this);
+  }
+}
+
+
 // ----------------------------------------------------------------------------
 // Implementation of AstVisitor
 
index ad7b119854dad4cc67ce5fd92f84d798bf08af94..4e851f217c8279d6173fd4259ed3fff25fc2dd4c 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -39,6 +39,7 @@
 #include "small-pointer-list.h"
 #include "smart-pointers.h"
 #include "token.h"
+#include "type-info.h"
 #include "utils.h"
 #include "variables.h"
 #include "interface.h"
@@ -373,6 +374,10 @@ class Expression: public AstNode {
     return STANDARD_STORE;
   }
 
+  // TODO(rossberg): this should move to its own AST node eventually.
+  void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
+  byte to_boolean_types() const { return to_boolean_types_; }
+
   BailoutId id() const { return id_; }
   TypeFeedbackId test_id() const { return test_id_; }
 
@@ -382,6 +387,8 @@ class Expression: public AstNode {
         test_id_(GetNextId(isolate)) {}
 
  private:
+  byte to_boolean_types_;
+
   const BailoutId id_;
   const TypeFeedbackId test_id_;
 };
@@ -716,6 +723,7 @@ class IterationStatement: public BreakableStatement {
  private:
   Statement* body_;
   Label continue_target_;
+
   const BailoutId osr_entry_id_;
 };
 
@@ -751,7 +759,9 @@ class DoWhileStatement: public IterationStatement {
 
  private:
   Expression* cond_;
+
   int condition_position_;
+
   const BailoutId continue_id_;
   const BailoutId back_edge_id_;
 };
@@ -788,8 +798,10 @@ class WhileStatement: public IterationStatement {
 
  private:
   Expression* cond_;
+
   // True if there is a function literal subexpression in the condition.
   bool may_have_function_literal_;
+
   const BailoutId body_id_;
 };
 
@@ -843,9 +855,11 @@ class ForStatement: public IterationStatement {
   Statement* init_;
   Expression* cond_;
   Statement* next_;
+
   // True if there is a function literal subexpression in the condition.
   bool may_have_function_literal_;
   Variable* loop_variable_;
+
   const BailoutId continue_id_;
   const BailoutId body_id_;
 };
@@ -859,6 +873,7 @@ class ForInStatement: public IterationStatement {
     IterationStatement::Initialize(body);
     each_ = each;
     enumerable_ = enumerable;
+    for_in_type_ = SLOW_FOR_IN;
   }
 
   Expression* each() const { return each_; }
@@ -870,6 +885,9 @@ class ForInStatement: public IterationStatement {
   BailoutId PrepareId() const { return prepare_id_; }
 
   TypeFeedbackId ForInFeedbackId() const { return reuse(PrepareId()); }
+  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+  enum ForInType { FAST_FOR_IN, SLOW_FOR_IN };
+  ForInType for_in_type() const { return for_in_type_; }
 
  protected:
   ForInStatement(Isolate* isolate, ZoneStringList* labels)
@@ -883,6 +901,9 @@ class ForInStatement: public IterationStatement {
  private:
   Expression* each_;
   Expression* enumerable_;
+
+  ForInType for_in_type_;
+
   const BailoutId body_id_;
   const BailoutId prepare_id_;
 };
@@ -1023,11 +1044,16 @@ class SwitchStatement: public BreakableStatement {
   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)
       : BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
@@ -1037,6 +1063,7 @@ class SwitchStatement: public BreakableStatement {
  private:
   Expression* tag_;
   ZoneList<CaseClause*>* cases_;
+  SwitchType switch_type_;
 };
 
 
@@ -1282,52 +1309,55 @@ class MaterializedLiteral: public Expression {
 };
 
 
+// Property is used for passing information
+// about an object literal's properties from the parser
+// to the code generator.
+class ObjectLiteralProperty: public ZoneObject {
+ public:
+  enum Kind {
+    CONSTANT,              // Property with constant value (compile time).
+    COMPUTED,              // Property with computed value (execution time).
+    MATERIALIZED_LITERAL,  // Property value is a materialized literal.
+    GETTER, SETTER,        // Property is an accessor function.
+    PROTOTYPE              // Property is __proto__.
+  };
+
+  ObjectLiteralProperty(Literal* key, Expression* value, Isolate* isolate);
+
+  Literal* key() { return key_; }
+  Expression* value() { return value_; }
+  Kind kind() { return kind_; }
+
+  // Type feedback information.
+  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+  bool IsMonomorphic() { return !receiver_type_.is_null(); }
+  Handle<Map> GetReceiverType() { return receiver_type_; }
+
+  bool IsCompileTimeValue();
+
+  void set_emit_store(bool emit_store);
+  bool emit_store();
+
+ protected:
+  template<class> friend class AstNodeFactory;
+
+  ObjectLiteralProperty(bool is_getter, FunctionLiteral* value);
+  void set_key(Literal* key) { key_ = key; }
+
+ private:
+  Literal* key_;
+  Expression* value_;
+  Kind kind_;
+  bool emit_store_;
+  Handle<Map> receiver_type_;
+};
+
+
 // An object literal has a boilerplate object that is used
 // for minimizing the work when constructing it at runtime.
 class ObjectLiteral: public MaterializedLiteral {
  public:
-  // Property is used for passing information
-  // about an object literal's properties from the parser
-  // to the code generator.
-  class Property: public ZoneObject {
-   public:
-    enum Kind {
-      CONSTANT,              // Property with constant value (compile time).
-      COMPUTED,              // Property with computed value (execution time).
-      MATERIALIZED_LITERAL,  // Property value is a materialized literal.
-      GETTER, SETTER,        // Property is an accessor function.
-      PROTOTYPE              // Property is __proto__.
-    };
-
-    Property(Literal* key, Expression* value, Isolate* isolate);
-
-    Literal* key() { return key_; }
-    Expression* value() { return value_; }
-    Kind kind() { return kind_; }
-
-    // Type feedback information.
-    void RecordTypeFeedback(TypeFeedbackOracle* oracle);
-    bool IsMonomorphic() { return !receiver_type_.is_null(); }
-    Handle<Map> GetReceiverType() { return receiver_type_; }
-
-    bool IsCompileTimeValue();
-
-    void set_emit_store(bool emit_store);
-    bool emit_store();
-
-   protected:
-    template<class> friend class AstNodeFactory;
-
-    Property(bool is_getter, FunctionLiteral* value);
-    void set_key(Literal* key) { key_ = key; }
-
-   private:
-    Literal* key_;
-    Expression* value_;
-    Kind kind_;
-    bool emit_store_;
-    Handle<Map> receiver_type_;
-  };
+  typedef ObjectLiteralProperty Property;
 
   DECLARE_NODE_TYPE(ObjectLiteral)
 
@@ -1590,6 +1620,11 @@ class Call: public Expression {
 
   BailoutId ReturnId() const { return return_id_; }
 
+  // TODO(rossberg): this should really move somewhere else (and be merged with
+  // various similar methods in objets.cc), but for now...
+  static Handle<JSObject> GetPrototypeForPrimitiveCheck(
+      CheckType check, Isolate* isolate);
+
 #ifdef DEBUG
   // Used to assert that the FullCodeGenerator records the return site.
   bool return_is_recorded_;
@@ -1636,10 +1671,11 @@ class CallNew: public Expression {
   TypeFeedbackId CallNewFeedbackId() const { return reuse(id()); }
   void RecordTypeFeedback(TypeFeedbackOracle* oracle);
   virtual bool IsMonomorphic() { return is_monomorphic_; }
-  Handle<JSFunction> target() { return target_; }
+  Handle<JSFunction> target() const { return target_; }
+  ElementsKind elements_kind() const { return elements_kind_; }
+  Handle<Smi> allocation_elements_kind() const { return alloc_elements_kind_; }
 
   BailoutId ReturnId() const { return return_id_; }
-  ElementsKind elements_kind() const { return elements_kind_; }
 
  protected:
   CallNew(Isolate* isolate,
@@ -1651,8 +1687,8 @@ class CallNew: public Expression {
         arguments_(arguments),
         pos_(pos),
         is_monomorphic_(false),
-        return_id_(GetNextId(isolate)),
-        elements_kind_(GetInitialFastElementsKind()) { }
+        elements_kind_(GetInitialFastElementsKind()),
+        return_id_(GetNextId(isolate)) { }
 
  private:
   Expression* expression_;
@@ -1661,9 +1697,10 @@ class CallNew: public Expression {
 
   bool is_monomorphic_;
   Handle<JSFunction> target_;
+  ElementsKind elements_kind_;
+  Handle<Smi> alloc_elements_kind_;
 
   const BailoutId return_id_;
-  ElementsKind elements_kind_;
 };
 
 
@@ -1713,6 +1750,8 @@ class UnaryOperation: public Expression {
   BailoutId MaterializeFalseId() { return materialize_false_id_; }
 
   TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
+  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+  TypeInfo type() const { return type_; }
 
  protected:
   UnaryOperation(Isolate* isolate,
@@ -1733,6 +1772,8 @@ class UnaryOperation: public Expression {
   Expression* expression_;
   int pos_;
 
+  TypeInfo type_;
+
   // For unary not (Token::NOT), the AST ids where true and false will
   // actually be materialized, respectively.
   const BailoutId materialize_true_id_;
@@ -1754,6 +1795,10 @@ class BinaryOperation: public Expression {
   BailoutId RightId() const { return right_id_; }
 
   TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
+  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+  TypeInfo left_type() const { return left_type_; }
+  TypeInfo right_type() const { return right_type_; }
+  TypeInfo result_type() const { return result_type_; }
 
  protected:
   BinaryOperation(Isolate* isolate,
@@ -1775,6 +1820,11 @@ class BinaryOperation: public Expression {
   Expression* left_;
   Expression* right_;
   int pos_;
+
+  TypeInfo left_type_;
+  TypeInfo right_type_;
+  TypeInfo result_type_;
+
   // The short-circuit logical operations need an AST ID for their
   // right-hand subexpression.
   const BailoutId right_id_;
@@ -1804,6 +1854,7 @@ class CountOperation: public Expression {
   virtual KeyedAccessStoreMode GetStoreMode() {
     return store_mode_;
   }
+  TypeInfo type() const { return type_; }
 
   BailoutId AssignmentId() const { return assignment_id_; }
 
@@ -1832,6 +1883,8 @@ class CountOperation: public Expression {
   bool is_monomorphic_ : 1;
   KeyedAccessStoreMode store_mode_ : 5;  // Windows treats as signed,
                                          // must have extra bit.
+  TypeInfo type_;
+
   Expression* expression_;
   int pos_;
   const BailoutId assignment_id_;
@@ -1851,6 +1904,12 @@ class CompareOperation: public Expression {
 
   // Type feedback information.
   TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
+  void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+  TypeInfo left_type() const { return left_type_; }
+  TypeInfo right_type() const { return right_type_; }
+  TypeInfo overall_type() const { return overall_type_; }
+  byte compare_nil_types() const { return compare_nil_types_; }
+  Handle<Map> map() const { return map_; }
 
   // Match special cases.
   bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
@@ -1876,6 +1935,12 @@ class CompareOperation: public Expression {
   Expression* left_;
   Expression* right_;
   int pos_;
+
+  TypeInfo left_type_;
+  TypeInfo right_type_;
+  TypeInfo overall_type_;
+  byte compare_nil_types_;
+  Handle<Map> map_;
 };
 
 
index 08ccafdb0ecce4a8e4d4faa7f3d133634d977141..901751f8c2104369b00cabcf7b052d235aacaaa7 100644 (file)
@@ -672,7 +672,7 @@ class ArrayConstructorStub: public PlatformCodeStub {
 
 class MathPowStub: public PlatformCodeStub {
  public:
-  enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK};
+  enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK };
 
   explicit MathPowStub(ExponentType exponent_type)
       : exponent_type_(exponent_type) { }
index 504575803dcaaf9dd733a98b52aeacfa4070960a..b799a5a6ef1808b11d1b7f190b69a74be4cfa0f9 100644 (file)
@@ -36,6 +36,7 @@
 #include "deoptimizer.h"
 #include "full-codegen.h"
 #include "gdb-jit.h"
+#include "typing.h"
 #include "hydrogen.h"
 #include "isolate-inl.h"
 #include "lithium.h"
@@ -361,11 +362,11 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
     PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
     isolate()->GetHTracer()->TraceCompilation(info());
   }
-  Handle<Context> native_context(
-      info()->closure()->context()->native_context());
-  oracle_ = new(info()->zone()) TypeFeedbackOracle(
-      code, native_context, isolate(), info()->zone());
-  graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info(), oracle_);
+
+  // Type-check the function.
+  AstTyper::Type(info());
+
+  graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info());
 
   Timer t(this, &time_taken_to_create_graph_);
   graph_ = graph_builder_->CreateGraph();
index dbb513ccdb49c8c967cd26ac81a6e2955739de23..8e6d295996d049f1c01dde6424c3ba3ae220d819 100644 (file)
@@ -449,7 +449,6 @@ class OptimizingCompiler: public ZoneObject {
  public:
   explicit OptimizingCompiler(CompilationInfo* info)
       : info_(info),
-        oracle_(NULL),
         graph_builder_(NULL),
         graph_(NULL),
         chunk_(NULL),
@@ -478,7 +477,6 @@ class OptimizingCompiler: public ZoneObject {
 
  private:
   CompilationInfo* info_;
-  TypeFeedbackOracle* oracle_;
   HOptimizedGraphBuilder* graph_builder_;
   HGraph* graph_;
   LChunk* chunk_;
index ae01e7010121a1b042663221b03cb999b3e2bdc0..b3d12c0f845956ef41ce34ac7bfe62968cbf196f 100644 (file)
@@ -39,6 +39,7 @@
 #include "scopeinfo.h"
 #include "scopes.h"
 #include "stub-cache.h"
+#include "typing.h"
 
 #if V8_TARGET_ARCH_IA32
 #include "ia32/lithium-codegen-ia32.h"
@@ -1934,11 +1935,10 @@ HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object,
 }
 
 
-HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
-                                               TypeFeedbackOracle* oracle)
+HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
     : HGraphBuilder(info),
       function_state_(NULL),
-      initial_function_state_(this, info, oracle, NORMAL_RETURN),
+      initial_function_state_(this, info, NORMAL_RETURN),
       ast_context_(NULL),
       break_scope_(NULL),
       inlined_count_(0),
@@ -3510,11 +3510,9 @@ void HGraph::ComputeMinusZeroChecks() {
 // a (possibly inlined) function.
 FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
                              CompilationInfo* info,
-                             TypeFeedbackOracle* oracle,
                              InliningKind inlining_kind)
     : owner_(owner),
       compilation_info_(info),
-      oracle_(oracle),
       call_context_(NULL),
       inlining_kind_(inlining_kind),
       function_return_(NULL),
@@ -3531,11 +3529,9 @@ FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
       if_false->MarkAsInlineReturnTarget();
       TestContext* outer_test_context = TestContext::cast(owner->ast_context());
       Expression* cond = outer_test_context->condition();
-      TypeFeedbackOracle* outer_oracle = outer_test_context->oracle();
       // The AstContext constructor pushed on the context stack.  This newed
       // instance is the reason that AstContext can't be BASE_EMBEDDED.
-      test_context_ =
-          new TestContext(owner, cond, outer_oracle, if_true, if_false);
+      test_context_ = new TestContext(owner, cond, if_true, if_false);
     } else {
       function_return_ = owner->graph()->CreateBasicBlock();
       function_return()->MarkAsInlineReturnTarget();
@@ -3769,8 +3765,7 @@ void TestContext::BuildBranch(HValue* value) {
   }
   HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
   HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
-  TypeFeedbackId test_id = condition()->test_id();
-  ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
+  ToBooleanStub::Types expected(condition()->to_boolean_types());
   HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
   builder->current_block()->Finish(test);
 
@@ -3825,7 +3820,7 @@ void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) {
 void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
                                              HBasicBlock* true_block,
                                              HBasicBlock* false_block) {
-  TestContext for_test(this, expr, oracle(), true_block, false_block);
+  TestContext for_test(this, expr, true_block, false_block);
   Visit(expr);
 }
 
@@ -4834,9 +4829,8 @@ void HOptimizedGraphBuilder::VisitContinueStatement(
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   int drop_extra = 0;
-  HBasicBlock* continue_block = break_scope()->Get(stmt->target(),
-                                                   CONTINUE,
-                                                   &drop_extra);
+  HBasicBlock* continue_block = break_scope()->Get(
+      stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
   Drop(drop_extra);
   current_block()->Goto(continue_block);
   set_current_block(NULL);
@@ -4848,9 +4842,8 @@ void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   int drop_extra = 0;
-  HBasicBlock* break_block = break_scope()->Get(stmt->target(),
-                                                BREAK,
-                                                &drop_extra);
+  HBasicBlock* break_block = break_scope()->Get(
+      stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
   Drop(drop_extra);
   current_block()->Goto(break_block);
   set_current_block(NULL);
@@ -4941,6 +4934,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
+
   // We only optimize switch statements with smi-literal smi comparisons,
   // with a bounded number of clauses.
   const int kCaseClauseLimit = 128;
@@ -4950,6 +4944,11 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
     return Bailout("SwitchStatement: too many clauses");
   }
 
+  ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH);
+  if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) {
+    return Bailout("SwitchStatement: mixed or non-literal switch labels");
+  }
+
   HValue* context = environment()->LookupContext();
 
   CHECK_ALIVE(VisitForValue(stmt->tag()));
@@ -4957,34 +4956,11 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
   HValue* tag_value = Pop();
   HBasicBlock* first_test_block = current_block();
 
-  SwitchType switch_type = UNKNOWN_SWITCH;
-
-  // 1. Extract clause type
-  for (int i = 0; i < clause_count; ++i) {
-    CaseClause* clause = clauses->at(i);
-    if (clause->is_default()) continue;
-
-    if (switch_type == UNKNOWN_SWITCH) {
-      if (clause->label()->IsSmiLiteral()) {
-        switch_type = SMI_SWITCH;
-      } else if (clause->label()->IsStringLiteral()) {
-        switch_type = STRING_SWITCH;
-      } else {
-        return Bailout("SwitchStatement: non-literal switch label");
-      }
-    } else if ((switch_type == STRING_SWITCH &&
-                !clause->label()->IsStringLiteral()) ||
-               (switch_type == SMI_SWITCH &&
-                !clause->label()->IsSmiLiteral())) {
-      return Bailout("SwitchStatement: mixed label types are not supported");
-    }
-  }
-
   HUnaryControlInstruction* string_check = NULL;
   HBasicBlock* not_string_block = NULL;
 
   // Test switch's tag value if all clauses are string literals
-  if (switch_type == STRING_SWITCH) {
+  if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
     string_check = new(zone()) HIsStringAndBranch(tag_value);
     first_test_block = graph()->CreateBasicBlock();
     not_string_block = graph()->CreateBasicBlock();
@@ -4996,7 +4972,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
     set_current_block(first_test_block);
   }
 
-  // 2. Build all the tests, with dangling true branches
+  // 1. Build all the tests, with dangling true branches
   BailoutId default_id = BailoutId::None();
   for (int i = 0; i < clause_count; ++i) {
     CaseClause* clause = clauses->at(i);
@@ -5004,9 +4980,6 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
       default_id = clause->EntryId();
       continue;
     }
-    if (switch_type == SMI_SWITCH) {
-      clause->RecordTypeFeedback(oracle());
-    }
 
     // Generate a compare and branch.
     CHECK_ALIVE(VisitForValue(clause->label()));
@@ -5017,7 +4990,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 
     HControlInstruction* compare;
 
-    if (switch_type == SMI_SWITCH) {
+    if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) {
       if (!clause->IsSmiCompare()) {
         // Finish with deoptimize and add uses of enviroment values to
         // account for invisible uses.
@@ -5055,7 +5028,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
     last_block = CreateJoin(last_block, not_string_block, join_id);
   }
 
-  // 3. Loop over the clauses and the linked list of tests in lockstep,
+  // 2. Loop over the clauses and the linked list of tests in lockstep,
   // translating the clause bodies.
   HBasicBlock* curr_test_block = first_test_block;
   HBasicBlock* fall_through_block = NULL;
@@ -5342,7 +5315,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
     return Bailout("ForInStatement optimization is disabled");
   }
 
-  if (!oracle()->IsForInFastCase(stmt)) {
+  if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
     return Bailout("ForInStatement is not fast case");
   }
 
@@ -5483,8 +5456,7 @@ void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
     Code* unoptimized_code, FunctionLiteral* expr) {
   int start_position = expr->start_position();
-  RelocIterator it(unoptimized_code);
-  for (; !it.done(); it.next()) {
+  for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
     RelocInfo* rinfo = it.rinfo();
     if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
     Object* obj = rinfo->target_object();
@@ -5505,8 +5477,7 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   Handle<SharedFunctionInfo> shared_info =
-      SearchSharedFunctionInfo(info()->shared_info()->code(),
-                               expr);
+      SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
   if (shared_info.is_null()) {
     shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
   }
@@ -5938,7 +5909,6 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
       case ObjectLiteral::Property::COMPUTED:
         if (key->handle()->IsInternalizedString()) {
           if (property->emit_store()) {
-            property->RecordTypeFeedback(oracle());
             CHECK_ALIVE(VisitForValue(value));
             HValue* value = Pop();
             Handle<Map> map = property->GetReceiverType();
@@ -6474,7 +6444,6 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
   Property* prop = expr->target()->AsProperty();
   ASSERT(prop != NULL);
-  expr->RecordTypeFeedback(oracle(), zone());
   CHECK_ALIVE(VisitForValue(prop->obj()));
 
   if (prop->key()->IsPropertyName()) {
@@ -6672,8 +6641,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
     return ast_context()->ReturnValue(Pop());
 
   } else if (prop != NULL) {
-    prop->RecordTypeFeedback(oracle(), zone());
-
     if (prop->key()->IsPropertyName()) {
       // Named property.
       CHECK_ALIVE(VisitForValue(prop->obj()));
@@ -6755,7 +6722,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
       Push(load);
       if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
 
-
       CHECK_ALIVE(VisitForValue(expr->value()));
       HValue* right = Pop();
       HValue* left = Pop();
@@ -6766,7 +6732,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
         AddSimulate(operation->id(), REMOVABLE_SIMULATE);
       }
 
-      expr->RecordTypeFeedback(oracle(), zone());
       HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
                                RelocInfo::kNoPosition,
                                true,  // is_store
@@ -7506,7 +7471,6 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
-  expr->RecordTypeFeedback(oracle(), zone());
 
   if (TryArgumentsAccess(expr)) return;
 
@@ -7997,19 +7961,15 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
   // After this point, we've made a decision to inline this function (so
   // TryInline should always return true).
 
-  // Save the pending call context and type feedback oracle. Set up new ones
-  // for the inlined function.
+  // Type-check the inlined function.
   ASSERT(target_shared->has_deoptimization_support());
-  Handle<Code> unoptimized_code(target_shared->code());
-  TypeFeedbackOracle target_oracle(
-      unoptimized_code,
-      Handle<Context>(target->context()->native_context()),
-      isolate(),
-      zone());
+  AstTyper::Type(&target_info);
+
+  // Save the pending call context. Set up new one for the inlined function.
   // The function state is new-allocated because we need to delete it
   // in two different places.
   FunctionState* target_state = new FunctionState(
-      this, &target_info, &target_oracle, inlining_kind);
+      this, &target_info, inlining_kind);
 
   HConstant* undefined = graph()->GetConstantUndefined();
   bool undefined_receiver = HEnvironment::UseUndefinedReceiver(
@@ -8083,6 +8043,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
   // Update inlined nodes count.
   inlined_count_ += nodes_added;
 
+  Handle<Code> unoptimized_code(target_shared->code());
   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
   Handle<TypeFeedbackInfo> type_info(
       TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
@@ -8299,7 +8260,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
         HValue* context = environment()->LookupContext();
         ASSERT(!expr->holder().is_null());
         AddInstruction(new(zone()) HCheckPrototypeMaps(
-            oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
+            Call::GetPrototypeForPrimitiveCheck(STRING_CHECK,
+                expr->holder()->GetIsolate()),
             expr->holder(),
             zone()));
         HInstruction* char_code =
@@ -8614,8 +8576,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     }
 
     // Named function call.
-    expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
-
     if (TryCallApply(expr)) return;
 
     CHECK_ALIVE(VisitForValue(prop->obj()));
@@ -8681,7 +8641,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     }
 
   } else {
-    expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
     VariableProxy* proxy = expr->expression()->AsVariableProxy();
     bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
 
@@ -8817,7 +8776,6 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
-  expr->RecordTypeFeedback(oracle());
   int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
   HValue* context = environment()->LookupContext();
 
@@ -8877,8 +8835,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
       // information that happened after crankshaft won't be lost.  The right
       // way to do that is to begin passing the cell to the type feedback oracle
       // instead of just the value in the cell. Do this in a follow-up checkin.
-      Handle<Object> feedback = oracle()->GetInfo(expr->CallNewFeedbackId());
-      ASSERT(feedback->IsSmi());
+      Handle<Smi> feedback = expr->allocation_elements_kind();
       Handle<JSGlobalPropertyCell> cell =
           isolate()->factory()->NewJSGlobalPropertyCell(feedback);
 
@@ -8966,6 +8923,7 @@ void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
   }
 }
 
+
 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
   Property* prop = expr->expression()->AsProperty();
   VariableProxy* proxy = expr->expression()->AsVariableProxy();
@@ -9022,7 +8980,7 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
   HValue* context = environment()->LookupContext();
   HInstruction* instr =
       HMul::New(zone(), context, value, graph()->GetConstantMinus1());
-  TypeInfo info = oracle()->UnaryType(expr);
+  TypeInfo info = expr->type();
   Representation rep = ToRepresentation(info);
   if (info.IsUninitialized()) {
     AddSoftDeoptimize();
@@ -9039,7 +8997,7 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) {
 void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
   CHECK_ALIVE(VisitForValue(expr->expression()));
   HValue* value = Pop();
-  TypeInfo info = oracle()->UnaryType(expr);
+  TypeInfo info = expr->type();
   if (info.IsUninitialized()) {
     AddSoftDeoptimize();
   }
@@ -9096,7 +9054,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
     bool returns_original_input,
     CountOperation* expr) {
   // The input to the count operation is on top of the expression stack.
-  TypeInfo info = oracle()->IncrementType(expr);
+  TypeInfo info = expr->type();
   Representation rep = ToRepresentation(info);
   if (rep.IsTagged()) {
     rep = Representation::Integer32();
@@ -9210,7 +9168,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
   } else {
     // Argument of the count operation is a property.
     ASSERT(prop != NULL);
-    prop->RecordTypeFeedback(oracle(), zone());
 
     if (prop->key()->IsPropertyName()) {
       // Named property.
@@ -9293,7 +9250,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
       after = BuildIncrement(returns_original_input, expr);
       input = environment()->ExpressionStackAt(0);
 
-      expr->RecordTypeFeedback(oracle(), zone());
       HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
                                RelocInfo::kNoPosition,
                                true,  // is_store
@@ -9402,8 +9358,10 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
     HValue* left,
     HValue* right) {
   HValue* context = environment()->LookupContext();
-  TypeInfo left_info, right_info, result_info, combined_info;
-  oracle()->BinaryType(expr, &left_info, &right_info, &result_info);
+  TypeInfo left_info = expr->left_type();
+  TypeInfo right_info = expr->right_type();
+  TypeInfo result_info = expr->result_type();
+  TypeInfo combined_info;
   Representation left_rep = ToRepresentation(left_info);
   Representation right_rep = ToRepresentation(right_info);
   Representation result_rep = ToRepresentation(result_info);
@@ -9561,8 +9519,7 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
     // We need an extra block to maintain edge-split form.
     HBasicBlock* empty_block = graph()->CreateBasicBlock();
     HBasicBlock* eval_right = graph()->CreateBasicBlock();
-    TypeFeedbackId test_id = expr->left()->test_id();
-    ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
+    ToBooleanStub::Types expected(expr->left()->to_boolean_types());
     HBranch* test = is_logical_and
       ? new(zone()) HBranch(left_value, eval_right, empty_block, expected)
       : new(zone()) HBranch(left_value, empty_block, eval_right, expected);
@@ -9730,16 +9687,17 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     return ast_context()->ReturnControl(instr, expr->id());
   }
 
-  TypeInfo left_type, right_type, overall_type_info;
-  oracle()->CompareType(expr, &left_type, &right_type, &overall_type_info);
-  Representation combined_rep = ToRepresentation(overall_type_info);
+  TypeInfo left_type = expr->left_type();
+  TypeInfo right_type = expr->right_type();
+  TypeInfo overall_type = expr->overall_type();
+  Representation combined_rep = ToRepresentation(overall_type);
   Representation left_rep = ToRepresentation(left_type);
   Representation right_rep = ToRepresentation(right_type);
   // Check if this expression was ever executed according to type feedback.
   // Note that for the special typeof/null/undefined cases we get unknown here.
-  if (overall_type_info.IsUninitialized()) {
+  if (overall_type.IsUninitialized()) {
     AddSoftDeoptimize();
-    overall_type_info = left_type = right_type = TypeInfo::Unknown();
+    overall_type = left_type = right_type = TypeInfo::Unknown();
   }
 
   CHECK_ALIVE(VisitForValue(expr->left()));
@@ -9811,12 +9769,12 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     HIn* result = new(zone()) HIn(context, left, right);
     result->set_position(expr->position());
     return ast_context()->ReturnInstruction(result, expr->id());
-  } else if (overall_type_info.IsNonPrimitive()) {
+  } else if (overall_type.IsNonPrimitive()) {
     switch (op) {
       case Token::EQ:
       case Token::EQ_STRICT: {
         // Can we get away with map check and not instance type check?
-        Handle<Map> map = oracle()->GetCompareMap(expr);
+        Handle<Map> map = expr->map();
         if (!map.is_null()) {
           AddCheckMapsWithTransitions(left, map);
           AddCheckMapsWithTransitions(right, map);
@@ -9838,7 +9796,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
       default:
         return Bailout("Unsupported non-primitive compare");
     }
-  } else if (overall_type_info.IsInternalizedString() &&
+  } else if (overall_type.IsInternalizedString() &&
              Token::IsEqualityOp(op)) {
     BuildCheckNonSmi(left);
     AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
@@ -9876,18 +9834,15 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
   EqualityKind kind =
       expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
   HIfContinuation continuation;
-  TypeFeedbackId id = expr->CompareOperationFeedbackId();
   CompareNilICStub::Types types;
   if (kind == kStrictEquality) {
     types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
                                     CompareNilICStub::UNDEFINED);
   } else {
-    types = CompareNilICStub::Types(oracle()->CompareNilTypes(id));
-    if (types.IsEmpty()) {
-      types = CompareNilICStub::Types::FullCompare();
-    }
+    types = CompareNilICStub::Types(expr->compare_nil_types());
+    if (types.IsEmpty()) types = CompareNilICStub::Types::FullCompare();
   }
-  Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
+  Handle<Map> map_handle = expr->map();
   BuildCompareNil(value, kind, types, map_handle,
                   expr->position(), &continuation);
   return ast_context()->ReturnContinuation(&continuation, expr->id());
index 51e1ad0818ba9328a945f34d3e38e4d541f59ef4..3023810cf3f4f6c0d28d30f0dd506b8cbd33b706 100644 (file)
@@ -34,7 +34,6 @@
 #include "ast.h"
 #include "compiler.h"
 #include "hydrogen-instructions.h"
-#include "type-info.h"
 #include "zone.h"
 #include "scopes.h"
 
@@ -792,12 +791,10 @@ class TestContext: public AstContext {
  public:
   TestContext(HOptimizedGraphBuilder* owner,
               Expression* condition,
-              TypeFeedbackOracle* oracle,
               HBasicBlock* if_true,
               HBasicBlock* if_false)
       : AstContext(owner, Expression::kTest),
         condition_(condition),
-        oracle_(oracle),
         if_true_(if_true),
         if_false_(if_false) {
   }
@@ -814,7 +811,6 @@ class TestContext: public AstContext {
   }
 
   Expression* condition() const { return condition_; }
-  TypeFeedbackOracle* oracle() const { return oracle_; }
   HBasicBlock* if_true() const { return if_true_; }
   HBasicBlock* if_false() const { return if_false_; }
 
@@ -824,7 +820,6 @@ class TestContext: public AstContext {
   void BuildBranch(HValue* value);
 
   Expression* condition_;
-  TypeFeedbackOracle* oracle_;
   HBasicBlock* if_true_;
   HBasicBlock* if_false_;
 };
@@ -834,12 +829,10 @@ class FunctionState {
  public:
   FunctionState(HOptimizedGraphBuilder* owner,
                 CompilationInfo* info,
-                TypeFeedbackOracle* oracle,
                 InliningKind inlining_kind);
   ~FunctionState();
 
   CompilationInfo* compilation_info() { return compilation_info_; }
-  TypeFeedbackOracle* oracle() { return oracle_; }
   AstContext* call_context() { return call_context_; }
   InliningKind inlining_kind() const { return inlining_kind_; }
   HBasicBlock* function_return() { return function_return_; }
@@ -865,7 +858,6 @@ class FunctionState {
   HOptimizedGraphBuilder* owner_;
 
   CompilationInfo* compilation_info_;
-  TypeFeedbackOracle* oracle_;
 
   // During function inlining, expression context of the call being
   // inlined. NULL when not inlining.
@@ -1353,9 +1345,6 @@ class HGraphBuilder {
 
 class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
  public:
-  enum BreakType { BREAK, CONTINUE };
-  enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
-
   // A class encapsulating (lazily-allocated) break and continue blocks for
   // a breakable statement.  Separated from BreakAndContinueScope so that it
   // can have a separate lifetime.
@@ -1400,6 +1389,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
     BreakAndContinueScope* next() { return next_; }
 
     // Search the break stack for a break or continue target.
+    enum BreakType { BREAK, CONTINUE };
     HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
 
    private:
@@ -1408,7 +1398,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
     BreakAndContinueScope* next_;
   };
 
-  HOptimizedGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
+  explicit HOptimizedGraphBuilder(CompilationInfo* info);
 
   virtual bool BuildGraph();
 
@@ -1426,8 +1416,6 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
                           HBasicBlock* second,
                           BailoutId join_id);
 
-  TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
-
   FunctionState* function_state() const { return function_state_; }
 
   void VisitDeclarations(ZoneList<Declaration*>* declarations);
index 53866c16cb5941a0f39408ae2ddeead023b3837b..3a83c41bb8fea807a5106c6b1e4490add1826e22 100644 (file)
@@ -184,10 +184,11 @@ bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(
 }
 
 
-bool TypeFeedbackOracle::IsForInFastCase(ForInStatement* stmt) {
+byte TypeFeedbackOracle::ForInType(ForInStatement* stmt) {
   Handle<Object> value = GetInfo(stmt->ForInFeedbackId());
   return value->IsSmi() &&
-      Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker;
+      Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker
+          ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN;
 }
 
 
@@ -221,8 +222,8 @@ Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
 
 
 Handle<Map> TypeFeedbackOracle::CompareNilMonomorphicReceiverType(
-    TypeFeedbackId id) {
-  Handle<Object> maybe_code = GetInfo(id);
+    CompareOperation* expr) {
+  Handle<Object> maybe_code = GetInfo(expr->CompareOperationFeedbackId());
   if (maybe_code->IsCode()) {
     Map* map = Handle<Code>::cast(maybe_code)->FindFirstMap();
     if (map == NULL) return Handle<Map>();
@@ -296,31 +297,6 @@ CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
 }
 
 
-Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
-    CheckType check) {
-  JSFunction* function = NULL;
-  switch (check) {
-    case RECEIVER_MAP_CHECK:
-      UNREACHABLE();
-      break;
-    case STRING_CHECK:
-      function = native_context_->string_function();
-      break;
-    case SYMBOL_CHECK:
-      function = native_context_->symbol_function();
-      break;
-    case NUMBER_CHECK:
-      function = native_context_->number_function();
-      break;
-    case BOOLEAN_CHECK:
-      function = native_context_->boolean_function();
-      break;
-  }
-  ASSERT(function != NULL);
-  return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
-}
-
-
 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
   return Handle<JSFunction>::cast(GetInfo(expr->CallFeedbackId()));
 }
@@ -641,8 +617,8 @@ byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) {
 }
 
 
-byte TypeFeedbackOracle::CompareNilTypes(TypeFeedbackId id) {
-  Handle<Object> object = GetInfo(id);
+byte TypeFeedbackOracle::CompareNilTypes(CompareOperation* expr) {
+  Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId());
   if (object->IsCode() &&
       Handle<Code>::cast(object)->is_compare_nil_ic_stub()) {
     return Handle<Code>::cast(object)->compare_nil_types();
index d6d958d56d2c4cf7588518cbad77af41ec52b431..6c7e31acdb6d071e433d9d37d377e79eaeb9dfd4 100644 (file)
@@ -29,7 +29,6 @@
 #define V8_TYPE_INFO_H_
 
 #include "allocation.h"
-#include "ast.h"
 #include "globals.h"
 #include "zone-inl.h"
 
@@ -232,6 +231,8 @@ class ICStub;
 class Property;
 class SmallMapList;
 class UnaryOperation;
+class ObjectLiteral;
+class ObjectLiteralProperty;
 
 
 class TypeFeedbackOracle: public ZoneObject {
@@ -248,13 +249,15 @@ class TypeFeedbackOracle: public ZoneObject {
   bool StoreIsPolymorphic(TypeFeedbackId ast_id);
   bool CallIsMonomorphic(Call* expr);
   bool CallNewIsMonomorphic(CallNew* expr);
-  bool ObjectLiteralStoreIsMonomorphic(ObjectLiteral::Property* prop);
+  bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop);
 
-  bool IsForInFastCase(ForInStatement* expr);
+  // TODO(1571) We can't use ForInStatement::ForInType as the return value due
+  // to various cycles in our headers.
+  byte ForInType(ForInStatement* expr);
 
   Handle<Map> LoadMonomorphicReceiverType(Property* expr);
   Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId id);
-  Handle<Map> CompareNilMonomorphicReceiverType(TypeFeedbackId id);
+  Handle<Map> CompareNilMonomorphicReceiverType(CompareOperation* expr);
 
   KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id);
 
@@ -278,26 +281,24 @@ class TypeFeedbackOracle: public ZoneObject {
   void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
 
   CheckType GetCallCheckType(Call* expr);
-  Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
-
   Handle<JSFunction> GetCallTarget(Call* expr);
   Handle<JSFunction> GetCallNewTarget(CallNew* expr);
   ElementsKind GetCallNewElementsKind(CallNew* expr);
 
-  Handle<Map> GetObjectLiteralStoreMap(ObjectLiteral::Property* prop);
+  Handle<Map> GetObjectLiteralStoreMap(ObjectLiteralProperty* prop);
 
   bool LoadIsBuiltin(Property* expr, Builtins::Name id);
   bool LoadIsStub(Property* expr, ICStub* stub);
 
   // TODO(1571) We can't use ToBooleanStub::Types as the return value because
-  // of various cylces in our headers. Death to tons of implementations in
+  // of various cycles in our headers. Death to tons of implementations in
   // headers!! :-P
   byte ToBooleanTypes(TypeFeedbackId ast_id);
 
   // TODO(1571) We can't use CompareNilICStub::Types as the return value because
   // of various cylces in our headers. Death to tons of implementations in
   // headers!! :-P
-  byte CompareNilTypes(TypeFeedbackId ast_id);
+  byte CompareNilTypes(CompareOperation* expr);
 
   // Get type information for arithmetic operations and compares.
   TypeInfo UnaryType(UnaryOperation* expr);
@@ -314,6 +315,7 @@ class TypeFeedbackOracle: public ZoneObject {
   TypeInfo IncrementType(CountOperation* expr);
 
   Zone* zone() const { return zone_; }
+  Isolate* isolate() const { return isolate_; }
 
  private:
   void CollectReceiverTypes(TypeFeedbackId ast_id,
diff --git a/src/typing.cc b/src/typing.cc
new file mode 100644 (file)
index 0000000..c2d418f
--- /dev/null
@@ -0,0 +1,512 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "typing.h"
+
+#include "v8.h"
+#include "parser.h"  // for CompileTimeValue; TODO(rossberg): should move
+#include "scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+AstTyper::AstTyper(CompilationInfo* info)
+    : info_(info),
+      oracle_(
+          Handle<Code>(info->closure()->shared()->code()),
+          Handle<Context>(info->closure()->context()->native_context()),
+          info->isolate(),
+          info->zone()) {
+  InitializeAstVisitor();
+}
+
+
+#define CHECK_ALIVE(call)                     \
+  do {                                        \
+    call;                                     \
+    if (visitor->HasStackOverflow()) return;  \
+  } while (false)
+
+
+void AstTyper::Type(CompilationInfo* info) {
+  AstTyper* visitor = new(info->zone()) AstTyper(info);
+  Scope* scope = info->scope();
+
+  // Handle implicit declaration of the function name in named function
+  // expressions before other declarations.
+  if (scope->is_function_scope() && scope->function() != NULL) {
+    CHECK_ALIVE(visitor->VisitVariableDeclaration(scope->function()));
+  }
+  CHECK_ALIVE(visitor->VisitDeclarations(scope->declarations()));
+  CHECK_ALIVE(visitor->VisitStatements(info->function()->body()));
+}
+
+
+#undef CHECK_ALIVE
+#define CHECK_ALIVE(call)            \
+  do {                               \
+    call;                            \
+    if (HasStackOverflow()) return;  \
+  } while (false)
+
+
+void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
+  ASSERT(!HasStackOverflow());
+  for (int i = 0; i < stmts->length(); ++i) {
+    Statement* stmt = stmts->at(i);
+    CHECK_ALIVE(Visit(stmt));
+  }
+}
+
+
+void AstTyper::VisitBlock(Block* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(VisitStatements(stmt->statements()));
+}
+
+
+void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->expression()));
+}
+
+
+void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitIfStatement(IfStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->condition()));
+  CHECK_ALIVE(Visit(stmt->then_statement()));
+  CHECK_ALIVE(Visit(stmt->else_statement()));
+
+  if (!stmt->condition()->ToBooleanIsTrue() &&
+      !stmt->condition()->ToBooleanIsFalse()) {
+    stmt->condition()->RecordToBooleanTypeFeedback(oracle());
+  }
+}
+
+
+void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->expression()));
+
+  // TODO(rossberg): we only need this for inlining into test contexts...
+  stmt->expression()->RecordToBooleanTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitWithStatement(WithStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(stmt->expression());
+  CHECK_ALIVE(stmt->statement());
+}
+
+
+void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->tag()));
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  SwitchStatement::SwitchType switch_type = stmt->switch_type();
+  for (int i = 0; i < clauses->length(); ++i) {
+    CaseClause* clause = clauses->at(i);
+    if (!clause->is_default()) {
+      Expression* label = clause->label();
+      CHECK_ALIVE(Visit(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;
+    }
+    CHECK_ALIVE(VisitStatements(clause->statements()));
+  }
+  if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
+    switch_type = SwitchStatement::GENERIC_SWITCH;
+  stmt->set_switch_type(switch_type);
+
+  // 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->RecordTypeFeedback(oracle());
+    }
+  }
+}
+
+
+void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->body()));
+  CHECK_ALIVE(Visit(stmt->cond()));
+
+  if (!stmt->cond()->ToBooleanIsTrue()) {
+    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+  }
+}
+
+
+void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->cond()));
+  CHECK_ALIVE(Visit(stmt->body()));
+
+  if (!stmt->cond()->ToBooleanIsTrue()) {
+    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+  }
+}
+
+
+void AstTyper::VisitForStatement(ForStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  if (stmt->init() != NULL) {
+    CHECK_ALIVE(Visit(stmt->init()));
+  }
+  if (stmt->cond() != NULL) {
+    CHECK_ALIVE(Visit(stmt->cond()));
+
+    stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+  }
+  CHECK_ALIVE(Visit(stmt->body()));
+  if (stmt->next() != NULL) {
+    CHECK_ALIVE(Visit(stmt->next()));
+  }
+}
+
+
+void AstTyper::VisitForInStatement(ForInStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->enumerable()));
+  CHECK_ALIVE(Visit(stmt->body()));
+
+  stmt->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->try_block()));
+  CHECK_ALIVE(Visit(stmt->catch_block()));
+}
+
+
+void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->try_block()));
+  CHECK_ALIVE(Visit(stmt->finally_block()));
+}
+
+
+void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitConditional(Conditional* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->condition()));
+  CHECK_ALIVE(Visit(expr->then_expression()));
+  CHECK_ALIVE(Visit(expr->else_expression()));
+
+  expr->condition()->RecordToBooleanTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitVariableProxy(VariableProxy* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitLiteral(Literal* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
+  ASSERT(!HasStackOverflow());
+  ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
+  for (int i = 0; i < properties->length(); ++i) {
+    ObjectLiteral::Property* prop = properties->at(i);
+    CHECK_ALIVE(Visit(prop->value()));
+
+    if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
+        !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
+        prop->kind() == ObjectLiteral::Property::COMPUTED) {
+      if (prop->key()->handle()->IsInternalizedString() && prop->emit_store())
+        prop->RecordTypeFeedback(oracle());
+    }
+  }
+}
+
+
+void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
+  ASSERT(!HasStackOverflow());
+  ZoneList<Expression*>* values = expr->values();
+  for (int i = 0; i < values->length(); ++i) {
+    Expression* value = values->at(i);
+    CHECK_ALIVE(Visit(value));
+  }
+}
+
+
+void AstTyper::VisitAssignment(Assignment* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->target()));
+  CHECK_ALIVE(Visit(expr->value()));
+
+  // TODO(rossberg): Can we clean this up?
+  if (expr->is_compound()) {
+    CHECK_ALIVE(Visit(expr->binary_operation()));
+
+    Expression* target = expr->target();
+    Property* prop = target->AsProperty();
+    if (prop != NULL) {
+      prop->RecordTypeFeedback(oracle(), zone());
+      if (!prop->key()->IsPropertyName())  // i.e., keyed
+        expr->RecordTypeFeedback(oracle(), zone());
+    }
+    return;
+  }
+  if (expr->target()->AsProperty())
+    expr->RecordTypeFeedback(oracle(), zone());
+}
+
+
+void AstTyper::VisitYield(Yield* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->generator_object()));
+  CHECK_ALIVE(Visit(expr->expression()));
+}
+
+
+void AstTyper::VisitThrow(Throw* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->exception()));
+}
+
+
+void AstTyper::VisitProperty(Property* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->obj()));
+  CHECK_ALIVE(Visit(expr->key()));
+
+  expr->RecordTypeFeedback(oracle(), zone());
+}
+
+
+void AstTyper::VisitCall(Call* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->expression()));
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    CHECK_ALIVE(Visit(arg));
+  }
+
+  Expression* callee = expr->expression();
+  Property* prop = callee->AsProperty();
+  if (prop != NULL) {
+    if (prop->key()->IsPropertyName())
+      expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
+  } else {
+    expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
+  }
+}
+
+
+void AstTyper::VisitCallNew(CallNew* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->expression()));
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    CHECK_ALIVE(Visit(arg));
+  }
+
+  expr->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitCallRuntime(CallRuntime* expr) {
+  ASSERT(!HasStackOverflow());
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    CHECK_ALIVE(Visit(arg));
+  }
+}
+
+
+void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->expression()));
+
+  expr->RecordTypeFeedback(oracle());
+  if (expr->op() == Token::NOT) {
+    // TODO(rossberg): only do in test or value context.
+    expr->expression()->RecordToBooleanTypeFeedback(oracle());
+  }
+}
+
+
+void AstTyper::VisitCountOperation(CountOperation* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->expression()));
+
+  expr->RecordTypeFeedback(oracle(), zone());
+  Property* prop = expr->expression()->AsProperty();
+  if (prop != NULL) {
+    prop->RecordTypeFeedback(oracle(), zone());
+  }
+}
+
+
+void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->left()));
+  CHECK_ALIVE(Visit(expr->right()));
+
+  expr->RecordTypeFeedback(oracle());
+  if (expr->op() == Token::OR || expr->op() == Token::AND) {
+    expr->left()->RecordToBooleanTypeFeedback(oracle());
+  }
+}
+
+
+void AstTyper::VisitCompareOperation(CompareOperation* expr) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(expr->left()));
+  CHECK_ALIVE(Visit(expr->right()));
+
+  expr->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitThisFunction(ThisFunction* expr) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
+  ASSERT(!HasStackOverflow());
+  for (int i = 0; i < decls->length(); ++i) {
+    Declaration* decl = decls->at(i);
+    CHECK_ALIVE(Visit(decl));
+  }
+}
+
+
+void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(declaration->fun()));
+}
+
+
+void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(declaration->module()));
+}
+
+
+void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(declaration->module()));
+}
+
+
+void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(module->body()));
+}
+
+
+void AstTyper::VisitModuleVariable(ModuleVariable* module) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModulePath(ModulePath* module) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(module->module()));
+}
+
+
+void AstTyper::VisitModuleUrl(ModuleUrl* module) {
+  ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
+  ASSERT(!HasStackOverflow());
+  CHECK_ALIVE(Visit(stmt->body()));
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/typing.h b/src/typing.h
new file mode 100644 (file)
index 0000000..d8708c2
--- /dev/null
@@ -0,0 +1,77 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_TYPING_H_
+#define V8_TYPING_H_
+
+#include "v8.h"
+
+#include "allocation.h"
+#include "ast.h"
+#include "compiler.h"
+#include "type-info.h"
+#include "zone.h"
+#include "scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+class AstTyper: public AstVisitor {
+ public:
+  static void Type(CompilationInfo* info);
+
+  void* operator new(size_t size, Zone* zone) {
+    return zone->New(static_cast<int>(size));
+  }
+  void operator delete(void* pointer, Zone* zone) { }
+  void operator delete(void* pointer) { }
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+
+ private:
+  explicit AstTyper(CompilationInfo* info);
+
+  CompilationInfo* info_;
+  TypeFeedbackOracle oracle_;
+
+  TypeFeedbackOracle* oracle() { return &oracle_; }
+  Zone* zone() const { return info_->zone(); }
+
+  void VisitDeclarations(ZoneList<Declaration*>* declarations);
+  void VisitStatements(ZoneList<Statement*>* statements);
+
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  DISALLOW_COPY_AND_ASSIGN(AstTyper);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_TYPING_H_
index e2ca4ed4352d2563003272ee782de56ae322b7bf..f0eedafd0977181da3d9b74795eb9c154b792d54 100644 (file)
         '../../src/transitions.h',
         '../../src/type-info.cc',
         '../../src/type-info.h',
+        '../../src/typing.cc',
+        '../../src/typing.h',
         '../../src/unbound-queue-inl.h',
         '../../src/unbound-queue.h',
         '../../src/unicode-inl.h',