| 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 |