| 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_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 } else { | 650 } else { |
| 651 __ LoadObject(RAX, literal); | 651 __ LoadObject(RAX, literal); |
| 652 } | 652 } |
| 653 } else { | 653 } else { |
| 654 // Pop the previously evaluated result value into RAX. | 654 // Pop the previously evaluated result value into RAX. |
| 655 __ popq(RAX); | 655 __ popq(RAX); |
| 656 } | 656 } |
| 657 | 657 |
| 658 // Generate type check. | 658 // Generate type check. |
| 659 if (FLAG_enable_type_checks) { | 659 if (FLAG_enable_type_checks) { |
| 660 const bool returns_null = node->value()->IsLiteralNode() && | |
| 661 node->value()->AsLiteralNode()->literal().IsNull(); | |
| 662 const RawFunction::Kind kind = parsed_function().function().kind(); | 660 const RawFunction::Kind kind = parsed_function().function().kind(); |
| 663 const bool is_implicit_getter = | 661 const bool is_implicit_getter = |
| 664 (kind == RawFunction::kImplicitGetter) || | 662 (kind == RawFunction::kImplicitGetter) || |
| 665 (kind == RawFunction::kConstImplicitGetter); | 663 (kind == RawFunction::kConstImplicitGetter); |
| 666 const bool is_static = parsed_function().function().is_static(); | 664 const bool is_static = parsed_function().function().is_static(); |
| 667 // Implicit getters do not need a type check at return, unless they compute | 665 // Implicit getters do not need a type check at return, unless they compute |
| 668 // the initial value of a static field. | 666 // the initial value of a static field. |
| 669 if (!returns_null && (is_static || !is_implicit_getter)) { | 667 if (is_static || !is_implicit_getter) { |
| 670 GenerateAssertAssignable( | 668 GenerateAssertAssignable( |
| 671 node->id(), | 669 node->id(), |
| 672 node->value()->token_index(), | 670 node->value()->token_index(), |
| 671 node->value(), |
| 673 AbstractType::ZoneHandle(parsed_function().function().result_type()), | 672 AbstractType::ZoneHandle(parsed_function().function().result_type()), |
| 674 String::ZoneHandle(String::NewSymbol("function result"))); | 673 String::ZoneHandle(String::NewSymbol("function result"))); |
| 675 } | 674 } |
| 676 } | 675 } |
| 677 GenerateReturnEpilog(node); | 676 GenerateReturnEpilog(node); |
| 678 } | 677 } |
| 679 | 678 |
| 680 | 679 |
| 681 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { | 680 void CodeGenerator::VisitLiteralNode(LiteralNode* node) { |
| 682 if (!IsResultNeeded(node)) return; | 681 if (!IsResultNeeded(node)) return; |
| 683 __ PushObject(node->literal()); | 682 __ PushObject(node->literal()); |
| 684 } | 683 } |
| 685 | 684 |
| 686 | 685 |
| 687 void CodeGenerator::VisitTypeNode(TypeNode* node) { | 686 void CodeGenerator::VisitTypeNode(TypeNode* node) { |
| 688 // Type nodes are handled specially by the code generator. | 687 // Type nodes are handled specially by the code generator. |
| 689 UNREACHABLE(); | 688 UNREACHABLE(); |
| 690 } | 689 } |
| 691 | 690 |
| 692 | 691 |
| 693 void CodeGenerator::VisitAssignableNode(AssignableNode* node) { | 692 void CodeGenerator::VisitAssignableNode(AssignableNode* node) { |
| 694 ASSERT(FLAG_enable_type_checks); | 693 ASSERT(FLAG_enable_type_checks); |
| 695 node->expr()->Visit(this); | 694 node->expr()->Visit(this); |
| 696 __ popq(RAX); | 695 __ popq(RAX); |
| 697 GenerateAssertAssignable(node->id(), | 696 GenerateAssertAssignable(node->id(), |
| 698 node->token_index(), | 697 node->token_index(), |
| 698 node->expr(), |
| 699 node->type(), | 699 node->type(), |
| 700 node->dst_name()); | 700 node->dst_name()); |
| 701 if (IsResultNeeded(node)) { | 701 if (IsResultNeeded(node)) { |
| 702 __ pushq(RAX); | 702 __ pushq(RAX); |
| 703 } | 703 } |
| 704 } | 704 } |
| 705 | 705 |
| 706 | 706 |
| 707 void CodeGenerator::VisitClosureNode(ClosureNode* node) { | 707 void CodeGenerator::VisitClosureNode(ClosureNode* node) { |
| 708 const Function& function = node->function(); | 708 const Function& function = node->function(); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 } | 900 } |
| 901 } | 901 } |
| 902 | 902 |
| 903 | 903 |
| 904 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { | 904 void CodeGenerator::VisitStoreLocalNode(StoreLocalNode* node) { |
| 905 node->value()->Visit(this); | 905 node->value()->Visit(this); |
| 906 __ popq(RAX); | 906 __ popq(RAX); |
| 907 if (FLAG_enable_type_checks) { | 907 if (FLAG_enable_type_checks) { |
| 908 GenerateAssertAssignable(node->id(), | 908 GenerateAssertAssignable(node->id(), |
| 909 node->value()->token_index(), | 909 node->value()->token_index(), |
| 910 node->value(), |
| 910 node->local().type(), | 911 node->local().type(), |
| 911 node->local().name()); | 912 node->local().name()); |
| 912 } | 913 } |
| 913 GenerateStoreVariable(node->local(), RAX, R10); | 914 GenerateStoreVariable(node->local(), RAX, R10); |
| 914 if (IsResultNeeded(node)) { | 915 if (IsResultNeeded(node)) { |
| 915 __ pushq(RAX); | 916 __ pushq(RAX); |
| 916 } | 917 } |
| 917 } | 918 } |
| 918 | 919 |
| 919 | 920 |
| 920 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { | 921 void CodeGenerator::VisitLoadInstanceFieldNode(LoadInstanceFieldNode* node) { |
| 921 node->instance()->Visit(this); | 922 node->instance()->Visit(this); |
| 922 MarkDeoptPoint(node->id(), node->token_index()); | 923 MarkDeoptPoint(node->id(), node->token_index()); |
| 923 __ popq(RAX); // Instance. | 924 __ popq(RAX); // Instance. |
| 924 __ movq(RAX, FieldAddress(RAX, node->field().Offset())); | 925 __ movq(RAX, FieldAddress(RAX, node->field().Offset())); |
| 925 if (IsResultNeeded(node)) { | 926 if (IsResultNeeded(node)) { |
| 926 __ pushq(RAX); | 927 __ pushq(RAX); |
| 927 } | 928 } |
| 928 } | 929 } |
| 929 | 930 |
| 930 | 931 |
| 931 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { | 932 void CodeGenerator::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) { |
| 932 node->instance()->Visit(this); | 933 node->instance()->Visit(this); |
| 933 node->value()->Visit(this); | 934 node->value()->Visit(this); |
| 934 MarkDeoptPoint(node->id(), node->token_index()); | 935 MarkDeoptPoint(node->id(), node->token_index()); |
| 935 __ popq(RAX); // Value. | 936 __ popq(RAX); // Value. |
| 936 if (FLAG_enable_type_checks) { | 937 if (FLAG_enable_type_checks) { |
| 937 GenerateAssertAssignable(node->id(), | 938 GenerateAssertAssignable(node->id(), |
| 938 node->value()->token_index(), | 939 node->value()->token_index(), |
| 940 node->value(), |
| 939 AbstractType::ZoneHandle(node->field().type()), | 941 AbstractType::ZoneHandle(node->field().type()), |
| 940 String::ZoneHandle(node->field().name())); | 942 String::ZoneHandle(node->field().name())); |
| 941 } | 943 } |
| 942 __ popq(R10); // Instance. | 944 __ popq(R10); // Instance. |
| 943 __ StoreIntoObject(R10, FieldAddress(R10, node->field().Offset()), RAX); | 945 __ StoreIntoObject(R10, FieldAddress(R10, node->field().Offset()), RAX); |
| 944 ASSERT(!IsResultNeeded(node)); | 946 ASSERT(!IsResultNeeded(node)); |
| 945 } | 947 } |
| 946 | 948 |
| 947 | 949 |
| 948 // Expects array and index on stack and returns result in RAX. | 950 // Expects array and index on stack and returns result in RAX. |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 } | 1034 } |
| 1033 | 1035 |
| 1034 | 1036 |
| 1035 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { | 1037 void CodeGenerator::VisitStoreStaticFieldNode(StoreStaticFieldNode* node) { |
| 1036 node->value()->Visit(this); | 1038 node->value()->Visit(this); |
| 1037 MarkDeoptPoint(node->id(), node->token_index()); | 1039 MarkDeoptPoint(node->id(), node->token_index()); |
| 1038 __ popq(RAX); // Value. | 1040 __ popq(RAX); // Value. |
| 1039 if (FLAG_enable_type_checks) { | 1041 if (FLAG_enable_type_checks) { |
| 1040 GenerateAssertAssignable(node->id(), | 1042 GenerateAssertAssignable(node->id(), |
| 1041 node->value()->token_index(), | 1043 node->value()->token_index(), |
| 1044 node->value(), |
| 1042 AbstractType::ZoneHandle(node->field().type()), | 1045 AbstractType::ZoneHandle(node->field().type()), |
| 1043 String::ZoneHandle(node->field().name())); | 1046 String::ZoneHandle(node->field().name())); |
| 1044 } | 1047 } |
| 1045 __ LoadObject(RDX, node->field()); | 1048 __ LoadObject(RDX, node->field()); |
| 1046 __ StoreIntoObject(RDX, FieldAddress(RDX, Field::value_offset()), RAX); | 1049 __ StoreIntoObject(RDX, FieldAddress(RDX, Field::value_offset()), RAX); |
| 1047 if (IsResultNeeded(node)) { | 1050 if (IsResultNeeded(node)) { |
| 1048 // The result is the input value. | 1051 // The result is the input value. |
| 1049 __ pushq(RAX); | 1052 __ pushq(RAX); |
| 1050 } | 1053 } |
| 1051 } | 1054 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1118 } | 1121 } |
| 1119 const Immediate value = Immediate(reinterpret_cast<int64_t>(Smi::New(1))); | 1122 const Immediate value = Immediate(reinterpret_cast<int64_t>(Smi::New(1))); |
| 1120 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; | 1123 const char* operator_name = (node->kind() == Token::kINCR) ? "+" : "-"; |
| 1121 __ pushq(RAX); | 1124 __ pushq(RAX); |
| 1122 __ pushq(value); | 1125 __ pushq(value); |
| 1123 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); | 1126 GenerateBinaryOperatorCall(node->id(), node->token_index(), operator_name); |
| 1124 // result is in RAX. | 1127 // result is in RAX. |
| 1125 if (FLAG_enable_type_checks) { | 1128 if (FLAG_enable_type_checks) { |
| 1126 GenerateAssertAssignable(node->id(), | 1129 GenerateAssertAssignable(node->id(), |
| 1127 node->token_index(), | 1130 node->token_index(), |
| 1131 NULL, |
| 1128 node->local().type(), | 1132 node->local().type(), |
| 1129 node->local().name()); | 1133 node->local().name()); |
| 1130 } | 1134 } |
| 1131 GenerateStoreVariable(node->local(), RAX, RDX); | 1135 GenerateStoreVariable(node->local(), RAX, RDX); |
| 1132 if (node->prefix() && IsResultNeeded(node)) { | 1136 if (node->prefix() && IsResultNeeded(node)) { |
| 1133 __ pushq(RAX); | 1137 __ pushq(RAX); |
| 1134 } | 1138 } |
| 1135 } | 1139 } |
| 1136 | 1140 |
| 1137 | 1141 |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1210 | 1214 |
| 1211 static const Class* CoreClass(const char* c_name) { | 1215 static const Class* CoreClass(const char* c_name) { |
| 1212 const String& class_name = String::Handle(String::NewSymbol(c_name)); | 1216 const String& class_name = String::Handle(String::NewSymbol(c_name)); |
| 1213 const Class& cls = Class::ZoneHandle(Library::Handle( | 1217 const Class& cls = Class::ZoneHandle(Library::Handle( |
| 1214 Library::CoreImplLibrary()).LookupClass(class_name)); | 1218 Library::CoreImplLibrary()).LookupClass(class_name)); |
| 1215 ASSERT(!cls.IsNull()); | 1219 ASSERT(!cls.IsNull()); |
| 1216 return &cls; | 1220 return &cls; |
| 1217 } | 1221 } |
| 1218 | 1222 |
| 1219 | 1223 |
| 1220 // Optimize instanceof type test by adding inlined tests for: | 1224 // If instanceof type test cannot be performed successfully at compile time and |
| 1225 // therefore eliminated, optimize it by adding inlined tests for: |
| 1221 // - NULL -> return false. | 1226 // - NULL -> return false. |
| 1222 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1227 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1223 // - Class equality (only if class is not parameterized). | 1228 // - Class equality (only if class is not parameterized). |
| 1224 // Inputs: | 1229 // Inputs: |
| 1225 // - RAX: object. | 1230 // - RAX: object. |
| 1226 // Destroys RCX. | 1231 // Destroys RCX. |
| 1227 // Returns: | 1232 // Returns: |
| 1228 // - true or false on stack. | 1233 // - true or false on stack. |
| 1229 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, | 1234 void CodeGenerator::GenerateInstanceOf(intptr_t node_id, |
| 1230 intptr_t token_index, | 1235 intptr_t token_index, |
| 1236 AstNode* value, |
| 1231 const AbstractType& type, | 1237 const AbstractType& type, |
| 1232 bool negate_result) { | 1238 bool negate_result) { |
| 1233 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1239 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1234 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1240 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1235 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1241 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1236 | 1242 |
| 1237 // All instances are of a subtype of the Object type. | 1243 // All objects are instances of type T if Object type is a subtype of type T. |
| 1238 const Type& object_type = | 1244 const Type& object_type = |
| 1239 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1245 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1240 Error& malformed_error = Error::Handle(); | 1246 Error& malformed_error = Error::Handle(); |
| 1241 if (type.IsInstantiated() && | 1247 if (type.IsInstantiated() && |
| 1242 object_type.IsSubtypeOf(type, &malformed_error)) { | 1248 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1243 __ PushObject(negate_result ? bool_false : bool_true); | 1249 __ PushObject(negate_result ? bool_false : bool_true); |
| 1244 return; | 1250 return; |
| 1245 } | 1251 } |
| 1246 | 1252 |
| 1253 // Eliminate the test if it can be performed successfully at compile time. |
| 1254 if ((value != NULL) && value->IsLiteralNode() && type.IsInstantiated()) { |
| 1255 const Instance& literal_value = value->AsLiteralNode()->literal(); |
| 1256 const Class& cls = Class::Handle(literal_value.clazz()); |
| 1257 if (cls.IsNullClass()) { |
| 1258 ASSERT(literal_value.IsNull() || |
| 1259 (literal_value.raw() == Object::sentinel()) || |
| 1260 (literal_value.raw() == Object::transition_sentinel())); |
| 1261 // A null object is only an instance of Object and Dynamic, which has |
| 1262 // already been checked above (if the type is instantiated). So we can |
| 1263 // return false here if the instance is null (and if the type is |
| 1264 // instantiated). |
| 1265 __ PushObject(negate_result ? bool_true : bool_false); |
| 1266 } else { |
| 1267 Error& malformed_error = Error::Handle(); |
| 1268 if (literal_value.IsInstanceOf(type, |
| 1269 TypeArguments::Handle(), |
| 1270 &malformed_error)) { |
| 1271 __ PushObject(negate_result ? bool_false : bool_true); |
| 1272 } else { |
| 1273 ASSERT(malformed_error.IsNull()); |
| 1274 __ PushObject(negate_result ? bool_true : bool_false); |
| 1275 } |
| 1276 } |
| 1277 return; |
| 1278 } |
| 1279 |
| 1247 const Immediate raw_null = | 1280 const Immediate raw_null = |
| 1248 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1281 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1249 Label done; | 1282 Label done; |
| 1250 // If type is instantiated and non-parameterized, we can inline code | 1283 // If type is instantiated and non-parameterized, we can inline code |
| 1251 // checking whether the tested instance is a Smi. | 1284 // checking whether the tested instance is a Smi. |
| 1252 if (type.IsInstantiated()) { | 1285 if (type.IsInstantiated()) { |
| 1253 // A null object is only an instance of Object and Dynamic, which has | 1286 // A null object is only an instance of Object and Dynamic, which has |
| 1254 // already been checked above (if the type is instantiated). So we can | 1287 // already been checked above (if the type is instantiated). So we can |
| 1255 // return false here if the instance is null (and if the type is | 1288 // return false here if the instance is null (and if the type is |
| 1256 // instantiated). | 1289 // instantiated). |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1328 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1296 __ CompareObject(RCX, type_class); | 1329 __ CompareObject(RCX, type_class); |
| 1297 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1330 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1298 __ PushObject(negate_result ? bool_false : bool_true); | 1331 __ PushObject(negate_result ? bool_false : bool_true); |
| 1299 __ jmp(&done); | 1332 __ jmp(&done); |
| 1300 } | 1333 } |
| 1301 } | 1334 } |
| 1302 __ Bind(&runtime_call); | 1335 __ Bind(&runtime_call); |
| 1303 // Fall through to runtime call. | 1336 // Fall through to runtime call. |
| 1304 } else { | 1337 } else { |
| 1338 ASSERT(!requires_type_arguments); |
| 1339 // Test if object is Smi and for a couple known test-classes. |
| 1305 Label compare_classes; | 1340 Label compare_classes; |
| 1306 __ testq(RAX, Immediate(kSmiTagMask)); | 1341 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1307 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1342 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1308 // Object is Smi. | 1343 // Object is Smi. |
| 1309 const Class& smi_class = Class::Handle(Smi::Class()); | 1344 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1310 // TODO(regis): We should introduce a SmiType. | 1345 // TODO(regis): We should introduce a SmiType. |
| 1311 Error& malformed_error = Error::Handle(); | 1346 Error& malformed_error = Error::Handle(); |
| 1312 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1347 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1313 type_class, | 1348 type_class, |
| 1314 TypeArguments::Handle(), | 1349 TypeArguments::Handle(), |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1376 | 1411 |
| 1377 // Jumps to label if RCX equals the given class. | 1412 // Jumps to label if RCX equals the given class. |
| 1378 // Inputs: | 1413 // Inputs: |
| 1379 // - RCX: tested class. | 1414 // - RCX: tested class. |
| 1380 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { | 1415 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { |
| 1381 __ CompareObject(RCX, cls); | 1416 __ CompareObject(RCX, cls); |
| 1382 __ j(EQUAL, label); | 1417 __ j(EQUAL, label); |
| 1383 } | 1418 } |
| 1384 | 1419 |
| 1385 | 1420 |
| 1386 // Optimize assignable type check by adding inlined tests for: | 1421 // If type check cannot be performed successfully at compile time and therefore |
| 1422 // eliminated, optimize it by adding inlined tests for: |
| 1387 // - NULL -> return NULL. | 1423 // - NULL -> return NULL. |
| 1388 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1424 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1389 // - Class equality (only if class is not parameterized). | 1425 // - Class equality (only if class is not parameterized). |
| 1390 // Inputs: | 1426 // Inputs: |
| 1391 // - RAX: object. | 1427 // - RAX: object. |
| 1392 // Destroys RCX and RDX. | 1428 // Destroys RCX and RDX. |
| 1393 // Returns: | 1429 // Returns: |
| 1394 // - object in RAX for successful assignable check (or throws TypeError). | 1430 // - object in RAX for successful assignable check (or throws TypeError). |
| 1431 // Performance notes: positive checks must be quick, negative checks can be slow |
| 1432 // as they throw an exception. |
| 1395 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1433 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1396 intptr_t token_index, | 1434 intptr_t token_index, |
| 1435 AstNode* value, |
| 1397 const AbstractType& dst_type, | 1436 const AbstractType& dst_type, |
| 1398 const String& dst_name) { | 1437 const String& dst_name) { |
| 1399 ASSERT(FLAG_enable_type_checks); | 1438 ASSERT(FLAG_enable_type_checks); |
| 1400 ASSERT(token_index >= 0); | 1439 ASSERT(token_index >= 0); |
| 1401 ASSERT(!dst_type.IsNull()); | 1440 ASSERT(!dst_type.IsNull()); |
| 1402 ASSERT(dst_type.IsFinalized()); | 1441 ASSERT(dst_type.IsFinalized()); |
| 1403 | 1442 |
| 1404 // Any expression is assignable to the Dynamic type and to the Object type. | 1443 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1405 // Skip the test. | 1444 // Skip the test. |
| 1406 if (!dst_type.IsMalformed() && | 1445 if (!dst_type.IsMalformed() && |
| 1407 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { | 1446 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { |
| 1408 return; | 1447 return; |
| 1409 } | 1448 } |
| 1410 | 1449 |
| 1411 // It is a compile-time error to explicitly return a value (including null) | 1450 // It is a compile-time error to explicitly return a value (including null) |
| 1412 // from a void function. However, functions that do not explicitly return a | 1451 // from a void function. However, functions that do not explicitly return a |
| 1413 // value, implicitly return null. This includes void functions. Therefore, we | 1452 // value, implicitly return null. This includes void functions. Therefore, we |
| 1414 // skip the type test here and trust the parser to only return null in void | 1453 // skip the type test here and trust the parser to only return null in void |
| 1415 // function. | 1454 // function. |
| 1416 if (dst_type.IsVoidType()) { | 1455 if (dst_type.IsVoidType()) { |
| 1417 return; | 1456 return; |
| 1418 } | 1457 } |
| 1419 | 1458 |
| 1459 // Eliminate the test if it can be performed successfully at compile time. |
| 1460 if ((value != NULL) && value->IsLiteralNode()) { |
| 1461 const Instance& literal_value = value->AsLiteralNode()->literal(); |
| 1462 const Class& cls = Class::Handle(literal_value.clazz()); |
| 1463 if (cls.IsNullClass()) { |
| 1464 ASSERT(literal_value.IsNull() || |
| 1465 (literal_value.raw() == Object::sentinel()) || |
| 1466 (literal_value.raw() == Object::transition_sentinel())); |
| 1467 return; |
| 1468 } |
| 1469 Error& malformed_error = Error::Handle(); |
| 1470 if (!dst_type.IsMalformed() && |
| 1471 dst_type.IsInstantiated() && |
| 1472 literal_value.IsInstanceOf(dst_type, |
| 1473 TypeArguments::Handle(), |
| 1474 &malformed_error)) { |
| 1475 return; |
| 1476 } |
| 1477 } |
| 1478 |
| 1420 // A null object is always assignable and is returned as result. | 1479 // A null object is always assignable and is returned as result. |
| 1421 const Immediate raw_null = | 1480 const Immediate raw_null = |
| 1422 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1481 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1423 Label done, runtime_call; | 1482 Label done, runtime_call; |
| 1424 __ cmpq(RAX, raw_null); | 1483 __ cmpq(RAX, raw_null); |
| 1425 __ j(EQUAL, &done); | 1484 __ j(EQUAL, &done); |
| 1426 | 1485 |
| 1427 // Generate throw new TypeError() if the type is malformed. | 1486 // Generate throw new TypeError() if the type is malformed. |
| 1428 if (dst_type.IsMalformed()) { | 1487 if (dst_type.IsMalformed()) { |
| 1429 const Error& error = Error::Handle(dst_type.malformed_error()); | 1488 const Error& error = Error::Handle(dst_type.malformed_error()); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1572 const Function& function = parsed_function_.function(); | 1631 const Function& function = parsed_function_.function(); |
| 1573 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 1632 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 1574 const int num_fixed_params = function.num_fixed_parameters(); | 1633 const int num_fixed_params = function.num_fixed_parameters(); |
| 1575 const int num_opt_params = function.num_optional_parameters(); | 1634 const int num_opt_params = function.num_optional_parameters(); |
| 1576 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); | 1635 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); |
| 1577 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { | 1636 for (int i = 0; i < num_fixed_params + num_opt_params; i++) { |
| 1578 LocalVariable* parameter = scope->VariableAt(i); | 1637 LocalVariable* parameter = scope->VariableAt(i); |
| 1579 GenerateLoadVariable(RAX, *parameter); | 1638 GenerateLoadVariable(RAX, *parameter); |
| 1580 GenerateAssertAssignable(AstNode::kNoId, | 1639 GenerateAssertAssignable(AstNode::kNoId, |
| 1581 parameter->token_index(), | 1640 parameter->token_index(), |
| 1641 NULL, |
| 1582 parameter->type(), | 1642 parameter->type(), |
| 1583 parameter->name()); | 1643 parameter->name()); |
| 1584 } | 1644 } |
| 1585 } | 1645 } |
| 1586 | 1646 |
| 1587 | 1647 |
| 1588 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, | 1648 void CodeGenerator::GenerateConditionTypeCheck(intptr_t node_id, |
| 1589 intptr_t token_index) { | 1649 intptr_t token_index) { |
| 1590 if (!FLAG_enable_type_checks) { | 1650 if (!FLAG_enable_type_checks) { |
| 1591 return; | 1651 return; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1628 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1688 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1629 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1689 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1630 node->left()->Visit(this); | 1690 node->left()->Visit(this); |
| 1631 | 1691 |
| 1632 // The instanceof operator needs special handling. | 1692 // The instanceof operator needs special handling. |
| 1633 if (Token::IsInstanceofOperator(node->kind())) { | 1693 if (Token::IsInstanceofOperator(node->kind())) { |
| 1634 __ popq(RAX); // Left operand. | 1694 __ popq(RAX); // Left operand. |
| 1635 ASSERT(node->right()->IsTypeNode()); | 1695 ASSERT(node->right()->IsTypeNode()); |
| 1636 GenerateInstanceOf(node->id(), | 1696 GenerateInstanceOf(node->id(), |
| 1637 node->token_index(), | 1697 node->token_index(), |
| 1698 node->left(), |
| 1638 node->right()->AsTypeNode()->type(), | 1699 node->right()->AsTypeNode()->type(), |
| 1639 (node->kind() == Token::kISNOT)); | 1700 (node->kind() == Token::kISNOT)); |
| 1640 if (!IsResultNeeded(node)) { | 1701 if (!IsResultNeeded(node)) { |
| 1641 __ popq(RAX); // Pop the result of the instanceof operation. | 1702 __ popq(RAX); // Pop the result of the instanceof operation. |
| 1642 } | 1703 } |
| 1643 return; | 1704 return; |
| 1644 } | 1705 } |
| 1645 | 1706 |
| 1646 node->right()->Visit(this); | 1707 node->right()->Visit(this); |
| 1647 // Both left and right values on stack. | 1708 // Both left and right values on stack. |
| (...skipping 1015 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2663 const Error& error = Error::Handle( | 2724 const Error& error = Error::Handle( |
| 2664 Parser::FormatError(script, token_index, "Error", format, args)); | 2725 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2665 va_end(args); | 2726 va_end(args); |
| 2666 Isolate::Current()->long_jump_base()->Jump(1, error); | 2727 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2667 UNREACHABLE(); | 2728 UNREACHABLE(); |
| 2668 } | 2729 } |
| 2669 | 2730 |
| 2670 } // namespace dart | 2731 } // namespace dart |
| 2671 | 2732 |
| 2672 #endif // defined TARGET_ARCH_X64 | 2733 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |