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 23 matching lines...) Expand all Loading... |
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 | 40 |
41 DECLARE_FLAG(bool, enable_debugger); | 41 DECLARE_FLAG(bool, enable_debugger); |
42 DECLARE_FLAG(bool, enable_type_checks); | 42 DECLARE_FLAG(bool, enable_type_checks); |
43 DECLARE_FLAG(int, optimization_counter_threshold); | 43 DECLARE_FLAG(int, optimization_counter_threshold); |
44 DECLARE_FLAG(bool, silent_warnings); | |
45 DECLARE_FLAG(bool, warn_on_javascript_compatibility); | 44 DECLARE_FLAG(bool, warn_on_javascript_compatibility); |
46 DECLARE_FLAG(bool, warning_as_error); | |
47 | 45 |
48 // Quick access to the locally defined isolate() method. | 46 // Quick access to the locally defined isolate() method. |
49 #define I (isolate()) | 47 #define I (isolate()) |
50 | 48 |
51 // TODO(srdjan): Allow compiler to add constants as they are encountered in | 49 // TODO(srdjan): Allow compiler to add constants as they are encountered in |
52 // the compilation. | 50 // the compilation. |
53 const double kCommonDoubleConstants[] = | 51 const double kCommonDoubleConstants[] = |
54 {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 2.0, 4.0, 5.0, | 52 {-1.0, -0.5, -0.1, 0.0, 0.1, 0.5, 1.0, 2.0, 4.0, 5.0, |
55 10.0, 20.0, 30.0, 64.0, 255.0, NAN, | 53 10.0, 20.0, 30.0, 64.0, 255.0, NAN, |
56 // From dart:math | 54 // From dart:math |
(...skipping 1352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1409 Value* value, | 1407 Value* value, |
1410 const AbstractType& dst_type, | 1408 const AbstractType& dst_type, |
1411 const String& dst_name) { | 1409 const String& dst_name) { |
1412 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { | 1410 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { |
1413 return value; | 1411 return value; |
1414 } | 1412 } |
1415 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); | 1413 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); |
1416 } | 1414 } |
1417 | 1415 |
1418 | 1416 |
1419 void FlowGraphBuilder::WarnOnJSIntegralNumTypeTest( | 1417 bool FlowGraphBuilder::WarnOnJSIntegralNumTypeTest( |
1420 AstNode* node, const AbstractType& type) const { | 1418 AstNode* node, const AbstractType& type) const { |
1421 if (is_optimizing()) { | |
1422 // Warnings for constants are issued when the graph is built for the first | |
1423 // time only, i.e. just before generating unoptimized code. | |
1424 // They should not be repeated when generating optimized code. | |
1425 return; | |
1426 } | |
1427 if (!(node->IsLiteralNode() && (type.IsIntType() || type.IsDoubleType()))) { | 1419 if (!(node->IsLiteralNode() && (type.IsIntType() || type.IsDoubleType()))) { |
1428 return; | 1420 return false; |
1429 } | 1421 } |
1430 const Instance& instance = node->AsLiteralNode()->literal(); | 1422 const Instance& instance = node->AsLiteralNode()->literal(); |
1431 if (type.IsIntType()) { | 1423 if (type.IsIntType()) { |
1432 if (instance.IsDouble()) { | 1424 if (instance.IsDouble()) { |
1433 const Double& double_instance = Double::Cast(instance); | 1425 const Double& double_instance = Double::Cast(instance); |
1434 double value = double_instance.value(); | 1426 double value = double_instance.value(); |
1435 if (floor(value) == value) { | 1427 if (floor(value) == value) { |
1436 JSWarning(node->token_pos(), | 1428 return true; |
1437 "integral value of type 'double' is also considered " | |
1438 "to be of type 'int'"); | |
1439 } | 1429 } |
1440 } | 1430 } |
1441 } else { | 1431 } else { |
1442 ASSERT(type.IsDoubleType()); | 1432 ASSERT(type.IsDoubleType()); |
1443 if (instance.IsInteger()) { | 1433 if (instance.IsInteger()) { |
1444 JSWarning(node->token_pos(), | 1434 return true; |
1445 "integer value is also considered to be of type 'double'"); | |
1446 } | 1435 } |
1447 } | 1436 } |
| 1437 return false; |
1448 } | 1438 } |
1449 | 1439 |
1450 | 1440 |
1451 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { | 1441 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { |
1452 ASSERT(Token::IsTypeTestOperator(node->kind())); | 1442 ASSERT(Token::IsTypeTestOperator(node->kind())); |
1453 const AbstractType& type = node->right()->AsTypeNode()->type(); | 1443 const AbstractType& type = node->right()->AsTypeNode()->type(); |
1454 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 1444 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
1455 const bool negate_result = (node->kind() == Token::kISNOT); | 1445 const bool negate_result = (node->kind() == Token::kISNOT); |
1456 // All objects are instances of type T if Object type is a subtype of type T. | 1446 // All objects are instances of type T if Object type is a subtype of type T. |
1457 const Type& object_type = Type::Handle(I, Type::ObjectType()); | 1447 const Type& object_type = Type::Handle(I, Type::ObjectType()); |
1458 if (type.IsInstantiated() && object_type.IsSubtypeOf(type, NULL)) { | 1448 if (type.IsInstantiated() && object_type.IsSubtypeOf(type, NULL)) { |
1459 // Must evaluate left side. | 1449 // Must evaluate left side. |
1460 EffectGraphVisitor for_left_value(owner()); | 1450 EffectGraphVisitor for_left_value(owner()); |
1461 node->left()->Visit(&for_left_value); | 1451 node->left()->Visit(&for_left_value); |
1462 Append(for_left_value); | 1452 Append(for_left_value); |
1463 ReturnDefinition(new ConstantInstr(Bool::Get(!negate_result))); | 1453 ReturnDefinition(new ConstantInstr(Bool::Get(!negate_result))); |
1464 return; | 1454 return; |
1465 } | 1455 } |
1466 | |
1467 // Check for javascript compatibility. | |
1468 if (FLAG_warn_on_javascript_compatibility) { | |
1469 owner()->WarnOnJSIntegralNumTypeTest(node->left(), type); | |
1470 } | |
1471 | |
1472 ValueGraphVisitor for_left_value(owner()); | 1456 ValueGraphVisitor for_left_value(owner()); |
1473 node->left()->Visit(&for_left_value); | 1457 node->left()->Visit(&for_left_value); |
1474 Append(for_left_value); | 1458 Append(for_left_value); |
1475 PushArgumentInstr* push_left = PushArgument(for_left_value.value()); | 1459 PushArgumentInstr* push_left = PushArgument(for_left_value.value()); |
1476 PushArgumentInstr* push_instantiator = NULL; | 1460 PushArgumentInstr* push_instantiator = NULL; |
1477 PushArgumentInstr* push_type_args = NULL; | 1461 PushArgumentInstr* push_type_args = NULL; |
1478 if (type.IsInstantiated()) { | 1462 if (type.IsInstantiated()) { |
1479 push_instantiator = PushArgument(BuildNullValue()); | 1463 push_instantiator = PushArgument(BuildNullValue()); |
1480 push_type_args = PushArgument(BuildNullValue()); | 1464 push_type_args = PushArgument(BuildNullValue()); |
1481 } else { | 1465 } else { |
(...skipping 24 matching lines...) Expand all Loading... |
1506 owner()->ic_data_array()); | 1490 owner()->ic_data_array()); |
1507 ReturnDefinition(call); | 1491 ReturnDefinition(call); |
1508 } | 1492 } |
1509 | 1493 |
1510 | 1494 |
1511 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { | 1495 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { |
1512 ASSERT(Token::IsTypeCastOperator(node->kind())); | 1496 ASSERT(Token::IsTypeCastOperator(node->kind())); |
1513 ASSERT(!node->right()->AsTypeNode()->type().IsNull()); | 1497 ASSERT(!node->right()->AsTypeNode()->type().IsNull()); |
1514 const AbstractType& type = node->right()->AsTypeNode()->type(); | 1498 const AbstractType& type = node->right()->AsTypeNode()->type(); |
1515 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 1499 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
1516 | |
1517 // Check for javascript compatibility. | |
1518 if (FLAG_warn_on_javascript_compatibility) { | |
1519 owner()->WarnOnJSIntegralNumTypeTest(node->left(), type); | |
1520 } | |
1521 | |
1522 ValueGraphVisitor for_value(owner()); | 1500 ValueGraphVisitor for_value(owner()); |
1523 node->left()->Visit(&for_value); | 1501 node->left()->Visit(&for_value); |
1524 Append(for_value); | 1502 Append(for_value); |
1525 const String& dst_name = String::ZoneHandle( | 1503 const String& dst_name = String::ZoneHandle( |
1526 I, Symbols::New(Exceptions::kCastErrorDstName)); | 1504 I, Symbols::New(Exceptions::kCastErrorDstName)); |
1527 if (CanSkipTypeCheck(node->token_pos(), | 1505 if (CanSkipTypeCheck(node->token_pos(), |
1528 for_value.value(), | 1506 for_value.value(), |
1529 type, | 1507 type, |
1530 dst_name)) { | 1508 dst_name)) { |
1531 ReturnValue(for_value.value()); | 1509 // Check for javascript compatibility. |
1532 return; | 1510 // Do not skip type check if javascript compatibility warning is required. |
| 1511 if (!FLAG_warn_on_javascript_compatibility || |
| 1512 !owner()->WarnOnJSIntegralNumTypeTest(node->left(), type)) { |
| 1513 ReturnValue(for_value.value()); |
| 1514 return; |
| 1515 } |
1533 } | 1516 } |
1534 PushArgumentInstr* push_left = PushArgument(for_value.value()); | 1517 PushArgumentInstr* push_left = PushArgument(for_value.value()); |
1535 PushArgumentInstr* push_instantiator = NULL; | 1518 PushArgumentInstr* push_instantiator = NULL; |
1536 PushArgumentInstr* push_type_args = NULL; | 1519 PushArgumentInstr* push_type_args = NULL; |
1537 if (type.IsInstantiated()) { | 1520 if (type.IsInstantiated()) { |
1538 push_instantiator = PushArgument(BuildNullValue()); | 1521 push_instantiator = PushArgument(BuildNullValue()); |
1539 push_type_args = PushArgument(BuildNullValue()); | 1522 push_type_args = PushArgument(BuildNullValue()); |
1540 } else { | 1523 } else { |
1541 BuildTypecheckPushArguments(node->token_pos(), | 1524 BuildTypecheckPushArguments(node->token_pos(), |
1542 &push_instantiator, | 1525 &push_instantiator, |
(...skipping 2410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3953 | 3936 |
3954 void FlowGraphBuilder::PruneUnreachable() { | 3937 void FlowGraphBuilder::PruneUnreachable() { |
3955 ASSERT(osr_id_ != Isolate::kNoDeoptId); | 3938 ASSERT(osr_id_ != Isolate::kNoDeoptId); |
3956 BitVector* block_marks = new BitVector(last_used_block_id_ + 1); | 3939 BitVector* block_marks = new BitVector(last_used_block_id_ + 1); |
3957 bool found = graph_entry_->PruneUnreachable(this, graph_entry_, NULL, osr_id_, | 3940 bool found = graph_entry_->PruneUnreachable(this, graph_entry_, NULL, osr_id_, |
3958 block_marks); | 3941 block_marks); |
3959 ASSERT(found); | 3942 ASSERT(found); |
3960 } | 3943 } |
3961 | 3944 |
3962 | 3945 |
3963 void FlowGraphBuilder::JSWarning(intptr_t token_pos, const char* msg) const { | |
3964 const Script& script = Script::Handle(parsed_function_->function().script()); | |
3965 if (FLAG_warning_as_error) { | |
3966 // Report::kJSWarning would result in a JavascriptCompatibilityError, but we | |
3967 // want a compile-time error. | |
3968 // TODO(regis): Should we change the expection and make the tests work with | |
3969 // a JavascriptCompatibilityError? | |
3970 Report::MessageF(Report::kWarning, script, token_pos, "%s", msg); | |
3971 UNREACHABLE(); | |
3972 } | |
3973 Report::MessageF(Report::kJSWarning, script, token_pos, "%s", msg); | |
3974 } | |
3975 | |
3976 | |
3977 void FlowGraphBuilder::Bailout(const char* reason) const { | 3946 void FlowGraphBuilder::Bailout(const char* reason) const { |
3978 const Function& function = parsed_function_->function(); | 3947 const Function& function = parsed_function_->function(); |
3979 Report::MessageF(Report::kBailout, | 3948 Report::MessageF(Report::kBailout, |
3980 Script::Handle(function.script()), | 3949 Script::Handle(function.script()), |
3981 function.token_pos(), | 3950 function.token_pos(), |
3982 "FlowGraphBuilder Bailout: %s %s", | 3951 "FlowGraphBuilder Bailout: %s %s", |
3983 String::Handle(function.name()).ToCString(), | 3952 String::Handle(function.name()).ToCString(), |
3984 reason); | 3953 reason); |
3985 UNREACHABLE(); | 3954 UNREACHABLE(); |
3986 } | 3955 } |
3987 | 3956 |
3988 } // namespace dart | 3957 } // namespace dart |
OLD | NEW |