| 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/globals.h" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 __ pushl(EAX); // Preserve result. | 660 __ pushl(EAX); // Preserve result. |
| 661 __ pushl(EBX); // Argument for runtime: function to optimize. | 661 __ pushl(EBX); // Argument for runtime: function to optimize. |
| 662 __ CallRuntimeFromDart(kOptimizeInvokedFunctionRuntimeEntry); | 662 __ CallRuntimeFromDart(kOptimizeInvokedFunctionRuntimeEntry); |
| 663 __ popl(EBX); // Remove argument. | 663 __ popl(EBX); // Remove argument. |
| 664 __ popl(EAX); // Restore result. | 664 __ popl(EAX); // Restore result. |
| 665 __ Bind(¬_yet_hot); | 665 __ Bind(¬_yet_hot); |
| 666 } | 666 } |
| 667 } | 667 } |
| 668 if (FLAG_trace_functions) { | 668 if (FLAG_trace_functions) { |
| 669 const Function& function = | 669 const Function& function = |
| 670 Function::ZoneHandle(parsed_function_.function().raw()); | 670 Function::ZoneHandle(parsed_function_.function().raw()); |
| 671 __ LoadObject(EBX, function); | 671 __ LoadObject(EBX, function); |
| 672 __ pushl(EAX); // Preserve result. | 672 __ pushl(EAX); // Preserve result. |
| 673 __ pushl(EBX); | 673 __ pushl(EBX); |
| 674 GenerateCallRuntime(AstNode::kNoId, | 674 GenerateCallRuntime(AstNode::kNoId, |
| 675 0, | 675 0, |
| 676 kTraceFunctionExitRuntimeEntry); | 676 kTraceFunctionExitRuntimeEntry); |
| 677 __ popl(EAX); // Remove argument. | 677 __ popl(EAX); // Remove argument. |
| 678 __ popl(EAX); // Restore result. | 678 __ popl(EAX); // Restore result. |
| 679 } | 679 } |
| 680 __ LeaveFrame(); | 680 __ LeaveFrame(); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 716 } else { | 716 } else { |
| 717 __ LoadObject(EAX, literal); | 717 __ LoadObject(EAX, literal); |
| 718 } | 718 } |
| 719 } else { | 719 } else { |
| 720 // Pop the previously evaluated result value into EAX. | 720 // Pop the previously evaluated result value into EAX. |
| 721 __ popl(EAX); | 721 __ popl(EAX); |
| 722 } | 722 } |
| 723 | 723 |
| 724 // Generate type check. | 724 // Generate type check. |
| 725 if (FLAG_enable_type_checks) { | 725 if (FLAG_enable_type_checks) { |
| 726 const bool returns_null = node->value()->IsLiteralNode() && | |
| 727 node->value()->AsLiteralNode()->literal().IsNull(); | |
| 728 const RawFunction::Kind kind = parsed_function().function().kind(); | 726 const RawFunction::Kind kind = parsed_function().function().kind(); |
| 729 const bool is_implicit_getter = | 727 const bool is_implicit_getter = |
| 730 (kind == RawFunction::kImplicitGetter) || | 728 (kind == RawFunction::kImplicitGetter) || |
| 731 (kind == RawFunction::kConstImplicitGetter); | 729 (kind == RawFunction::kConstImplicitGetter); |
| 732 const bool is_static = parsed_function().function().is_static(); | 730 const bool is_static = parsed_function().function().is_static(); |
| 733 // Implicit getters do not need a type check at return, unless they compute | 731 // Implicit getters do not need a type check at return, unless they compute |
| 734 // the initial value of a static field. | 732 // the initial value of a static field. |
| 735 if (!returns_null && (is_static || !is_implicit_getter)) { | 733 if (is_static || !is_implicit_getter) { |
| 736 GenerateAssertAssignable( | 734 GenerateAssertAssignable( |
| 737 node->id(), | 735 node->id(), |
| 738 node->value()->token_index(), | 736 node->value()->token_index(), |
| 737 node->value(), |
| 739 AbstractType::ZoneHandle(parsed_function().function().result_type()), | 738 AbstractType::ZoneHandle(parsed_function().function().result_type()), |
| 740 String::ZoneHandle(String::NewSymbol("function result"))); | 739 String::ZoneHandle(String::NewSymbol("function result"))); |
| 741 } | 740 } |
| 742 } | 741 } |
| 743 GenerateReturnEpilog(node); | 742 GenerateReturnEpilog(node); |
| 744 } | 743 } |
| 745 | 744 |
| 746 | 745 |
| 747 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { | 746 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { |
| 748 if (!IsResultNeeded(node)) return; | 747 if (!IsResultNeeded(node)) return; |
| 749 __ PushObject(node->literal()); | 748 __ PushObject(node->literal()); |
| 750 } | 749 } |
| 751 | 750 |
| 752 | 751 |
| 753 void CodeGenerator::VisitTypeNode(TypeNode* node) { | 752 void CodeGenerator::VisitTypeNode(TypeNode* node) { |
| 754 // Type nodes are handled specially by the code generator. | 753 // Type nodes are handled specially by the code generator. |
| 755 UNREACHABLE(); | 754 UNREACHABLE(); |
| 756 } | 755 } |
| 757 | 756 |
| 758 | 757 |
| 759 void CodeGenerator::VisitAssignableNode(AssignableNode* node) { | 758 void CodeGenerator::VisitAssignableNode(AssignableNode* node) { |
| 760 ASSERT(FLAG_enable_type_checks); | 759 ASSERT(FLAG_enable_type_checks); |
| 761 node->expr()->Visit(this); | 760 node->expr()->Visit(this); |
| 762 __ popl(EAX); | 761 __ popl(EAX); |
| 763 GenerateAssertAssignable(node->id(), | 762 GenerateAssertAssignable(node->id(), |
| 764 node->token_index(), | 763 node->token_index(), |
| 764 node->expr(), |
| 765 node->type(), | 765 node->type(), |
| 766 node->dst_name()); | 766 node->dst_name()); |
| 767 if (IsResultNeeded(node)) { | 767 if (IsResultNeeded(node)) { |
| 768 __ pushl(EAX); | 768 __ pushl(EAX); |
| 769 } | 769 } |
| 770 } | 770 } |
| 771 | 771 |
| 772 | 772 |
| 773 void CodeGenerator::VisitClosureNode(ClosureNode* node) { | 773 void CodeGenerator::VisitClosureNode(ClosureNode* node) { |
| 774 const Function& function = node->function(); | 774 const Function& function = node->function(); |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 964 } | 964 } |
| 965 } | 965 } |
| 966 | 966 |
| 967 | 967 |
| 968 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 968 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
| 969 node->value()->Visit(this); | 969 node->value()->Visit(this); |
| 970 __ popl(EAX); | 970 __ popl(EAX); |
| 971 if (FLAG_enable_type_checks) { | 971 if (FLAG_enable_type_checks) { |
| 972 GenerateAssertAssignable(node->id(), | 972 GenerateAssertAssignable(node->id(), |
| 973 node->value()->token_index(), | 973 node->value()->token_index(), |
| 974 node->value(), |
| 974 node->local().type(), | 975 node->local().type(), |
| 975 node->local().name()); | 976 node->local().name()); |
| 976 } | 977 } |
| 977 GenerateStoreVariable(node->local(), EAX, EDX); | 978 GenerateStoreVariable(node->local(), EAX, EDX); |
| 978 if (IsResultNeeded(node)) { | 979 if (IsResultNeeded(node)) { |
| 979 __ pushl(EAX); | 980 __ pushl(EAX); |
| 980 } | 981 } |
| 981 } | 982 } |
| 982 | 983 |
| 983 | 984 |
| 984 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { | 985 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { |
| 985 node->instance()->Visit(this); | 986 node->instance()->Visit(this); |
| 986 MarkDeoptPoint(node->id(), node->token_index()); | 987 MarkDeoptPoint(node->id(), node->token_index()); |
| 987 __ popl(EAX); // Instance. | 988 __ popl(EAX); // Instance. |
| 988 __ movl(EAX, FieldAddress(EAX, node->field().Offset())); | 989 __ movl(EAX, FieldAddress(EAX, node->field().Offset())); |
| 989 if (IsResultNeeded(node)) { | 990 if (IsResultNeeded(node)) { |
| 990 __ pushl(EAX); | 991 __ pushl(EAX); |
| 991 } | 992 } |
| 992 } | 993 } |
| 993 | 994 |
| 994 | 995 |
| 995 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { | 996 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { |
| 996 node->instance()->Visit(this); | 997 node->instance()->Visit(this); |
| 997 node->value()->Visit(this); | 998 node->value()->Visit(this); |
| 998 MarkDeoptPoint(node->id(), node->token_index()); | 999 MarkDeoptPoint(node->id(), node->token_index()); |
| 999 __ popl(EAX); // Value. | 1000 __ popl(EAX); // Value. |
| 1000 if (FLAG_enable_type_checks) { | 1001 if (FLAG_enable_type_checks) { |
| 1001 GenerateAssertAssignable(node->id(), | 1002 GenerateAssertAssignable(node->id(), |
| 1002 node->value()->token_index(), | 1003 node->value()->token_index(), |
| 1004 node->value(), |
| 1003 AbstractType::ZoneHandle(node->field().type()), | 1005 AbstractType::ZoneHandle(node->field().type()), |
| 1004 String::ZoneHandle(node->field().name())); | 1006 String::ZoneHandle(node->field().name())); |
| 1005 } | 1007 } |
| 1006 __ popl(EDX); // Instance. | 1008 __ popl(EDX); // Instance. |
| 1007 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); | 1009 __ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX); |
| 1008 ASSERT(!IsResultNeeded(node)); | 1010 ASSERT(!IsResultNeeded(node)); |
| 1009 } | 1011 } |
| 1010 | 1012 |
| 1011 | 1013 |
| 1012 // Expects array and index on stack and returns result in EAX. | 1014 // Expects array and index on stack and returns result in EAX. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 } | 1098 } |
| 1097 | 1099 |
| 1098 | 1100 |
| 1099 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { | 1101 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { |
| 1100 node->value()->Visit(this); | 1102 node->value()->Visit(this); |
| 1101 MarkDeoptPoint(node->id(), node->token_index()); | 1103 MarkDeoptPoint(node->id(), node->token_index()); |
| 1102 __ popl(EAX); // Value. | 1104 __ popl(EAX); // Value. |
| 1103 if (FLAG_enable_type_checks) { | 1105 if (FLAG_enable_type_checks) { |
| 1104 GenerateAssertAssignable(node->id(), | 1106 GenerateAssertAssignable(node->id(), |
| 1105 node->value()->token_index(), | 1107 node->value()->token_index(), |
| 1108 node->value(), |
| 1106 AbstractType::ZoneHandle(node->field().type()), | 1109 AbstractType::ZoneHandle(node->field().type()), |
| 1107 String::ZoneHandle(node->field().name())); | 1110 String::ZoneHandle(node->field().name())); |
| 1108 } | 1111 } |
| 1109 __ LoadObject(EDX, node->field()); | 1112 __ LoadObject(EDX, node->field()); |
| 1110 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); | 1113 __ StoreIntoObject(EDX, FieldAddress(EDX, Field::value_offset()), EAX); |
| 1111 if (IsResultNeeded(node)) { | 1114 if (IsResultNeeded(node)) { |
| 1112 // The result is the input value. | 1115 // The result is the input value. |
| 1113 __ pushl(EAX); | 1116 __ pushl(EAX); |
| 1114 } | 1117 } |
| 1115 } | 1118 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1182 } | 1185 } |
| 1183 const Immediate value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | 1186 const Immediate value = Immediate(reinterpret_cast<int32_t>(Smi::New(1))); |
| 1184 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; | 1187 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; |
| 1185 __ pushl(EAX); | 1188 __ pushl(EAX); |
| 1186 __ pushl(value); | 1189 __ pushl(value); |
| 1187 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); | 1190 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); |
| 1188 // result is in EAX. | 1191 // result is in EAX. |
| 1189 if (FLAG_enable_type_checks) { | 1192 if (FLAG_enable_type_checks) { |
| 1190 GenerateAssertAssignable(node->id(), | 1193 GenerateAssertAssignable(node->id(), |
| 1191 node->token_index(), | 1194 node->token_index(), |
| 1195 NULL, |
| 1192 node->local().type(), | 1196 node->local().type(), |
| 1193 node->local().name()); | 1197 node->local().name()); |
| 1194 } | 1198 } |
| 1195 GenerateStoreVariable(node->local(), EAX, EDX); | 1199 GenerateStoreVariable(node->local(), EAX, EDX); |
| 1196 if (node->prefix() && IsResultNeeded(node)) { | 1200 if (node->prefix() && IsResultNeeded(node)) { |
| 1197 __ pushl(EAX); | 1201 __ pushl(EAX); |
| 1198 } | 1202 } |
| 1199 } | 1203 } |
| 1200 | 1204 |
| 1201 | 1205 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1274 | 1278 |
| 1275 static const Class* CoreClass(const char* c_name) { | 1279 static const Class* CoreClass(const char* c_name) { |
| 1276 const String& class_name = String::Handle(String::NewSymbol(c_name)); | 1280 const String& class_name = String::Handle(String::NewSymbol(c_name)); |
| 1277 const Class& cls = Class::ZoneHandle(Library::Handle( | 1281 const Class& cls = Class::ZoneHandle(Library::Handle( |
| 1278 Library::CoreImplLibrary()).LookupClass(class_name)); | 1282 Library::CoreImplLibrary()).LookupClass(class_name)); |
| 1279 ASSERT(!cls.IsNull()); | 1283 ASSERT(!cls.IsNull()); |
| 1280 return &cls; | 1284 return &cls; |
| 1281 } | 1285 } |
| 1282 | 1286 |
| 1283 | 1287 |
| 1284 // Optimize instanceof type test by adding inlined tests for: | 1288 // If instanceof type test cannot be performed successfully at compile time and |
| 1289 // therefore eliminated, optimize it by adding inlined tests for: |
| 1285 // - NULL -> return false. | 1290 // - NULL -> return false. |
| 1286 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1291 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1287 // - Class equality (only if class is not parameterized). | 1292 // - Class equality (only if class is not parameterized). |
| 1288 // Inputs: | 1293 // Inputs: |
| 1289 // - EAX: object. | 1294 // - EAX: object. |
| 1290 // Destroys ECX. | 1295 // Destroys ECX. |
| 1291 // Returns: | 1296 // Returns: |
| 1292 // - true or false on stack. | 1297 // - true or false on stack. |
| 1293 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, | 1298 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, |
| 1294 intptr_t token_index, | 1299 intptr_t token_index, |
| 1300 AstNode* value, |
| 1295 const AbstractType& type, | 1301 const AbstractType& type, |
| 1296 bool negate_result) { | 1302 bool negate_result) { |
| 1297 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1303 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1298 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1304 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1299 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1305 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1300 | 1306 |
| 1301 // All instances are of a subtype of the Object type. | 1307 // All objects are instances of type T if Object type is a subtype of type T. |
| 1302 const Type& object_type = | 1308 const Type& object_type = |
| 1303 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1309 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1304 Error& malformed_error = Error::Handle(); | 1310 Error& malformed_error = Error::Handle(); |
| 1305 if (type.IsInstantiated() && | 1311 if (type.IsInstantiated() && |
| 1306 object_type.IsSubtypeOf(type, &malformed_error)) { | 1312 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1307 __ PushObject(negate_result ? bool_false : bool_true); | 1313 __ PushObject(negate_result ? bool_false : bool_true); |
| 1308 return; | 1314 return; |
| 1309 } | 1315 } |
| 1310 | 1316 |
| 1317 // Eliminate the test if it can be performed successfully at compile time. |
| 1318 if ((value != NULL) && value->IsLiteralNode() && type.IsInstantiated()) { |
| 1319 const Instance& literal_value = value->AsLiteralNode()->literal(); |
| 1320 const Class& cls = Class::Handle(literal_value.clazz()); |
| 1321 if (cls.IsNullClass()) { |
| 1322 ASSERT(literal_value.IsNull() || |
| 1323 (literal_value.raw() == Object::sentinel()) || |
| 1324 (literal_value.raw() == Object::transition_sentinel())); |
| 1325 // A null object is only an instance of Object and Dynamic, which has |
| 1326 // already been checked above (if the type is instantiated). So we can |
| 1327 // return false here if the instance is null (and if the type is |
| 1328 // instantiated). |
| 1329 __ PushObject(negate_result ? bool_true : bool_false); |
| 1330 } else { |
| 1331 Error& malformed_error = Error::Handle(); |
| 1332 if (literal_value.IsInstanceOf(type, |
| 1333 TypeArguments::Handle(), |
| 1334 &malformed_error)) { |
| 1335 __ PushObject(negate_result ? bool_false : bool_true); |
| 1336 } else { |
| 1337 ASSERT(malformed_error.IsNull()); |
| 1338 __ PushObject(negate_result ? bool_true : bool_false); |
| 1339 } |
| 1340 } |
| 1341 return; |
| 1342 } |
| 1343 |
| 1311 const Immediate raw_null = | 1344 const Immediate raw_null = |
| 1312 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1345 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1313 Label done, check_negate_done; | 1346 Label done, check_negate_done; |
| 1314 // If type is instantiated and non-parameterized, we can inline code | 1347 // If type is instantiated and non-parameterized, we can inline code |
| 1315 // checking whether the tested instance is a Smi. | 1348 // checking whether the tested instance is a Smi. |
| 1316 if (type.IsInstantiated()) { | 1349 if (type.IsInstantiated()) { |
| 1317 // A null object is only an instance of Object and Dynamic, which has | 1350 // A null object is only an instance of Object and Dynamic, which has |
| 1318 // already been checked above (if the type is instantiated). So we can | 1351 // already been checked above (if the type is instantiated). So we can |
| 1319 // return false here if the instance is null (and if the type is | 1352 // return false here if the instance is null (and if the type is |
| 1320 // instantiated). | 1353 // instantiated). |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1481 | 1514 |
| 1482 // Jumps to label if ECX equals the given class. | 1515 // Jumps to label if ECX equals the given class. |
| 1483 // Inputs: | 1516 // Inputs: |
| 1484 // - ECX: tested class. | 1517 // - ECX: tested class. |
| 1485 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { | 1518 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { |
| 1486 __ CompareObject(ECX, cls); | 1519 __ CompareObject(ECX, cls); |
| 1487 __ j(EQUAL, label, Assembler::kNearJump); | 1520 __ j(EQUAL, label, Assembler::kNearJump); |
| 1488 } | 1521 } |
| 1489 | 1522 |
| 1490 | 1523 |
| 1491 // Optimize assignable type check by adding inlined tests for: | 1524 // If type check cannot be performed successfully at compile time and therefore |
| 1525 // eliminated, optimize it by adding inlined tests for: |
| 1492 // - NULL -> return NULL. | 1526 // - NULL -> return NULL. |
| 1493 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1527 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1494 // - Class equality (only if class is not parameterized). | 1528 // - Class equality (only if class is not parameterized). |
| 1495 // Inputs: | 1529 // Inputs: |
| 1496 // - EAX: object. | 1530 // - EAX: object. |
| 1497 // Destroys ECX and EDX. | 1531 // Destroys ECX and EDX. |
| 1498 // Returns: | 1532 // Returns: |
| 1499 // - object in EAX for successful assignable check (or throws TypeError). | 1533 // - object in EAX for successful assignable check (or throws TypeError). |
| 1500 // Performance notes: positive checks must be quick, negative checks can be slow | 1534 // Performance notes: positive checks must be quick, negative checks can be slow |
| 1501 // as they throw an exception. | 1535 // as they throw an exception. |
| 1502 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1536 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1503 intptr_t token_index, | 1537 intptr_t token_index, |
| 1538 AstNode* value, |
| 1504 const AbstractType& dst_type, | 1539 const AbstractType& dst_type, |
| 1505 const String& dst_name) { | 1540 const String& dst_name) { |
| 1506 ASSERT(FLAG_enable_type_checks); | 1541 ASSERT(FLAG_enable_type_checks); |
| 1507 ASSERT(token_index >= 0); | 1542 ASSERT(token_index >= 0); |
| 1508 ASSERT(!dst_type.IsNull()); | 1543 ASSERT(!dst_type.IsNull()); |
| 1509 ASSERT(dst_type.IsFinalized()); | 1544 ASSERT(dst_type.IsFinalized()); |
| 1510 | 1545 |
| 1511 // Any expression is assignable to the Dynamic type and to the Object type. | 1546 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1512 // Skip the test. | 1547 // Skip the test. |
| 1513 if (!dst_type.IsMalformed() && | 1548 if (!dst_type.IsMalformed() && |
| 1514 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { | 1549 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { |
| 1515 return; | 1550 return; |
| 1516 } | 1551 } |
| 1517 | 1552 |
| 1518 // It is a compile-time error to explicitly return a value (including null) | 1553 // It is a compile-time error to explicitly return a value (including null) |
| 1519 // from a void function. However, functions that do not explicitly return a | 1554 // from a void function. However, functions that do not explicitly return a |
| 1520 // value, implicitly return null. This includes void functions. Therefore, we | 1555 // value, implicitly return null. This includes void functions. Therefore, we |
| 1521 // skip the type test here and trust the parser to only return null in void | 1556 // skip the type test here and trust the parser to only return null in void |
| 1522 // function. | 1557 // function. |
| 1523 if (dst_type.IsVoidType()) { | 1558 if (dst_type.IsVoidType()) { |
| 1524 return; | 1559 return; |
| 1525 } | 1560 } |
| 1526 | 1561 |
| 1562 // Eliminate the test if it can be performed successfully at compile time. |
| 1563 if ((value != NULL) && value->IsLiteralNode()) { |
| 1564 const Instance& literal_value = value->AsLiteralNode()->literal(); |
| 1565 const Class& cls = Class::Handle(literal_value.clazz()); |
| 1566 if (cls.IsNullClass()) { |
| 1567 ASSERT(literal_value.IsNull() || |
| 1568 (literal_value.raw() == Object::sentinel()) || |
| 1569 (literal_value.raw() == Object::transition_sentinel())); |
| 1570 return; |
| 1571 } |
| 1572 Error& malformed_error = Error::Handle(); |
| 1573 if (!dst_type.IsMalformed() && |
| 1574 dst_type.IsInstantiated() && |
| 1575 literal_value.IsInstanceOf(dst_type, |
| 1576 TypeArguments::Handle(), |
| 1577 &malformed_error)) { |
| 1578 return; |
| 1579 } |
| 1580 } |
| 1581 |
| 1527 // A null object is always assignable and is returned as result. | 1582 // A null object is always assignable and is returned as result. |
| 1528 const Immediate raw_null = | 1583 const Immediate raw_null = |
| 1529 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1584 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1530 Label done, runtime_call; | 1585 Label done, runtime_call; |
| 1531 __ cmpl(EAX, raw_null); | 1586 __ cmpl(EAX, raw_null); |
| 1532 __ j(EQUAL, &done); | 1587 __ j(EQUAL, &done); |
| 1533 | 1588 |
| 1534 // Generate throw new TypeError() if the type is malformed. | 1589 // Generate throw new TypeError() if the type is malformed. |
| 1535 if (dst_type.IsMalformed()) { | 1590 if (dst_type.IsMalformed()) { |
| 1536 const Error& error = Error::Handle(dst_type.malformed_error()); | 1591 const Error& error = Error::Handle(dst_type.malformed_error()); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1741 const Function& function = parsed_function_.function(); | 1796 const Function& function = parsed_function_.function(); |
| 1742 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 1797 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 1743 const int num_fixed_params = function.num_fixed_parameters(); | 1798 const int num_fixed_params = function.num_fixed_parameters(); |
| 1744 const int num_opt_params = function.num_optional_parameters(); | 1799 const int num_opt_params = function.num_optional_parameters(); |
| 1745 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); | 1800 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); |
| 1746 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { | 1801 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { |
| 1747 LocalVariable* parameter = scope->VariableAt(i); | 1802 LocalVariable* parameter = scope->VariableAt(i); |
| 1748 GenerateLoadVariable(EAX, *parameter); | 1803 GenerateLoadVariable(EAX, *parameter); |
| 1749 GenerateAssertAssignable(AstNode::kNoId, | 1804 GenerateAssertAssignable(AstNode::kNoId, |
| 1750 parameter->token_index(), | 1805 parameter->token_index(), |
| 1806 NULL, |
| 1751 parameter->type(), | 1807 parameter->type(), |
| 1752 parameter->name()); | 1808 parameter->name()); |
| 1753 } | 1809 } |
| 1754 } | 1810 } |
| 1755 | 1811 |
| 1756 | 1812 |
| 1757 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, | 1813 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, |
| 1758 intptr_t token_index) { | 1814 intptr_t token_index) { |
| 1759 if (!FLAG_enable_type_checks) { | 1815 if (!FLAG_enable_type_checks) { |
| 1760 return; | 1816 return; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1797 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1853 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1798 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1854 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1799 node->left()->Visit(this); | 1855 node->left()->Visit(this); |
| 1800 | 1856 |
| 1801 // The instanceof operator needs special handling. | 1857 // The instanceof operator needs special handling. |
| 1802 if (Token::IsInstanceofOperator(node->kind())) { | 1858 if (Token::IsInstanceofOperator(node->kind())) { |
| 1803 __ popl(EAX); // Left operand. | 1859 __ popl(EAX); // Left operand. |
| 1804 ASSERT(node->right()->IsTypeNode()); | 1860 ASSERT(node->right()->IsTypeNode()); |
| 1805 GenerateInstanceOf(node->id(), | 1861 GenerateInstanceOf(node->id(), |
| 1806 node->token_index(), | 1862 node->token_index(), |
| 1863 node->left(), |
| 1807 node->right()->AsTypeNode()->type(), | 1864 node->right()->AsTypeNode()->type(), |
| 1808 (node->kind() == Token::kISNOT)); | 1865 (node->kind() == Token::kISNOT)); |
| 1809 if (!IsResultNeeded(node)) { | 1866 if (!IsResultNeeded(node)) { |
| 1810 __ popl(EAX); // Pop the result of the instanceof operation. | 1867 __ popl(EAX); // Pop the result of the instanceof operation. |
| 1811 } | 1868 } |
| 1812 return; | 1869 return; |
| 1813 } | 1870 } |
| 1814 | 1871 |
| 1815 node->right()->Visit(this); | 1872 node->right()->Visit(this); |
| 1816 // Both left and right values on stack. | 1873 // Both left and right values on stack. |
| (...skipping 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2833 const Error& error = Error::Handle( | 2890 const Error& error = Error::Handle( |
| 2834 Parser::FormatError(script, token_index, "Error", format, args)); | 2891 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2835 va_end(args); | 2892 va_end(args); |
| 2836 Isolate::Current()->long_jump_base()->Jump(1, error); | 2893 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2837 UNREACHABLE(); | 2894 UNREACHABLE(); |
| 2838 } | 2895 } |
| 2839 | 2896 |
| 2840 } // namespace dart | 2897 } // namespace dart |
| 2841 | 2898 |
| 2842 #endif // defined TARGET_ARCH_IA32 | 2899 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |