From 10f2c5c33a65a4b92fb44a7809e8e7be253264dc Mon Sep 17 00:00:00 2001 From: bradnelson Date: Mon, 24 Aug 2015 10:16:38 -0700 Subject: [PATCH] Adding visitors to regurgitate expression types or reset them. 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} --- BUILD.gn | 4 + src/ast-expression-visitor.cc | 337 +++++++++++++++++++++++++ src/ast-expression-visitor.h | 49 ++++ src/typing-reset.cc | 25 ++ src/typing-reset.h | 29 +++ test/cctest/cctest.gyp | 4 + test/cctest/expression-type-collector-macros.h | 36 +++ test/cctest/expression-type-collector.cc | 60 +++++ test/cctest/expression-type-collector.h | 40 +++ test/cctest/test-ast-expression-visitor.cc | 258 +++++++++++++++++++ test/cctest/test-typing-reset.cc | 285 +++++++++++++++++++++ tools/gyp/v8.gyp | 8 +- 12 files changed, 1133 insertions(+), 2 deletions(-) create mode 100644 src/ast-expression-visitor.cc create mode 100644 src/ast-expression-visitor.h create mode 100644 src/typing-reset.cc create mode 100644 src/typing-reset.h create mode 100644 test/cctest/expression-type-collector-macros.h create mode 100644 test/cctest/expression-type-collector.cc create mode 100644 test/cctest/expression-type-collector.h create mode 100644 test/cctest/test-ast-expression-visitor.cc create mode 100644 test/cctest/test-typing-reset.cc diff --git a/BUILD.gn b/BUILD.gn index 03f7d54..0f20932 100644 --- 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 index 0000000..08f2950 --- /dev/null +++ b/src/ast-expression-visitor.cc @@ -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* 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* clauses = stmt->cases(); + + for (int i = 0; i < clauses->length(); ++i) { + CaseClause* clause = clauses->at(i); + Expression* label = clause->label(); + RECURSE(Visit(label)); + ZoneList* 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* 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* 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* 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* 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* 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* 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 index 0000000..37960e0 --- /dev/null +++ b/src/ast-expression-visitor.h @@ -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* d) override; + void VisitStatements(ZoneList* 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 index 0000000..0650656 --- /dev/null +++ b/src/typing-reset.cc @@ -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 index 0000000..5e7d628 --- /dev/null +++ b/src/typing-reset.h @@ -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_ diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp index 24db817..5199471 100644 --- a/test/cctest/cctest.gyp +++ b/test/cctest/cctest.gyp @@ -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', @@ -98,6 +100,7 @@ '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', @@ -157,6 +160,7 @@ '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 index 0000000..2dcc1dc --- /dev/null +++ b/test/cctest/expression-type-collector-macros.h @@ -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 index 0000000..b64638b --- /dev/null +++ b/test/cctest/expression-type-collector.cc @@ -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* 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 index 0000000..4cf4e47 --- /dev/null +++ b/test/cctest/expression-type-collector.h @@ -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* dst); + void Run(); + + protected: + void VisitExpression(Expression* expression); + + private: + ZoneVector* 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 index 0000000..f270963 --- /dev/null +++ b/test/cctest/test-ast-expression-visitor.cc @@ -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 + +#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* dst) { + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + + i::Handle source_code = + factory->NewStringFromUtf8(i::CStrVector(source)).ToHandleChecked(); + + i::Handle 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 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 index 0000000..f92e955 --- /dev/null +++ b/test/cctest/test-typing-reset.cc @@ -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 + +#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& 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 source_code = + factory->NewStringFromUtf8(i::CStrVector(test_function)) + .ToHandleChecked(); + + i::Handle 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 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); +} diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index caca437..432c7ab 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -400,12 +400,14 @@ '../../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', @@ -969,6 +971,8 @@ '../../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', -- 2.7.4