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