Adding visitors to regurgitate expression types or reset them.
authorbradnelson <bradnelson@google.com>
Mon, 24 Aug 2015 17:16:38 +0000 (10:16 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 24 Aug 2015 17:16:49 +0000 (17:16 +0000)
Adding an AstExpressionVisitor to touch each expression node in
an AST.

Adding TypingReseter to clear the slate after a failed asm.js
validation that has set partial typing information.

Adding a ExpressionTypeCollector to walk the expressions
in an AST and emit them as a string for testing.

Adding tests of the above.

LOG=N
BUG= https://code.google.com/p/v8/issues/detail?id=4203
TEST=test-typing-reset,test-ast-expression-visitor
R=rossberg@chromium.org,titzer@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30336}

12 files changed:
BUILD.gn
src/ast-expression-visitor.cc [new file with mode: 0644]
src/ast-expression-visitor.h [new file with mode: 0644]
src/typing-reset.cc [new file with mode: 0644]
src/typing-reset.h [new file with mode: 0644]
test/cctest/cctest.gyp
test/cctest/expression-type-collector-macros.h [new file with mode: 0644]
test/cctest/expression-type-collector.cc [new file with mode: 0644]
test/cctest/expression-type-collector.h [new file with mode: 0644]
test/cctest/test-ast-expression-visitor.cc [new file with mode: 0644]
test/cctest/test-typing-reset.cc [new file with mode: 0644]
tools/gyp/v8.gyp

index 03f7d54..0f20932 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -643,6 +643,8 @@ source_set("v8_base") {
     "src/assembler.h",
     "src/assert-scope.h",
     "src/assert-scope.cc",
+    "src/ast-expression-visitor.cc",
+    "src/ast-expression-visitor.h",
     "src/ast-literal-reindexer.cc",
     "src/ast-literal-reindexer.h",
     "src/ast-numbering.cc",
@@ -1209,6 +1211,8 @@ source_set("v8_base") {
     "src/types-inl.h",
     "src/types.cc",
     "src/types.h",
+    "src/typing-reset.cc",
+    "src/typing-reset.h",
     "src/typing.cc",
     "src/typing.h",
     "src/unbound-queue-inl.h",
diff --git a/src/ast-expression-visitor.cc b/src/ast-expression-visitor.cc
new file mode 100644 (file)
index 0000000..08f2950
--- /dev/null
@@ -0,0 +1,337 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/ast-expression-visitor.h"
+
+#include "src/ast.h"
+#include "src/codegen.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define RECURSE(call)               \
+  do {                              \
+    DCHECK(!HasStackOverflow());    \
+    call;                           \
+    if (HasStackOverflow()) return; \
+  } while (false)
+
+
+#define RECURSE_EXPRESSION(call)    \
+  do {                              \
+    DCHECK(!HasStackOverflow());    \
+    ++depth_;                       \
+    call;                           \
+    --depth_;                       \
+    if (HasStackOverflow()) return; \
+  } while (false)
+
+
+AstExpressionVisitor::AstExpressionVisitor(CompilationInfo* info)
+    : compilation_info_(info), depth_(0) {
+  InitializeAstVisitor(info->isolate(), info->zone());
+}
+
+
+void AstExpressionVisitor::Run() {
+  RECURSE(VisitFunctionLiteral(compilation_info_->literal()));
+}
+
+
+void AstExpressionVisitor::VisitVariableDeclaration(VariableDeclaration* decl) {
+}
+
+
+void AstExpressionVisitor::VisitFunctionDeclaration(FunctionDeclaration* decl) {
+  RECURSE(Visit(decl->fun()));
+}
+
+
+void AstExpressionVisitor::VisitImportDeclaration(ImportDeclaration* decl) {}
+
+
+void AstExpressionVisitor::VisitExportDeclaration(ExportDeclaration* decl) {}
+
+
+void AstExpressionVisitor::VisitStatements(ZoneList<Statement*>* stmts) {
+  for (int i = 0; i < stmts->length(); ++i) {
+    Statement* stmt = stmts->at(i);
+    RECURSE(Visit(stmt));
+    if (stmt->IsJump()) break;
+  }
+}
+
+
+void AstExpressionVisitor::VisitBlock(Block* stmt) {
+  RECURSE(VisitStatements(stmt->statements()));
+}
+
+
+void AstExpressionVisitor::VisitExpressionStatement(ExpressionStatement* stmt) {
+  RECURSE(Visit(stmt->expression()));
+}
+
+
+void AstExpressionVisitor::VisitEmptyStatement(EmptyStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitIfStatement(IfStatement* stmt) {
+  RECURSE(Visit(stmt->condition()));
+  RECURSE(Visit(stmt->then_statement()));
+  RECURSE(Visit(stmt->else_statement()));
+}
+
+
+void AstExpressionVisitor::VisitContinueStatement(ContinueStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitBreakStatement(BreakStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitReturnStatement(ReturnStatement* stmt) {
+  RECURSE(Visit(stmt->expression()));
+}
+
+
+void AstExpressionVisitor::VisitWithStatement(WithStatement* stmt) {
+  RECURSE(stmt->expression());
+  RECURSE(stmt->statement());
+}
+
+
+void AstExpressionVisitor::VisitSwitchStatement(SwitchStatement* stmt) {
+  RECURSE(Visit(stmt->tag()));
+
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+
+  for (int i = 0; i < clauses->length(); ++i) {
+    CaseClause* clause = clauses->at(i);
+    Expression* label = clause->label();
+    RECURSE(Visit(label));
+    ZoneList<Statement*>* stmts = clause->statements();
+    RECURSE(VisitStatements(stmts));
+  }
+}
+
+
+void AstExpressionVisitor::VisitCaseClause(CaseClause* clause) {
+  UNREACHABLE();
+}
+
+
+void AstExpressionVisitor::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  RECURSE(Visit(stmt->body()));
+  RECURSE(Visit(stmt->cond()));
+}
+
+
+void AstExpressionVisitor::VisitWhileStatement(WhileStatement* stmt) {
+  RECURSE(Visit(stmt->cond()));
+  RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForStatement(ForStatement* stmt) {
+  RECURSE(Visit(stmt->init()));
+  RECURSE(Visit(stmt->cond()));
+  RECURSE(Visit(stmt->next()));
+  RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForInStatement(ForInStatement* stmt) {
+  RECURSE(Visit(stmt->enumerable()));
+  RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitForOfStatement(ForOfStatement* stmt) {
+  RECURSE(Visit(stmt->iterable()));
+  RECURSE(Visit(stmt->body()));
+}
+
+
+void AstExpressionVisitor::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  RECURSE(Visit(stmt->try_block()));
+  RECURSE(Visit(stmt->catch_block()));
+}
+
+
+void AstExpressionVisitor::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  RECURSE(Visit(stmt->try_block()));
+  RECURSE(Visit(stmt->finally_block()));
+}
+
+
+void AstExpressionVisitor::VisitDebuggerStatement(DebuggerStatement* stmt) {}
+
+
+void AstExpressionVisitor::VisitFunctionLiteral(FunctionLiteral* expr) {
+  Scope* scope = expr->scope();
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(VisitDeclarations(scope->declarations()));
+  RECURSE_EXPRESSION(VisitStatements(expr->body()));
+}
+
+
+void AstExpressionVisitor::VisitNativeFunctionLiteral(
+    NativeFunctionLiteral* expr) {}
+
+
+void AstExpressionVisitor::VisitConditional(Conditional* expr) {
+  RECURSE(Visit(expr->condition()));
+  RECURSE(Visit(expr->then_expression()));
+  RECURSE(Visit(expr->else_expression()));
+}
+
+
+void AstExpressionVisitor::VisitVariableProxy(VariableProxy* expr) {
+  VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitLiteral(Literal* expr) {
+  VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitRegExpLiteral(RegExpLiteral* expr) {
+  VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitObjectLiteral(ObjectLiteral* expr) {
+  VisitExpression(expr);
+  ZoneList<ObjectLiteralProperty*>* props = expr->properties();
+  for (int i = 0; i < props->length(); ++i) {
+    ObjectLiteralProperty* prop = props->at(i);
+    RECURSE_EXPRESSION(Visit(prop->value()));
+  }
+}
+
+
+void AstExpressionVisitor::VisitArrayLiteral(ArrayLiteral* expr) {
+  VisitExpression(expr);
+  ZoneList<Expression*>* values = expr->values();
+  for (int i = 0; i < values->length(); ++i) {
+    Expression* value = values->at(i);
+    RECURSE_EXPRESSION(Visit(value));
+  }
+}
+
+
+void AstExpressionVisitor::VisitAssignment(Assignment* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->target()));
+  RECURSE_EXPRESSION(Visit(expr->value()));
+}
+
+
+void AstExpressionVisitor::VisitYield(Yield* expr) {
+  RECURSE(Visit(expr->generator_object()));
+  RECURSE(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitThrow(Throw* expr) {
+  RECURSE(Visit(expr->exception()));
+}
+
+
+void AstExpressionVisitor::VisitProperty(Property* expr) {
+  RECURSE(Visit(expr->obj()));
+  RECURSE(Visit(expr->key()));
+}
+
+
+void AstExpressionVisitor::VisitCall(Call* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->expression()));
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    RECURSE_EXPRESSION(Visit(arg));
+  }
+}
+
+
+void AstExpressionVisitor::VisitCallNew(CallNew* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->expression()));
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    RECURSE_EXPRESSION(Visit(arg));
+  }
+}
+
+
+void AstExpressionVisitor::VisitCallRuntime(CallRuntime* expr) {
+  VisitExpression(expr);
+  ZoneList<Expression*>* args = expr->arguments();
+  for (int i = 0; i < args->length(); ++i) {
+    Expression* arg = args->at(i);
+    RECURSE_EXPRESSION(Visit(arg));
+  }
+}
+
+
+void AstExpressionVisitor::VisitUnaryOperation(UnaryOperation* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitCountOperation(CountOperation* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->expression()));
+}
+
+
+void AstExpressionVisitor::VisitBinaryOperation(BinaryOperation* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->left()));
+  RECURSE_EXPRESSION(Visit(expr->right()));
+}
+
+
+void AstExpressionVisitor::VisitCompareOperation(CompareOperation* expr) {
+  VisitExpression(expr);
+  RECURSE_EXPRESSION(Visit(expr->left()));
+  RECURSE_EXPRESSION(Visit(expr->right()));
+}
+
+
+void AstExpressionVisitor::VisitThisFunction(ThisFunction* expr) {
+  VisitExpression(expr);
+}
+
+
+void AstExpressionVisitor::VisitDeclarations(ZoneList<Declaration*>* decls) {
+  for (int i = 0; i < decls->length(); ++i) {
+    Declaration* decl = decls->at(i);
+    RECURSE(Visit(decl));
+  }
+}
+
+
+void AstExpressionVisitor::VisitClassLiteral(ClassLiteral* expr) {}
+
+
+void AstExpressionVisitor::VisitSpread(Spread* expr) {}
+
+
+void AstExpressionVisitor::VisitSuperPropertyReference(
+    SuperPropertyReference* expr) {}
+
+
+void AstExpressionVisitor::VisitSuperCallReference(SuperCallReference* expr) {}
+}
+
+
+}  // namespace v8::internal
diff --git a/src/ast-expression-visitor.h b/src/ast-expression-visitor.h
new file mode 100644 (file)
index 0000000..37960e0
--- /dev/null
@@ -0,0 +1,49 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_AST_EXPRESSION_VISITOR_H_
+#define V8_AST_EXPRESSION_VISITOR_H_
+
+#include "src/allocation.h"
+#include "src/ast.h"
+#include "src/effects.h"
+#include "src/scopes.h"
+#include "src/type-info.h"
+#include "src/types.h"
+#include "src/zone.h"
+
+namespace v8 {
+namespace internal {
+
+// A Visitor over a CompilationInfo's AST that invokes
+// VisitExpression on each expression node.
+
+class AstExpressionVisitor : public AstVisitor {
+ public:
+  explicit AstExpressionVisitor(CompilationInfo* info);
+  void Run();
+
+ protected:
+  virtual void VisitExpression(Expression* expression) = 0;
+  int depth() { return depth_; }
+
+ private:
+  void VisitDeclarations(ZoneList<Declaration*>* d) override;
+  void VisitStatements(ZoneList<Statement*>* s) override;
+
+  DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
+
+#define DECLARE_VISIT(type) virtual void Visit##type(type* node) override;
+  AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+  CompilationInfo* compilation_info_;
+  int depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(AstExpressionVisitor);
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_AST_EXPRESSION_VISITOR_H_
diff --git a/src/typing-reset.cc b/src/typing-reset.cc
new file mode 100644 (file)
index 0000000..0650656
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "src/typing-reset.h"
+
+#include "src/ast.h"
+#include "src/codegen.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+TypingReseter::TypingReseter(CompilationInfo* info)
+    : AstExpressionVisitor(info), info_(info) {}
+
+
+void TypingReseter::VisitExpression(Expression* expression) {
+  expression->set_bounds(Bounds::Unbounded(info_->zone()));
+}
+}
+}  // namespace v8::internal
diff --git a/src/typing-reset.h b/src/typing-reset.h
new file mode 100644 (file)
index 0000000..5e7d628
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_TYPING_RESET_H_
+#define V8_TYPING_RESET_H_
+
+#include "src/ast-expression-visitor.h"
+
+namespace v8 {
+namespace internal {
+
+// A Visitor over a CompilationInfo's AST that resets
+// typing bounds back to their default.
+
+class TypingReseter : public AstExpressionVisitor {
+ public:
+  explicit TypingReseter(CompilationInfo* info);
+
+ protected:
+  void VisitExpression(Expression* expression) override;
+
+ private:
+  CompilationInfo* info_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_TYPING_RESET_H_
index 24db817..5199471 100644 (file)
@@ -83,6 +83,8 @@
         'compiler/test-run-variables.cc',
         'compiler/test-simplified-lowering.cc',
         'cctest.cc',
+        'expression-type-collector.cc',
+        'expression-type-collector.h',
         'interpreter/test-bytecode-generator.cc',
         'interpreter/test-interpreter.cc',
         'gay-fixed.cc',
         'test-api-interceptors.cc',
         'test-array-list.cc',
         'test-ast.cc',
+        'test-ast-expression-visitor.cc',
         'test-atomicops.cc',
         'test-bignum.cc',
         'test-bignum-dtoa.cc',
         'test-transitions.cc',
         'test-typedarrays.cc',
         'test-types.cc',
+        'test-typing-reset.cc',
         'test-unbound-queue.cc',
         'test-unboxed-doubles.cc',
         'test-unique.cc',
diff --git a/test/cctest/expression-type-collector-macros.h b/test/cctest/expression-type-collector-macros.h
new file mode 100644 (file)
index 0000000..2dcc1dc
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_EXPRESSION_TYPE_COLLECTOR_MACROS_H_
+#define V8_EXPRESSION_TYPE_COLLECTOR_MACROS_H_
+
+#define CHECK_TYPES_BEGIN \
+  {                       \
+    size_t index = 0;     \
+    int depth = 0;
+
+#define CHECK_TYPES_END          \
+  CHECK_EQ(index, types.size()); \
+  }
+
+#define DEFAULT_TYPE Bounds::Unbounded(handles.main_zone())
+#define INT32_TYPE                            \
+  Bounds(Type::Signed32(handles.main_zone()), \
+         Type::Signed32(handles.main_zone()))
+
+#define CHECK_EXPR(ekind, type)                     \
+  CHECK_LT(index, types.size());                    \
+  CHECK(strcmp(#ekind, types[index].kind) == 0);    \
+  CHECK_EQ(depth, types[index].depth);              \
+  CHECK(type.lower->Is(types[index].bounds.lower)); \
+  CHECK(type.upper->Is(types[index].bounds.upper)); \
+  for (int j = (++depth, ++index, 0); j < 1 ? 1 : (--depth, 0); ++j)
+
+#define CHECK_VAR(vname, type)                                     \
+  CHECK_EXPR(VariableProxy, type);                                 \
+  CHECK_EQ(#vname, std::string(types[index - 1].name->raw_data(),  \
+                               types[index - 1].name->raw_data() + \
+                                   types[index - 1].name->byte_length()));
+
+#endif  // V8_EXPRESSION_TYPE_COLLECTOR_MACROS_H_
diff --git a/test/cctest/expression-type-collector.cc b/test/cctest/expression-type-collector.cc
new file mode 100644 (file)
index 0000000..b64638b
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+
+#include "test/cctest/expression-type-collector.h"
+
+#include "src/ast.h"
+#include "src/codegen.h"
+#include "src/scopes.h"
+
+namespace v8 {
+namespace internal {
+namespace {
+
+struct {
+  AstNode::NodeType type;
+  const char* name;
+} NodeTypeNameList[] = {
+#define DECLARE_VISIT(type)   \
+  { AstNode::k##type, #type } \
+  ,
+    AST_NODE_LIST(DECLARE_VISIT)
+#undef DECLARE_VISIT
+};
+}
+
+
+ExpressionTypeCollector::ExpressionTypeCollector(
+    CompilationInfo* info, ZoneVector<ExpressionTypeEntry>* dst)
+    : AstExpressionVisitor(info), result_(dst) {}
+
+
+void ExpressionTypeCollector::Run() {
+  result_->clear();
+  AstExpressionVisitor::Run();
+}
+
+
+void ExpressionTypeCollector::VisitExpression(Expression* expression) {
+  ExpressionTypeEntry e;
+  e.depth = depth();
+  VariableProxy* proxy = expression->AsVariableProxy();
+  if (proxy) {
+    e.name = proxy->raw_name();
+  }
+  e.bounds = expression->bounds();
+  AstNode::NodeType type = expression->node_type();
+  e.kind = "unknown";
+  for (size_t i = 0; i < arraysize(NodeTypeNameList); ++i) {
+    if (NodeTypeNameList[i].type == type) {
+      e.kind = NodeTypeNameList[i].name;
+      break;
+    }
+  }
+  result_->push_back(e);
+}
+}
+}
diff --git a/test/cctest/expression-type-collector.h b/test/cctest/expression-type-collector.h
new file mode 100644 (file)
index 0000000..4cf4e47
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_EXPRESSION_TYPE_COLLECTOR_H_
+#define V8_EXPRESSION_TYPE_COLLECTOR_H_
+
+#include "src/ast-expression-visitor.h"
+
+namespace v8 {
+namespace internal {
+
+// A Visitor over a CompilationInfo's AST that collects
+// a human readable string summarizing structure and types.
+// Used for testing of the typing information attached to the
+// expression nodes of an AST.
+
+struct ExpressionTypeEntry {
+  int depth;
+  const char* kind;
+  const AstRawString* name;
+  Bounds bounds;
+};
+
+class ExpressionTypeCollector : public AstExpressionVisitor {
+ public:
+  ExpressionTypeCollector(CompilationInfo* info,
+                          ZoneVector<ExpressionTypeEntry>* dst);
+  void Run();
+
+ protected:
+  void VisitExpression(Expression* expression);
+
+ private:
+  ZoneVector<ExpressionTypeEntry>* result_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_EXPRESSION_TYPE_COLLECTOR_H_
diff --git a/test/cctest/test-ast-expression-visitor.cc b/test/cctest/test-ast-expression-visitor.cc
new file mode 100644 (file)
index 0000000..f270963
--- /dev/null
@@ -0,0 +1,258 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include "src/v8.h"
+
+#include "src/ast.h"
+#include "src/ast-expression-visitor.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/expression-type-collector.h"
+#include "test/cctest/expression-type-collector-macros.h"
+
+using namespace v8::internal;
+
+namespace {
+
+static void CollectTypes(HandleAndZoneScope* handles, const char* source,
+                         ZoneVector<ExpressionTypeEntry>* dst) {
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  i::Handle<i::String> source_code =
+      factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked();
+
+  i::Handle<i::Script> script = factory->NewScript(source_code);
+
+  i::ParseInfo info(handles->main_zone(), script);
+  i::Parser parser(&info);
+  parser.set_allow_harmony_arrow_functions(true);
+  parser.set_allow_harmony_sloppy(true);
+  info.set_global();
+  info.set_lazy(false);
+  info.set_allow_lazy_parsing(false);
+  info.set_toplevel(true);
+
+  i::CompilationInfo compilation_info(&info);
+  CHECK(i::Compiler::ParseAndAnalyze(&info));
+  info.set_literal(
+      info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun());
+
+  ExpressionTypeCollector(&compilation_info, dst).Run();
+}
+}
+
+
+TEST(VisitExpressions) {
+  v8::V8::Initialize();
+  HandleAndZoneScope handles;
+  ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
+  const char test_function[] =
+      "function GeometricMean(stdlib, foreign, buffer) {\n"
+      "  \"use asm\";\n"
+      "\n"
+      "  var exp = stdlib.Math.exp;\n"
+      "  var log = stdlib.Math.log;\n"
+      "  var values = new stdlib.Float64Array(buffer);\n"
+      "\n"
+      "  function logSum(start, end) {\n"
+      "    start = start|0;\n"
+      "    end = end|0;\n"
+      "\n"
+      "    var sum = 0.0, p = 0, q = 0;\n"
+      "\n"
+      "    // asm.js forces byte addressing of the heap by requiring shifting "
+      "by 3\n"
+      "    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {\n"
+      "      sum = sum + +log(values[p>>3]);\n"
+      "    }\n"
+      "\n"
+      "    return +sum;\n"
+      "  }\n"
+      "\n"
+      " function geometricMean(start, end) {\n"
+      "    start = start|0;\n"
+      "    end = end|0;\n"
+      "\n"
+      "    return +exp(+logSum(start, end) / +((end - start)|0));\n"
+      "  }\n"
+      "\n"
+      "  return { geometricMean: geometricMean };\n"
+      "}\n";
+
+  CollectTypes(&handles, test_function, &types);
+  CHECK_TYPES_BEGIN {
+    // function logSum
+    CHECK_EXPR(FunctionLiteral, DEFAULT_TYPE) {
+      CHECK_EXPR(FunctionLiteral, DEFAULT_TYPE) {
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(start, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(start, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(end, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(end, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(sum, DEFAULT_TYPE);
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+        }
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(p, DEFAULT_TYPE);
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+        }
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(q, DEFAULT_TYPE);
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+        }
+        // for (p = start << 3, q = end << 3;
+        CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+          CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+            CHECK_VAR(p, DEFAULT_TYPE);
+            CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+              CHECK_VAR(start, DEFAULT_TYPE);
+              CHECK_EXPR(Literal, DEFAULT_TYPE);
+            }
+          }
+          CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+            CHECK_VAR(q, DEFAULT_TYPE);
+            CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+              CHECK_VAR(end, DEFAULT_TYPE);
+              CHECK_EXPR(Literal, DEFAULT_TYPE);
+            }
+          }
+        }
+        // (p|0) < (q|0);
+        CHECK_EXPR(CompareOperation, DEFAULT_TYPE) {
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(p, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(q, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        // p = (p + 8)|0) {\n"
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(p, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+              CHECK_VAR(p, DEFAULT_TYPE);
+              CHECK_EXPR(Literal, DEFAULT_TYPE);
+            }
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        // sum = sum + +log(values[p>>3]);
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(sum, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(sum, DEFAULT_TYPE);
+            CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+              CHECK_EXPR(Call, DEFAULT_TYPE) {
+                CHECK_VAR(log, DEFAULT_TYPE);
+                CHECK_VAR(values, DEFAULT_TYPE);
+                CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+                  CHECK_VAR(p, DEFAULT_TYPE);
+                  CHECK_EXPR(Literal, DEFAULT_TYPE);
+                }
+              }
+              CHECK_EXPR(Literal, DEFAULT_TYPE);
+            }
+          }
+        }
+        // return +sum;
+        CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+          CHECK_VAR(sum, DEFAULT_TYPE);
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+        }
+      }
+      // function geometricMean
+      CHECK_EXPR(FunctionLiteral, DEFAULT_TYPE) {
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(start, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(start, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+          CHECK_VAR(end, DEFAULT_TYPE);
+          CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+            CHECK_VAR(end, DEFAULT_TYPE);
+            CHECK_EXPR(Literal, DEFAULT_TYPE);
+          }
+        }
+        // return +exp(+logSum(start, end) / +((end - start)|0));
+        CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+          CHECK_EXPR(Call, DEFAULT_TYPE) {
+            CHECK_VAR(exp, DEFAULT_TYPE);
+            CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+              CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+                CHECK_EXPR(Call, DEFAULT_TYPE) {
+                  CHECK_VAR(logSum, DEFAULT_TYPE);
+                  CHECK_VAR(start, DEFAULT_TYPE);
+                  CHECK_VAR(end, DEFAULT_TYPE);
+                }
+                CHECK_EXPR(Literal, DEFAULT_TYPE);
+              }
+              CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+                CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+                  CHECK_EXPR(BinaryOperation, DEFAULT_TYPE) {
+                    CHECK_VAR(end, DEFAULT_TYPE);
+                    CHECK_VAR(start, DEFAULT_TYPE);
+                  }
+                  CHECK_EXPR(Literal, DEFAULT_TYPE);
+                }
+                CHECK_EXPR(Literal, DEFAULT_TYPE);
+              }
+            }
+          }
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+        }
+      }
+      // "use asm";
+      CHECK_EXPR(Literal, DEFAULT_TYPE);
+      // var exp = stdlib.Math.exp;
+      CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+        CHECK_VAR(exp, DEFAULT_TYPE);
+        CHECK_VAR(stdlib, DEFAULT_TYPE);
+        CHECK_EXPR(Literal, DEFAULT_TYPE);
+        CHECK_EXPR(Literal, DEFAULT_TYPE);
+      }
+      // var log = stdlib.Math.log;
+      CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+        CHECK_VAR(log, DEFAULT_TYPE);
+        CHECK_VAR(stdlib, DEFAULT_TYPE);
+        CHECK_EXPR(Literal, DEFAULT_TYPE);
+        CHECK_EXPR(Literal, DEFAULT_TYPE);
+      }
+      // var values = new stdlib.Float64Array(buffer);
+      CHECK_EXPR(Assignment, DEFAULT_TYPE) {
+        CHECK_VAR(values, DEFAULT_TYPE);
+        CHECK_EXPR(CallNew, DEFAULT_TYPE) {
+          CHECK_VAR(stdlib, DEFAULT_TYPE);
+          CHECK_EXPR(Literal, DEFAULT_TYPE);
+          CHECK_VAR(buffer, DEFAULT_TYPE);
+        }
+      }
+      // return { geometricMean: geometricMean };
+      CHECK_EXPR(ObjectLiteral, DEFAULT_TYPE) {
+        CHECK_VAR(geometricMean, DEFAULT_TYPE);
+      }
+    }
+  }
+  CHECK_TYPES_END
+}
diff --git a/test/cctest/test-typing-reset.cc b/test/cctest/test-typing-reset.cc
new file mode 100644 (file)
index 0000000..f92e955
--- /dev/null
@@ -0,0 +1,285 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+
+#include "src/v8.h"
+
+#include "src/ast.h"
+#include "src/ast-expression-visitor.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+#include "src/typing-reset.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/function-tester.h"
+#include "test/cctest/expression-type-collector.h"
+#include "test/cctest/expression-type-collector-macros.h"
+
+using namespace v8::internal;
+
+namespace {
+
+class TypeSetter : public AstExpressionVisitor {
+ public:
+  explicit TypeSetter(CompilationInfo* info) : AstExpressionVisitor(info) {}
+
+ protected:
+  void VisitExpression(Expression* expression) {
+    expression->set_bounds(Bounds(Type::Integral32()));
+  }
+};
+
+
+void CheckAllSame(ZoneVector<ExpressionTypeEntry>& types,
+                  Bounds expected_type) {
+  HandleAndZoneScope handles;
+  CHECK_TYPES_BEGIN {
+    // function logSum
+    CHECK_EXPR(FunctionLiteral, expected_type) {
+      CHECK_EXPR(FunctionLiteral, expected_type) {
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(start, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(start, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(end, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(end, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(sum, expected_type);
+          CHECK_EXPR(Literal, expected_type);
+        }
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(p, expected_type);
+          CHECK_EXPR(Literal, expected_type);
+        }
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(q, expected_type);
+          CHECK_EXPR(Literal, expected_type);
+        }
+        // for (p = start << 3, q = end << 3;
+        CHECK_EXPR(BinaryOperation, expected_type) {
+          CHECK_EXPR(Assignment, expected_type) {
+            CHECK_VAR(p, expected_type);
+            CHECK_EXPR(BinaryOperation, expected_type) {
+              CHECK_VAR(start, expected_type);
+              CHECK_EXPR(Literal, expected_type);
+            }
+          }
+          CHECK_EXPR(Assignment, expected_type) {
+            CHECK_VAR(q, expected_type);
+            CHECK_EXPR(BinaryOperation, expected_type) {
+              CHECK_VAR(end, expected_type);
+              CHECK_EXPR(Literal, expected_type);
+            }
+          }
+        }
+        // (p|0) < (q|0);
+        CHECK_EXPR(CompareOperation, expected_type) {
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(p, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(q, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        // p = (p + 8)|0) {\n"
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(p, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_EXPR(BinaryOperation, expected_type) {
+              CHECK_VAR(p, expected_type);
+              CHECK_EXPR(Literal, expected_type);
+            }
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        // sum = sum + +log(values[p>>3]);
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(sum, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(sum, expected_type);
+            CHECK_EXPR(BinaryOperation, expected_type) {
+              CHECK_EXPR(Call, expected_type) {
+                CHECK_VAR(log, expected_type);
+                CHECK_VAR(values, expected_type);
+                CHECK_EXPR(BinaryOperation, expected_type) {
+                  CHECK_VAR(p, expected_type);
+                  CHECK_EXPR(Literal, expected_type);
+                }
+              }
+              CHECK_EXPR(Literal, expected_type);
+            }
+          }
+        }
+        // return +sum;
+        CHECK_EXPR(BinaryOperation, expected_type) {
+          CHECK_VAR(sum, expected_type);
+          CHECK_EXPR(Literal, expected_type);
+        }
+      }
+      // function geometricMean
+      CHECK_EXPR(FunctionLiteral, expected_type) {
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(start, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(start, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        CHECK_EXPR(Assignment, expected_type) {
+          CHECK_VAR(end, expected_type);
+          CHECK_EXPR(BinaryOperation, expected_type) {
+            CHECK_VAR(end, expected_type);
+            CHECK_EXPR(Literal, expected_type);
+          }
+        }
+        // return +exp(+logSum(start, end) / +((end - start)|0));
+        CHECK_EXPR(BinaryOperation, expected_type) {
+          CHECK_EXPR(Call, expected_type) {
+            CHECK_VAR(exp, expected_type);
+            CHECK_EXPR(BinaryOperation, expected_type) {
+              CHECK_EXPR(BinaryOperation, expected_type) {
+                CHECK_EXPR(Call, expected_type) {
+                  CHECK_VAR(logSum, expected_type);
+                  CHECK_VAR(start, expected_type);
+                  CHECK_VAR(end, expected_type);
+                }
+                CHECK_EXPR(Literal, expected_type);
+              }
+              CHECK_EXPR(BinaryOperation, expected_type) {
+                CHECK_EXPR(BinaryOperation, expected_type) {
+                  CHECK_EXPR(BinaryOperation, expected_type) {
+                    CHECK_VAR(end, expected_type);
+                    CHECK_VAR(start, expected_type);
+                  }
+                  CHECK_EXPR(Literal, expected_type);
+                }
+                CHECK_EXPR(Literal, expected_type);
+              }
+            }
+          }
+          CHECK_EXPR(Literal, expected_type);
+        }
+      }
+      // "use asm";
+      CHECK_EXPR(Literal, expected_type);
+      // var exp = stdlib.Math.exp;
+      CHECK_EXPR(Assignment, expected_type) {
+        CHECK_VAR(exp, expected_type);
+        CHECK_VAR(stdlib, expected_type);
+        CHECK_EXPR(Literal, expected_type);
+        CHECK_EXPR(Literal, expected_type);
+      }
+      // var log = stdlib.Math.log;
+      CHECK_EXPR(Assignment, expected_type) {
+        CHECK_VAR(log, expected_type);
+        CHECK_VAR(stdlib, expected_type);
+        CHECK_EXPR(Literal, expected_type);
+        CHECK_EXPR(Literal, expected_type);
+      }
+      // var values = new stdlib.Float64Array(buffer);
+      CHECK_EXPR(Assignment, expected_type) {
+        CHECK_VAR(values, expected_type);
+        CHECK_EXPR(CallNew, expected_type) {
+          CHECK_VAR(stdlib, expected_type);
+          CHECK_EXPR(Literal, expected_type);
+          CHECK_VAR(buffer, expected_type);
+        }
+      }
+      // return { geometricMean: geometricMean };
+      CHECK_EXPR(ObjectLiteral, expected_type) {
+        CHECK_VAR(geometricMean, expected_type);
+      }
+    }
+  }
+  CHECK_TYPES_END
+}
+}
+
+
+TEST(ResetTypingInfo) {
+  const char test_function[] =
+      "function GeometricMean(stdlib, foreign, buffer) {\n"
+      "  \"use asm\";\n"
+      "\n"
+      "  var exp = stdlib.Math.exp;\n"
+      "  var log = stdlib.Math.log;\n"
+      "  var values = new stdlib.Float64Array(buffer);\n"
+      "\n"
+      "  function logSum(start, end) {\n"
+      "    start = start|0;\n"
+      "    end = end|0;\n"
+      "\n"
+      "    var sum = 0.0, p = 0, q = 0;\n"
+      "\n"
+      "    // asm.js forces byte addressing of the heap by requiring shifting "
+      "by 3\n"
+      "    for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {\n"
+      "      sum = sum + +log(values[p>>3]);\n"
+      "    }\n"
+      "\n"
+      "    return +sum;\n"
+      "  }\n"
+      "\n"
+      " function geometricMean(start, end) {\n"
+      "    start = start|0;\n"
+      "    end = end|0;\n"
+      "\n"
+      "    return +exp(+logSum(start, end) / +((end - start)|0));\n"
+      "  }\n"
+      "\n"
+      "  return { geometricMean: geometricMean };\n"
+      "}\n";
+
+  v8::V8::Initialize();
+  HandleAndZoneScope handles;
+
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  i::Handle<i::String> source_code =
+      factory->NewStringFromUtf8(i::CStrVector(test_function))
+          .ToHandleChecked();
+
+  i::Handle<i::Script> script = factory->NewScript(source_code);
+
+  i::ParseInfo info(handles.main_zone(), script);
+  i::Parser parser(&info);
+  parser.set_allow_harmony_arrow_functions(true);
+  parser.set_allow_harmony_sloppy(true);
+  info.set_global();
+  info.set_lazy(false);
+  info.set_allow_lazy_parsing(false);
+  info.set_toplevel(true);
+
+  i::CompilationInfo compilation_info(&info);
+  CHECK(i::Compiler::ParseAndAnalyze(&info));
+  info.set_literal(
+      info.scope()->declarations()->at(0)->AsFunctionDeclaration()->fun());
+
+  // Core of the test.
+  ZoneVector<ExpressionTypeEntry> types(handles.main_zone());
+  ExpressionTypeCollector(&compilation_info, &types).Run();
+  CheckAllSame(types, DEFAULT_TYPE);
+
+  TypeSetter(&compilation_info).Run();
+
+  ExpressionTypeCollector(&compilation_info, &types).Run();
+  CheckAllSame(types, INT32_TYPE);
+
+  TypingReseter(&compilation_info).Run();
+
+  ExpressionTypeCollector(&compilation_info, &types).Run();
+  CheckAllSame(types, DEFAULT_TYPE);
+}
index caca437..432c7ab 100644 (file)
         '../../src/assembler.h',
         '../../src/assert-scope.h',
         '../../src/assert-scope.cc',
-        '../../src/ast-value-factory.cc',
-        '../../src/ast-value-factory.h',
+        '../../src/ast-expression-visitor.cc',
+        '../../src/ast-expression-visitor.h',
         '../../src/ast-literal-reindexer.cc',
         '../../src/ast-literal-reindexer.h',
         '../../src/ast-numbering.cc',
         '../../src/ast-numbering.h',
+        '../../src/ast-value-factory.cc',
+        '../../src/ast-value-factory.h',
         '../../src/ast.cc',
         '../../src/ast.h',
         '../../src/background-parsing-task.cc',
         '../../src/types-inl.h',
         '../../src/types.cc',
         '../../src/types.h',
+        '../../src/typing-reset.cc',
+        '../../src/typing-reset.h',
         '../../src/typing.cc',
         '../../src/typing.h',
         '../../src/unbound-queue-inl.h',