| 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/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 GrowableArray<const Class*> args; | 134 GrowableArray<const Class*> args; |
| 135 args.Add(CoreClass("ObjectArray")); | 135 args.Add(CoreClass("ObjectArray")); |
| 136 args.Add(CoreClass("GrowableObjectArray")); | 136 args.Add(CoreClass("GrowableObjectArray")); |
| 137 args.Add(CoreClass("ImmutableArray")); | 137 args.Add(CoreClass("ImmutableArray")); |
| 138 CheckClasses(args, is_instance_lbl, &unknown); | 138 CheckClasses(args, is_instance_lbl, &unknown); |
| 139 __ Bind(&unknown); | 139 __ Bind(&unknown); |
| 140 } | 140 } |
| 141 return GenerateSubtype1TestCacheLookup( | 141 return GenerateSubtype1TestCacheLookup( |
| 142 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); | 142 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 143 } | 143 } |
| 144 return SubtypeTestCache::null(); | 144 // If one type argument only, check if type argument is Object or Dynamic. |
| 145 if (type_arguments.Length() == 1) { |
| 146 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 147 type_arguments.TypeAt(0)); |
| 148 ASSERT(!tp_argument.IsMalformed()); |
| 149 if (tp_argument.IsType()) { |
| 150 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 151 // Check if type argument is dynamic or Object. |
| 152 const Type& object_type = |
| 153 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 154 Error& malformed_error = Error::Handle(); |
| 155 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 156 // Instance class test only necessary. |
| 157 return GenerateSubtype1TestCacheLookup( |
| 158 cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 159 } |
| 160 } |
| 161 } |
| 162 |
| 163 // Regular subtype test cache involving instance's type arguments. |
| 164 const SubtypeTestCache& type_test_cache = |
| 165 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 166 Label runtime_call; |
| 167 const Immediate raw_null = |
| 168 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 169 __ LoadObject(R10, type_test_cache); |
| 170 __ pushq(R10); // Subtype test cache. |
| 171 __ pushq(RAX); // Instance. |
| 172 __ pushq(raw_null); // Unused. |
| 173 __ call(&StubCode::Subtype2TestCacheLabel()); |
| 174 __ popq(RAX); // Discard. |
| 175 __ popq(RAX); // Restore receiver. |
| 176 __ popq(RDX); // Discard. |
| 177 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 178 |
| 179 __ cmpq(RCX, raw_null); |
| 180 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 181 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 182 __ CompareObject(RCX, bool_true); |
| 183 __ j(EQUAL, is_instance_lbl); |
| 184 __ jmp(is_not_instance_lbl); |
| 185 __ Bind(&runtime_call); |
| 186 return type_test_cache.raw(); |
| 145 } | 187 } |
| 146 | 188 |
| 147 | 189 |
| 148 // R10: instance class to check. | 190 // R10: instance class to check. |
| 149 void FlowGraphCompiler::CheckClasses(const GrowableArray<const Class*>& classes, | 191 void FlowGraphCompiler::CheckClasses(const GrowableArray<const Class*>& classes, |
| 150 Label* is_instance_lbl, | 192 Label* is_instance_lbl, |
| 151 Label* is_not_instance_lbl) { | 193 Label* is_not_instance_lbl) { |
| 152 for (intptr_t i = 0; i < classes.length(); i++) { | 194 for (intptr_t i = 0; i < classes.length(); i++) { |
| 153 __ CompareObject(R10, *classes[i]); | 195 __ CompareObject(R10, *classes[i]); |
| 154 __ j(EQUAL, is_instance_lbl); | 196 __ j(EQUAL, is_instance_lbl); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 __ cmpq(RCX, raw_null); | 341 __ cmpq(RCX, raw_null); |
| 300 __ j(EQUAL, &runtime_call, Assembler::kNearJump); | 342 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 301 __ CompareObject(RCX, bool_true); | 343 __ CompareObject(RCX, bool_true); |
| 302 __ j(EQUAL, is_instance_lbl); | 344 __ j(EQUAL, is_instance_lbl); |
| 303 __ jmp(is_not_instance_lbl); | 345 __ jmp(is_not_instance_lbl); |
| 304 __ Bind(&runtime_call); | 346 __ Bind(&runtime_call); |
| 305 return type_test_cache.raw(); | 347 return type_test_cache.raw(); |
| 306 } | 348 } |
| 307 | 349 |
| 308 | 350 |
| 351 // Generates inlined check if 'type' is a type parameter or type itsef |
| 352 // RAX: instance (preserved). |
| 309 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 353 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 310 const AbstractType& type, | 354 const AbstractType& type, |
| 311 intptr_t cid, | 355 intptr_t cid, |
| 312 intptr_t token_index, | 356 intptr_t token_index, |
| 313 Label* is_instance_lbl, | 357 Label* is_instance_lbl, |
| 314 Label* is_not_instance_lbl) { | 358 Label* is_not_instance_lbl) { |
| 359 ASSERT(!type.IsInstantiated()); |
| 360 const Immediate raw_null = |
| 361 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 362 if (type.IsTypeParameter()) { |
| 363 // Load instantiator (or null) and instantiator type arguments on stack. |
| 364 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 365 // RDX: instantiator type arguments. |
| 366 // Check if type argument is Dynamic. |
| 367 __ cmpq(RDX, raw_null); |
| 368 __ j(EQUAL, is_instance_lbl); |
| 369 // Can handle only type arguments that are instances of TypeArguments. |
| 370 // (runtime checks canonicalize type arguments). |
| 371 Label fall_through; |
| 372 __ movq(R10, FieldAddress(RDX, Object::class_offset())); |
| 373 __ CompareObject(R10, Object::ZoneHandle(Object::type_arguments_class())); |
| 374 __ j(NOT_EQUAL, &fall_through); |
| 375 __ movq(RDI, |
| 376 FieldAddress(RDX, TypeArguments::type_at_offset(type.Index()))); |
| 377 // RDI: Concrete type. |
| 378 // Check if it is Dynamic, |
| 379 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); |
| 380 __ j(EQUAL, is_instance_lbl); |
| 381 __ cmpq(RDI, raw_null); |
| 382 __ j(EQUAL, is_instance_lbl); |
| 383 // For Smi check quickly against int and num interface types. |
| 384 Label not_smi; |
| 385 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 386 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 387 __ CompareObject(RDI, Type::ZoneHandle(Type::IntInterface())); |
| 388 __ j(EQUAL, is_instance_lbl); |
| 389 __ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface())); |
| 390 __ j(EQUAL, is_instance_lbl); |
| 391 __ jmp(&fall_through); |
| 392 __ Bind(¬_smi); |
| 393 // RDX: instantiator type arguments. |
| 394 // RAX: instance. |
| 395 const SubtypeTestCache& type_test_cache = |
| 396 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 397 __ LoadObject(R10, type_test_cache); |
| 398 __ pushq(R10); // Subtype test cache. |
| 399 __ pushq(RAX); // Instance |
| 400 __ pushq(RDX); // Instantiator type arguments. |
| 401 __ call(&StubCode::Subtype3TestCacheLabel()); |
| 402 __ popq(RDX); // Discard type arguments. |
| 403 __ popq(RAX); // Restore receiver. |
| 404 __ popq(RDX); // Discard subtype test cache. |
| 405 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 406 __ cmpq(RCX, raw_null); |
| 407 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 408 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 409 __ CompareObject(RCX, bool_true); |
| 410 __ j(EQUAL, is_instance_lbl); |
| 411 __ jmp(is_not_instance_lbl); |
| 412 __ Bind(&fall_through); |
| 413 return type_test_cache.raw(); |
| 414 } |
| 415 if (type.IsType()) { |
| 416 Label fall_through; |
| 417 __ testq(RAX, Immediate(kSmiTagMask)); // Is instance Smi? |
| 418 __ j(ZERO, is_not_instance_lbl); |
| 419 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 420 // Uninstantiated type class is known at compile time, but the type |
| 421 // arguments are determined at runtime by the instantiator. |
| 422 const SubtypeTestCache& type_test_cache = |
| 423 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 424 __ LoadObject(R10, type_test_cache); |
| 425 __ pushq(R10); // Subtype test cache. |
| 426 __ pushq(RAX); // Instance. |
| 427 __ pushq(RDX); // Instantiator type arguments. |
| 428 __ call(&StubCode::Subtype3TestCacheLabel()); |
| 429 __ popq(RDX); // Discard type arguments. |
| 430 __ popq(RAX); // Restore receiver. |
| 431 __ popq(RDX); // Discard subtype test cache. |
| 432 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 433 __ cmpq(RCX, raw_null); |
| 434 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 435 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 436 __ CompareObject(RCX, bool_true); |
| 437 __ j(EQUAL, is_instance_lbl); |
| 438 __ jmp(is_not_instance_lbl); |
| 439 __ Bind(&fall_through); |
| 440 return type_test_cache.raw(); |
| 441 } |
| 315 return SubtypeTestCache::null(); | 442 return SubtypeTestCache::null(); |
| 316 } | 443 } |
| 317 | 444 |
| 318 | 445 |
| 319 // Inputs: | 446 // Inputs: |
| 320 // - RAX: instance to test against (preserved). | 447 // - RAX: instance to test against (preserved). |
| 321 // - RDX: optional instantiator type arguments (preserved). | 448 // - RDX: optional instantiator type arguments (preserved). |
| 322 // Destroys RCX. | 449 // Destroys RCX. |
| 323 // Returns: | 450 // Returns: |
| 324 // - unchanged object in RAX and optional instantiator type arguments in RDX. | 451 // - unchanged object in RAX and optional instantiator type arguments in RDX. |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 __ Bind(&done); | 924 __ Bind(&done); |
| 798 } | 925 } |
| 799 | 926 |
| 800 | 927 |
| 801 // Optimize instanceof type test by adding inlined tests for: | 928 // Optimize instanceof type test by adding inlined tests for: |
| 802 // - NULL -> return false. | 929 // - NULL -> return false. |
| 803 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 930 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 804 // - Class equality (only if class is not parameterized). | 931 // - Class equality (only if class is not parameterized). |
| 805 // Inputs: | 932 // Inputs: |
| 806 // - RAX: object. | 933 // - RAX: object. |
| 807 // - RDX: oinstantiator type arguments or raw_null. | 934 // - RDX: instantiator type arguments or raw_null. |
| 808 // - RCX: instantiator or raw_null. | 935 // - RCX: instantiator or raw_null. |
| 809 // Destroys RCX and RDX. | 936 // Destroys RCX and RDX. |
| 810 // Returns: | 937 // Returns: |
| 811 // - true or false in RAX. | 938 // - true or false in RAX. |
| 812 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, | 939 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, |
| 813 intptr_t token_index, | 940 intptr_t token_index, |
| 814 intptr_t try_index, | 941 intptr_t try_index, |
| 815 const AbstractType& type, | 942 const AbstractType& type, |
| 816 bool negate_result) { | 943 bool negate_result) { |
| 817 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 944 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 818 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 945 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 819 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 946 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 820 | 947 |
| 821 const Immediate raw_null = | 948 const Immediate raw_null = |
| 822 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 949 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 823 Label is_instance, is_not_instance; | 950 Label is_instance, is_not_instance; |
| 824 __ pushq(RCX); // Temporary store instantiator on stack. | 951 __ pushq(RCX); // Store instantiator on stack. |
| 952 __ pushq(RDX); // Store instantiator type arguments. |
| 825 // If type is instantiated and non-parameterized, we can inline code | 953 // If type is instantiated and non-parameterized, we can inline code |
| 826 // checking whether the tested instance is a Smi. | 954 // checking whether the tested instance is a Smi. |
| 827 if (type.IsInstantiated()) { | 955 if (type.IsInstantiated()) { |
| 828 // A null object is only an instance of Object and Dynamic, which has | 956 // A null object is only an instance of Object and Dynamic, which has |
| 829 // already been checked above (if the type is instantiated). So we can | 957 // already been checked above (if the type is instantiated). So we can |
| 830 // return false here if the instance is null (and if the type is | 958 // return false here if the instance is null (and if the type is |
| 831 // instantiated). | 959 // instantiated). |
| 832 // We can only inline this null check if the type is instantiated at compile | 960 // We can only inline this null check if the type is instantiated at compile |
| 833 // time, since an uninstantiated type at compile time could be Object or | 961 // time, since an uninstantiated type at compile time could be Object or |
| 834 // Dynamic at run time. | 962 // Dynamic at run time. |
| 835 __ cmpq(RAX, raw_null); | 963 __ cmpq(RAX, raw_null); |
| 836 __ j(EQUAL, &is_not_instance); | 964 __ j(EQUAL, &is_not_instance); |
| 837 } | 965 } |
| 838 | 966 |
| 839 // Generate inline instanceof test. | 967 // Generate inline instanceof test. |
| 840 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 968 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 841 test_cache = GenerateInlineInstanceof(cid, token_index, type, | 969 test_cache = GenerateInlineInstanceof(cid, token_index, type, |
| 842 &is_instance, &is_not_instance); | 970 &is_instance, &is_not_instance); |
| 843 | 971 |
| 844 // Generate runtime call. | 972 // Generate runtime call. |
| 973 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 974 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 845 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 975 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 846 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. | 976 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. |
| 847 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. | 977 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. |
| 848 __ pushq(RAX); // Push the instance. | 978 __ pushq(RAX); // Push the instance. |
| 849 __ PushObject(type); // Push the type. | 979 __ PushObject(type); // Push the type. |
| 850 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null. | 980 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
| 851 if (type.IsInstantiated()) { | 981 __ pushq(RDX); // Instantiator type arguments. |
| 852 __ pushq(raw_null); // Null instantiator type arguments. | |
| 853 } else { | |
| 854 __ pushq(RDX); // Instantiator type arguments. | |
| 855 } | |
| 856 __ LoadObject(RAX, test_cache); | 982 __ LoadObject(RAX, test_cache); |
| 857 __ pushq(RAX); | 983 __ pushq(RAX); |
| 858 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); | 984 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); |
| 859 // Pop the two parameters supplied to the runtime entry. The result of the | 985 // Pop the two parameters supplied to the runtime entry. The result of the |
| 860 // instanceof runtime call will be left as the result of the operation. | 986 // instanceof runtime call will be left as the result of the operation. |
| 861 __ Drop(7); | 987 __ Drop(7); |
| 862 Label done; | 988 Label done; |
| 863 if (negate_result) { | 989 if (negate_result) { |
| 864 __ popq(RDX); | 990 __ popq(RDX); |
| 865 __ LoadObject(RAX, bool_true); | 991 __ LoadObject(RAX, bool_true); |
| 866 __ cmpq(RDX, RAX); | 992 __ cmpq(RDX, RAX); |
| 867 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 993 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 868 __ LoadObject(RAX, bool_false); | 994 __ LoadObject(RAX, bool_false); |
| 869 } else { | 995 } else { |
| 870 __ popq(RAX); | 996 __ popq(RAX); |
| 871 } | 997 } |
| 872 __ jmp(&done, Assembler::kNearJump); | 998 __ jmp(&done, Assembler::kNearJump); |
| 873 | 999 |
| 874 __ Bind(&is_not_instance); | 1000 __ Bind(&is_not_instance); |
| 875 __ LoadObject(RAX, negate_result ? bool_true : bool_false); | 1001 __ LoadObject(RAX, negate_result ? bool_true : bool_false); |
| 876 __ jmp(&done, Assembler::kNearJump); | 1002 __ jmp(&done, Assembler::kNearJump); |
| 877 | 1003 |
| 878 __ Bind(&is_instance); | 1004 __ Bind(&is_instance); |
| 879 __ LoadObject(RAX, negate_result ? bool_false : bool_true); | 1005 __ LoadObject(RAX, negate_result ? bool_false : bool_true); |
| 880 __ Bind(&done); | 1006 __ Bind(&done); |
| 1007 __ popq(RDX); // Remove pushed instantiator type arguments.. |
| 881 __ popq(RCX); // Remove pushed instantiator. | 1008 __ popq(RCX); // Remove pushed instantiator. |
| 882 } | 1009 } |
| 883 | 1010 |
| 884 | 1011 |
| 885 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { | 1012 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { |
| 886 const Immediate raw_null = | 1013 const Immediate raw_null = |
| 887 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1014 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 888 if (comp->type_arguments() == NULL) { | 1015 if (comp->type_arguments() == NULL) { |
| 889 __ movq(RDX, raw_null); | 1016 __ movq(RDX, raw_null); |
| 890 } else { | 1017 } else { |
| (...skipping 908 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1799 | 1926 |
| 1800 | 1927 |
| 1801 void FlowGraphCompiler::FinalizeComments(const Code& code) { | 1928 void FlowGraphCompiler::FinalizeComments(const Code& code) { |
| 1802 code.set_comments(assembler_->GetCodeComments()); | 1929 code.set_comments(assembler_->GetCodeComments()); |
| 1803 } | 1930 } |
| 1804 | 1931 |
| 1805 | 1932 |
| 1806 } // namespace dart | 1933 } // namespace dart |
| 1807 | 1934 |
| 1808 #endif // defined TARGET_ARCH_X64 | 1935 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |