OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "vm/zone.h" | 30 #include "vm/zone.h" |
31 | 31 |
32 namespace dart { | 32 namespace dart { |
33 | 33 |
34 DEFINE_FLAG(bool, eliminate_type_checks, true, | 34 DEFINE_FLAG(bool, eliminate_type_checks, true, |
35 "Eliminate type checks when allowed by static type analysis."); | 35 "Eliminate type checks when allowed by static type analysis."); |
36 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 36 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
37 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); | 37 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables."); |
38 DEFINE_FLAG(bool, trace_type_check_elimination, false, | 38 DEFINE_FLAG(bool, trace_type_check_elimination, false, |
39 "Trace type check elimination at compile time."); | 39 "Trace type check elimination at compile time."); |
| 40 DEFINE_FLAG(bool, warn_on_javascript_compatibility, false, |
| 41 "Warn on incompatibilities between vm and dart2js."); |
40 DECLARE_FLAG(bool, enable_type_checks); | 42 DECLARE_FLAG(bool, enable_type_checks); |
| 43 DECLARE_FLAG(bool, warning_as_error); |
| 44 DECLARE_FLAG(bool, silent_warnings); |
41 | 45 |
42 | 46 |
43 // TODO(srdjan): Allow compiler to add constants as they are encountered in | 47 // TODO(srdjan): Allow compiler to add constants as they are encountered in |
44 // the compilation. | 48 // the compilation. |
45 const double kCommonDoubleConstants[] = | 49 const double kCommonDoubleConstants[] = |
46 {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 2.0, 4.0, 5.0, | 50 {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 2.0, 4.0, 5.0, |
47 10.0, 20.0, 30.0, 64.0, 255.0, NAN, | 51 10.0, 20.0, 30.0, 64.0, 255.0, NAN, |
48 // From dart:math | 52 // From dart:math |
49 2.718281828459045, 2.302585092994046, 0.6931471805599453, | 53 2.718281828459045, 2.302585092994046, 0.6931471805599453, |
50 1.4426950408889634, 0.4342944819032518, 3.1415926535897932, | 54 1.4426950408889634, 0.4342944819032518, 3.1415926535897932, |
(...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 true_successor_addresses_.AddArray(for_left.true_successor_addresses_); | 953 true_successor_addresses_.AddArray(for_left.true_successor_addresses_); |
950 true_successor_addresses_.AddArray(for_right.true_successor_addresses_); | 954 true_successor_addresses_.AddArray(for_right.true_successor_addresses_); |
951 } | 955 } |
952 CloseFragment(); | 956 CloseFragment(); |
953 return; | 957 return; |
954 } | 958 } |
955 ValueGraphVisitor::VisitBinaryOpNode(node); | 959 ValueGraphVisitor::VisitBinaryOpNode(node); |
956 } | 960 } |
957 | 961 |
958 | 962 |
959 void EffectGraphVisitor::Bailout(const char* reason) { | 963 void EffectGraphVisitor::Bailout(const char* reason) const { |
960 owner()->Bailout(reason); | 964 owner()->Bailout(reason); |
961 } | 965 } |
962 | 966 |
963 | 967 |
964 void EffectGraphVisitor::InlineBailout(const char* reason) { | 968 void EffectGraphVisitor::InlineBailout(const char* reason) const { |
965 owner()->parsed_function()->function().set_is_inlinable(false); | 969 owner()->parsed_function()->function().set_is_inlinable(false); |
966 if (owner()->IsInlining()) owner()->Bailout(reason); | 970 if (owner()->IsInlining()) owner()->Bailout(reason); |
967 } | 971 } |
968 | 972 |
969 | 973 |
970 // <Statement> ::= Return { value: <Expression> | 974 // <Statement> ::= Return { value: <Expression> |
971 // inlined_finally_list: <InlinedFinally>* } | 975 // inlined_finally_list: <InlinedFinally>* } |
972 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { | 976 void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) { |
973 ValueGraphVisitor for_value(owner()); | 977 ValueGraphVisitor for_value(owner()); |
974 node->value()->Visit(&for_value); | 978 node->value()->Visit(&for_value); |
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1396 Value* value, | 1400 Value* value, |
1397 const AbstractType& dst_type, | 1401 const AbstractType& dst_type, |
1398 const String& dst_name) { | 1402 const String& dst_name) { |
1399 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { | 1403 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { |
1400 return value; | 1404 return value; |
1401 } | 1405 } |
1402 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); | 1406 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); |
1403 } | 1407 } |
1404 | 1408 |
1405 | 1409 |
| 1410 void FlowGraphBuilder::WarnOnJSIntegralNumTypeTest( |
| 1411 AstNode* node, const AbstractType& type) const { |
| 1412 if (is_optimizing()) { |
| 1413 // Warnings for constants are issued when the graph is built for the first |
| 1414 // time only, i.e. just before generating unoptimized code. |
| 1415 // They should not be repeated when generating optimized code. |
| 1416 return; |
| 1417 } |
| 1418 if (!(node->IsLiteralNode() && (type.IsIntType() || type.IsDoubleType()))) { |
| 1419 return; |
| 1420 } |
| 1421 const Instance& instance = node->AsLiteralNode()->literal(); |
| 1422 if (type.IsIntType()) { |
| 1423 if (instance.IsDouble()) { |
| 1424 const Double& double_instance = Double::Cast(instance); |
| 1425 double value = double_instance.value(); |
| 1426 if (floor(value) == value) { |
| 1427 Warning(node->token_pos(), |
| 1428 "javascript compatibility warning: integral value of type " |
| 1429 "'double' is also considered to be of type 'int'"); |
| 1430 } |
| 1431 } |
| 1432 } else { |
| 1433 ASSERT(type.IsDoubleType()); |
| 1434 if (instance.IsInteger()) { |
| 1435 Warning(node->token_pos(), |
| 1436 "javascript compatibility warning: integer value is also " |
| 1437 "considered to be of type 'double'"); |
| 1438 } |
| 1439 } |
| 1440 } |
| 1441 |
| 1442 |
1406 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { | 1443 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { |
1407 ASSERT(Token::IsTypeTestOperator(node->kind())); | 1444 ASSERT(Token::IsTypeTestOperator(node->kind())); |
1408 const AbstractType& type = node->right()->AsTypeNode()->type(); | 1445 const AbstractType& type = node->right()->AsTypeNode()->type(); |
1409 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 1446 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
1410 const bool negate_result = (node->kind() == Token::kISNOT); | 1447 const bool negate_result = (node->kind() == Token::kISNOT); |
1411 // All objects are instances of type T if Object type is a subtype of type T. | 1448 // All objects are instances of type T if Object type is a subtype of type T. |
1412 const Type& object_type = Type::Handle(Type::ObjectType()); | 1449 const Type& object_type = Type::Handle(Type::ObjectType()); |
1413 if (type.IsInstantiated() && object_type.IsSubtypeOf(type, NULL)) { | 1450 if (type.IsInstantiated() && object_type.IsSubtypeOf(type, NULL)) { |
1414 // Must evaluate left side. | 1451 // Must evaluate left side. |
1415 EffectGraphVisitor for_left_value(owner()); | 1452 EffectGraphVisitor for_left_value(owner()); |
1416 node->left()->Visit(&for_left_value); | 1453 node->left()->Visit(&for_left_value); |
1417 Append(for_left_value); | 1454 Append(for_left_value); |
1418 ReturnDefinition(new ConstantInstr(Bool::Get(!negate_result))); | 1455 ReturnDefinition(new ConstantInstr(Bool::Get(!negate_result))); |
1419 return; | 1456 return; |
1420 } | 1457 } |
| 1458 |
| 1459 // Check for javascript compatibility. |
| 1460 if (FLAG_warn_on_javascript_compatibility) { |
| 1461 owner()->WarnOnJSIntegralNumTypeTest(node->left(), type); |
| 1462 } |
| 1463 |
1421 ValueGraphVisitor for_left_value(owner()); | 1464 ValueGraphVisitor for_left_value(owner()); |
1422 node->left()->Visit(&for_left_value); | 1465 node->left()->Visit(&for_left_value); |
1423 Append(for_left_value); | 1466 Append(for_left_value); |
1424 PushArgumentInstr* push_left = PushArgument(for_left_value.value()); | 1467 PushArgumentInstr* push_left = PushArgument(for_left_value.value()); |
1425 PushArgumentInstr* push_instantiator = NULL; | 1468 PushArgumentInstr* push_instantiator = NULL; |
1426 PushArgumentInstr* push_type_args = NULL; | 1469 PushArgumentInstr* push_type_args = NULL; |
1427 if (type.IsInstantiated()) { | 1470 if (type.IsInstantiated()) { |
1428 push_instantiator = PushArgument(BuildNullValue()); | 1471 push_instantiator = PushArgument(BuildNullValue()); |
1429 push_type_args = PushArgument(BuildNullValue()); | 1472 push_type_args = PushArgument(BuildNullValue()); |
1430 } else { | 1473 } else { |
(...skipping 24 matching lines...) Expand all Loading... |
1455 owner()->ic_data_array()); | 1498 owner()->ic_data_array()); |
1456 ReturnDefinition(call); | 1499 ReturnDefinition(call); |
1457 } | 1500 } |
1458 | 1501 |
1459 | 1502 |
1460 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { | 1503 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { |
1461 ASSERT(Token::IsTypeCastOperator(node->kind())); | 1504 ASSERT(Token::IsTypeCastOperator(node->kind())); |
1462 ASSERT(!node->right()->AsTypeNode()->type().IsNull()); | 1505 ASSERT(!node->right()->AsTypeNode()->type().IsNull()); |
1463 const AbstractType& type = node->right()->AsTypeNode()->type(); | 1506 const AbstractType& type = node->right()->AsTypeNode()->type(); |
1464 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 1507 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
| 1508 |
| 1509 // Check for javascript compatibility. |
| 1510 if (FLAG_warn_on_javascript_compatibility) { |
| 1511 owner()->WarnOnJSIntegralNumTypeTest(node->left(), type); |
| 1512 } |
| 1513 |
1465 ValueGraphVisitor for_value(owner()); | 1514 ValueGraphVisitor for_value(owner()); |
1466 node->left()->Visit(&for_value); | 1515 node->left()->Visit(&for_value); |
1467 Append(for_value); | 1516 Append(for_value); |
1468 const String& dst_name = String::ZoneHandle( | 1517 const String& dst_name = String::ZoneHandle( |
1469 Symbols::New(Exceptions::kCastErrorDstName)); | 1518 Symbols::New(Exceptions::kCastErrorDstName)); |
1470 if (CanSkipTypeCheck(node->token_pos(), | 1519 if (CanSkipTypeCheck(node->token_pos(), |
1471 for_value.value(), | 1520 for_value.value(), |
1472 type, | 1521 type, |
1473 dst_name)) { | 1522 dst_name)) { |
1474 ReturnValue(for_value.value()); | 1523 ReturnValue(for_value.value()); |
(...skipping 2407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3882 | 3931 |
3883 void FlowGraphBuilder::PruneUnreachable() { | 3932 void FlowGraphBuilder::PruneUnreachable() { |
3884 ASSERT(osr_id_ != Isolate::kNoDeoptId); | 3933 ASSERT(osr_id_ != Isolate::kNoDeoptId); |
3885 BitVector* block_marks = new BitVector(last_used_block_id_ + 1); | 3934 BitVector* block_marks = new BitVector(last_used_block_id_ + 1); |
3886 bool found = graph_entry_->PruneUnreachable(this, graph_entry_, NULL, osr_id_, | 3935 bool found = graph_entry_->PruneUnreachable(this, graph_entry_, NULL, osr_id_, |
3887 block_marks); | 3936 block_marks); |
3888 ASSERT(found); | 3937 ASSERT(found); |
3889 } | 3938 } |
3890 | 3939 |
3891 | 3940 |
| 3941 void FlowGraphBuilder::Warning(intptr_t token_pos, |
| 3942 const char* format, ...) const { |
| 3943 if (FLAG_silent_warnings) return; |
| 3944 const Function& function = parsed_function_->function(); |
| 3945 va_list args; |
| 3946 va_start(args, format); |
| 3947 const Error& error = Error::Handle( |
| 3948 LanguageError::NewFormattedV(Error::Handle(), // No previous error. |
| 3949 Script::Handle(function.script()), |
| 3950 token_pos, LanguageError::kWarning, |
| 3951 Heap::kNew, format, args)); |
| 3952 va_end(args); |
| 3953 if (FLAG_warning_as_error) { |
| 3954 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3955 UNREACHABLE(); |
| 3956 } else { |
| 3957 OS::Print("%s", error.ToErrorCString()); |
| 3958 } |
| 3959 } |
| 3960 |
| 3961 |
3892 void FlowGraphBuilder::Bailout(const char* reason) const { | 3962 void FlowGraphBuilder::Bailout(const char* reason) const { |
3893 const Function& function = parsed_function_->function(); | 3963 const Function& function = parsed_function_->function(); |
3894 const Error& error = Error::Handle( | 3964 const Error& error = Error::Handle( |
3895 LanguageError::NewFormatted(Error::Handle(), // No previous error. | 3965 LanguageError::NewFormatted(Error::Handle(), // No previous error. |
3896 Script::Handle(function.script()), | 3966 Script::Handle(function.script()), |
3897 function.token_pos(), | 3967 function.token_pos(), |
3898 LanguageError::kError, | 3968 LanguageError::kBailout, |
3899 Heap::kNew, | 3969 Heap::kNew, |
3900 "FlowGraphBuilder Bailout: %s %s", | 3970 "FlowGraphBuilder Bailout: %s %s", |
3901 String::Handle(function.name()).ToCString(), | 3971 String::Handle(function.name()).ToCString(), |
3902 reason)); | 3972 reason)); |
3903 Isolate::Current()->long_jump_base()->Jump(1, error); | 3973 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3974 UNREACHABLE(); |
3904 } | 3975 } |
3905 | 3976 |
3906 } // namespace dart | 3977 } // namespace dart |
OLD | NEW |