| 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 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 | 99 |
| 100 // Inputs: | 100 // Inputs: |
| 101 // - RAX: object (preserved). | 101 // - RAX: object (preserved). |
| 102 // - RDX: optional instantiator type arguments (preserved). | 102 // - RDX: optional instantiator type arguments (preserved). |
| 103 // Destroys RCX. | 103 // Destroys RCX. |
| 104 // Returns: | 104 // Returns: |
| 105 // - unchanged object in RAX and optional instantiator type arguments in RDX. | 105 // - unchanged object in RAX and optional instantiator type arguments in RDX. |
| 106 // Note that this inlined code must be followed by the runtime_call code, as it | 106 // Note that this inlined code must be followed by the runtime_call code, as it |
| 107 // may fall through to it. Otherwise, this inline code will jump to the label | 107 // may fall through to it. Otherwise, this inline code will jump to the label |
| 108 // is_instance or to the label is_not_instance. | 108 // is_instance or to the label is_not_instance. |
| 109 void FlowGraphCompiler::GenerateInlineInstanceof(const AbstractType& type, | 109 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 110 Label* is_instance, | 110 intptr_t cid, |
| 111 Label* is_not_instance) { | 111 intptr_t token_index, |
| 112 const AbstractType& type, |
| 113 Label* is_instance, |
| 114 Label* is_not_instance) { |
| 112 Label runtime_call; | 115 Label runtime_call; |
| 113 if (type.IsInstantiated()) { | 116 if (type.IsInstantiated()) { |
| 114 const Class& type_class = Class::ZoneHandle(type.type_class()); | 117 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 115 const bool requires_type_arguments = type_class.HasTypeArguments(); | 118 const bool requires_type_arguments = type_class.HasTypeArguments(); |
| 116 // A Smi object cannot be the instance of a parameterized class. | 119 // A Smi object cannot be the instance of a parameterized class. |
| 117 // A class equality check is only applicable with a dst type of a | 120 // A class equality check is only applicable with a dst type of a |
| 118 // non-parameterized class or with a raw dst type of a parameterized class. | 121 // non-parameterized class or with a raw dst type of a parameterized class. |
| 119 if (requires_type_arguments) { | 122 if (requires_type_arguments) { |
| 120 const AbstractTypeArguments& type_arguments = | 123 const AbstractTypeArguments& type_arguments = |
| 121 AbstractTypeArguments::Handle(type.arguments()); | 124 AbstractTypeArguments::Handle(type.arguments()); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset())); | 265 __ movq(RCX, FieldAddress(RCX, Type::type_class_offset())); |
| 263 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset())); | 266 __ movq(R10, FieldAddress(RCX, Class::type_parameters_offset())); |
| 264 // Check that class of type has no type parameters. | 267 // Check that class of type has no type parameters. |
| 265 __ cmpq(R10, raw_null); | 268 __ cmpq(R10, raw_null); |
| 266 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 269 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 267 // TODO(srdjan): Implement subtype test cache. | 270 // TODO(srdjan): Implement subtype test cache. |
| 268 // Fall through to runtime call. | 271 // Fall through to runtime call. |
| 269 } | 272 } |
| 270 } | 273 } |
| 271 __ Bind(&runtime_call); | 274 __ Bind(&runtime_call); |
| 275 return SubtypeTestCache::null(); |
| 272 } | 276 } |
| 273 | 277 |
| 274 | 278 |
| 275 // Optimize assignable type check by adding inlined tests for: | 279 // Optimize assignable type check by adding inlined tests for: |
| 276 // - NULL -> return NULL. | 280 // - NULL -> return NULL. |
| 277 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 281 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 278 // - Class equality (only if class is not parameterized). | 282 // - Class equality (only if class is not parameterized). |
| 279 // Inputs: | 283 // Inputs: |
| 280 // - RAX: object. | 284 // - RAX: object. |
| 281 // - RDX: optional instantiator type arguments. | 285 // - RDX: instantiator type arguments or raw_null. |
| 286 // - RCX: instantiator or raw_null. |
| 282 // Destroys RCX and RDX. | 287 // Destroys RCX and RDX. |
| 283 // Returns: | 288 // Returns: |
| 284 // - object in RAX for successful assignable check (or throws TypeError). | 289 // - object in RAX for successful assignable check (or throws TypeError). |
| 285 // Performance notes: positive checks must be quick, negative checks can be slow | 290 // Performance notes: positive checks must be quick, negative checks can be slow |
| 286 // as they throw an exception. | 291 // as they throw an exception. |
| 287 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, | 292 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, |
| 288 intptr_t token_index, | 293 intptr_t token_index, |
| 289 intptr_t try_index, | 294 intptr_t try_index, |
| 290 const AbstractType& dst_type, | 295 const AbstractType& dst_type, |
| 291 const String& dst_name) { | 296 const String& dst_name) { |
| 292 ASSERT(FLAG_enable_type_checks); | 297 ASSERT(FLAG_enable_type_checks); |
| 293 ASSERT(token_index >= 0); | 298 ASSERT(token_index >= 0); |
| 294 ASSERT(!dst_type.IsNull()); | 299 ASSERT(!dst_type.IsNull()); |
| 295 ASSERT(dst_type.IsFinalized()); | 300 ASSERT(dst_type.IsFinalized()); |
| 301 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 296 ASSERT(dst_type.IsMalformed() || | 302 ASSERT(dst_type.IsMalformed() || |
| 297 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 303 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 298 ASSERT(!dst_type.IsVoidType()); | 304 ASSERT(!dst_type.IsVoidType()); |
| 299 | 305 __ pushq(RCX); // Temporary store instantiator on stack. |
| 300 // A null object is always assignable and is returned as result. | 306 // A null object is always assignable and is returned as result. |
| 301 const Immediate raw_null = | 307 const Immediate raw_null = |
| 302 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 308 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 303 Label is_assignable, runtime_call; | 309 Label is_assignable, runtime_call; |
| 304 __ cmpq(RAX, raw_null); | 310 __ cmpq(RAX, raw_null); |
| 305 __ j(EQUAL, &is_assignable); | 311 __ j(EQUAL, &is_assignable); |
| 306 | 312 |
| 307 // Generate throw new TypeError() if the type is malformed. | 313 // Generate throw new TypeError() if the type is malformed. |
| 308 if (dst_type.IsMalformed()) { | 314 if (dst_type.IsMalformed()) { |
| 309 const Error& error = Error::Handle(dst_type.malformed_error()); | 315 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 310 const String& error_message = String::ZoneHandle( | 316 const String& error_message = String::ZoneHandle( |
| 311 String::NewSymbol(error.ToErrorCString())); | 317 String::NewSymbol(error.ToErrorCString())); |
| 312 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 318 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 313 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. | 319 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. |
| 314 __ pushq(RAX); // Push the source object. | 320 __ pushq(RAX); // Push the source object. |
| 315 __ PushObject(dst_name); // Push the name of the destination. | 321 __ PushObject(dst_name); // Push the name of the destination. |
| 316 __ PushObject(error_message); | 322 __ PushObject(error_message); |
| 317 GenerateCallRuntime(cid, | 323 GenerateCallRuntime(cid, |
| 318 token_index, | 324 token_index, |
| 319 try_index, | 325 try_index, |
| 320 kMalformedTypeErrorRuntimeEntry); | 326 kMalformedTypeErrorRuntimeEntry); |
| 321 // We should never return here. | 327 // We should never return here. |
| 322 __ int3(); | 328 __ int3(); |
| 323 | 329 |
| 324 __ Bind(&is_assignable); // For a null object. | 330 __ Bind(&is_assignable); // For a null object. |
| 325 return; | 331 return; |
| 326 } | 332 } |
| 327 | 333 |
| 328 // Generate inline type check, linking to runtime call if not assignable. | 334 // Generate inline type check, linking to runtime call if not assignable. |
| 329 GenerateInlineInstanceof(dst_type, &is_assignable, &runtime_call); | 335 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 330 | 336 test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, |
| 337 &is_assignable, &runtime_call); |
| 331 __ Bind(&runtime_call); | 338 __ Bind(&runtime_call); |
| 339 __ movq(RCX, Address(RSP, 0)); // Get instantiator. |
| 332 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 340 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 333 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. | 341 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. |
| 334 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. | 342 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. |
| 335 __ pushq(RAX); // Push the source object. | 343 __ pushq(RAX); // Push the source object. |
| 336 __ PushObject(dst_type); // Push the type of the destination. | 344 __ PushObject(dst_type); // Push the type of the destination. |
| 337 __ pushq(raw_null); // TODO(srdjan): Instantiator. | 345 __ pushq(RCX); // Instantiator. |
| 338 if (dst_type.IsInstantiated()) { | 346 __ pushq(RDX); // Instantiator type arguments. |
| 339 __ pushq(raw_null); // Null instantiator type arguments. | |
| 340 } else { | |
| 341 __ pushq(RDX); // Instantiator type arguments. | |
| 342 } | |
| 343 __ PushObject(dst_name); // Push the name of the destination. | 347 __ PushObject(dst_name); // Push the name of the destination. |
| 344 __ pushq(raw_null); // SubtypeTestCache not yet supported. | 348 __ LoadObject(RAX, test_cache); |
| 349 __ pushq(RAX); |
| 345 GenerateCallRuntime(cid, | 350 GenerateCallRuntime(cid, |
| 346 token_index, | 351 token_index, |
| 347 try_index, | 352 try_index, |
| 348 kTypeCheckRuntimeEntry); | 353 kTypeCheckRuntimeEntry); |
| 349 // Pop the parameters supplied to the runtime entry. The result of the | 354 // Pop the parameters supplied to the runtime entry. The result of the |
| 350 // type check runtime call is the checked value. | 355 // type check runtime call is the checked value. |
| 351 __ Drop(8); | 356 __ Drop(8); |
| 352 __ popq(RAX); | 357 __ popq(RAX); |
| 353 | 358 |
| 354 __ Bind(&is_assignable); | 359 __ Bind(&is_assignable); |
| 360 __ popq(RCX); // Remove pushed instantiator. |
| 355 } | 361 } |
| 356 | 362 |
| 357 | 363 |
| 358 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { | 364 void FlowGraphCompiler::LoadValue(Register dst, Value* value) { |
| 359 if (value->IsConstant()) { | 365 if (value->IsConstant()) { |
| 360 ConstantVal* constant = value->AsConstant(); | 366 ConstantVal* constant = value->AsConstant(); |
| 361 if (constant->value().IsSmi()) { | 367 if (constant->value().IsSmi()) { |
| 362 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); | 368 int64_t imm = reinterpret_cast<int64_t>(constant->value().raw()); |
| 363 __ movq(dst, Immediate(imm)); | 369 __ movq(dst, Immediate(imm)); |
| 364 } else { | 370 } else { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 375 LoadValue(RAX, val); | 381 LoadValue(RAX, val); |
| 376 } | 382 } |
| 377 | 383 |
| 378 | 384 |
| 379 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { | 385 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { |
| 380 LoadValue(RAX, val); | 386 LoadValue(RAX, val); |
| 381 } | 387 } |
| 382 | 388 |
| 383 | 389 |
| 384 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { | 390 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { |
| 385 if (comp->instantiator_type_arguments() != NULL) { | 391 const Immediate raw_null = |
| 386 __ popq(RDX); | 392 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 393 if (comp->instantiator_type_arguments() == NULL) { |
| 394 __ movq(RDX, raw_null); |
| 395 } else { |
| 396 LoadValue(RDX, comp->instantiator_type_arguments()); |
| 397 } |
| 398 if (comp->instantiator() == NULL) { |
| 399 __ movq(RCX, raw_null); |
| 400 } else { |
| 401 LoadValue(RCX, comp->instantiator()); |
| 387 } | 402 } |
| 388 LoadValue(RAX, comp->value()); | 403 LoadValue(RAX, comp->value()); |
| 389 GenerateAssertAssignable(comp->cid(), | 404 GenerateAssertAssignable(comp->cid(), |
| 390 comp->token_index(), | 405 comp->token_index(), |
| 391 comp->try_index(), | 406 comp->try_index(), |
| 392 comp->dst_type(), | 407 comp->dst_type(), |
| 393 comp->dst_name()); | 408 comp->dst_name()); |
| 394 } | 409 } |
| 395 | 410 |
| 396 | 411 |
| (...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 __ Bind(&done); | 762 __ Bind(&done); |
| 748 } | 763 } |
| 749 | 764 |
| 750 | 765 |
| 751 // Optimize instanceof type test by adding inlined tests for: | 766 // Optimize instanceof type test by adding inlined tests for: |
| 752 // - NULL -> return false. | 767 // - NULL -> return false. |
| 753 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 768 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 754 // - Class equality (only if class is not parameterized). | 769 // - Class equality (only if class is not parameterized). |
| 755 // Inputs: | 770 // Inputs: |
| 756 // - RAX: object. | 771 // - RAX: object. |
| 757 // - RDX: optional instantiator type arguments. | 772 // - RDX: oinstantiator type arguments or raw_null. |
| 773 // - RCX: instantiator or raw_null. |
| 758 // Destroys RCX and RDX. | 774 // Destroys RCX and RDX. |
| 759 // Returns: | 775 // Returns: |
| 760 // - true or false in RAX. | 776 // - true or false in RAX. |
| 761 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, | 777 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, |
| 762 intptr_t token_index, | 778 intptr_t token_index, |
| 763 intptr_t try_index, | 779 intptr_t try_index, |
| 764 const AbstractType& type, | 780 const AbstractType& type, |
| 765 bool negate_result) { | 781 bool negate_result) { |
| 766 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 782 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 767 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 783 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 768 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 784 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 769 | 785 |
| 770 const Immediate raw_null = | 786 const Immediate raw_null = |
| 771 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 787 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 772 Label is_instance, is_not_instance; | 788 Label is_instance, is_not_instance; |
| 789 __ pushq(RCX); // Temporary store instantiator on stack. |
| 773 // If type is instantiated and non-parameterized, we can inline code | 790 // If type is instantiated and non-parameterized, we can inline code |
| 774 // checking whether the tested instance is a Smi. | 791 // checking whether the tested instance is a Smi. |
| 775 if (type.IsInstantiated()) { | 792 if (type.IsInstantiated()) { |
| 776 // A null object is only an instance of Object and Dynamic, which has | 793 // A null object is only an instance of Object and Dynamic, which has |
| 777 // already been checked above (if the type is instantiated). So we can | 794 // already been checked above (if the type is instantiated). So we can |
| 778 // return false here if the instance is null (and if the type is | 795 // return false here if the instance is null (and if the type is |
| 779 // instantiated). | 796 // instantiated). |
| 780 // We can only inline this null check if the type is instantiated at compile | 797 // We can only inline this null check if the type is instantiated at compile |
| 781 // time, since an uninstantiated type at compile time could be Object or | 798 // time, since an uninstantiated type at compile time could be Object or |
| 782 // Dynamic at run time. | 799 // Dynamic at run time. |
| 783 __ cmpq(RAX, raw_null); | 800 __ cmpq(RAX, raw_null); |
| 784 __ j(EQUAL, &is_not_instance); | 801 __ j(EQUAL, &is_not_instance); |
| 785 } | 802 } |
| 786 | 803 |
| 787 // Generate inline instanceof test. | 804 // Generate inline instanceof test. |
| 788 GenerateInlineInstanceof(type, &is_instance, &is_not_instance); | 805 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 806 test_cache = GenerateInlineInstanceof(cid, token_index, type, |
| 807 &is_instance, &is_not_instance); |
| 789 | 808 |
| 790 // Generate runtime call. | 809 // Generate runtime call. |
| 791 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 810 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 792 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. | 811 __ pushq(Immediate(Smi::RawValue(token_index))); // Source location. |
| 793 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. | 812 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. |
| 794 __ pushq(RAX); // Push the instance. | 813 __ pushq(RAX); // Push the instance. |
| 795 __ PushObject(type); // Push the type. | 814 __ PushObject(type); // Push the type. |
| 796 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null. | 815 __ pushq(raw_null); // TODO(srdjan): Pass instantiator instead of null. |
| 797 if (type.IsInstantiated()) { | 816 if (type.IsInstantiated()) { |
| 798 __ pushq(raw_null); // Null instantiator type arguments. | 817 __ pushq(raw_null); // Null instantiator type arguments. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 816 } | 835 } |
| 817 __ jmp(&done, Assembler::kNearJump); | 836 __ jmp(&done, Assembler::kNearJump); |
| 818 | 837 |
| 819 __ Bind(&is_not_instance); | 838 __ Bind(&is_not_instance); |
| 820 __ LoadObject(RAX, negate_result ? bool_true : bool_false); | 839 __ LoadObject(RAX, negate_result ? bool_true : bool_false); |
| 821 __ jmp(&done, Assembler::kNearJump); | 840 __ jmp(&done, Assembler::kNearJump); |
| 822 | 841 |
| 823 __ Bind(&is_instance); | 842 __ Bind(&is_instance); |
| 824 __ LoadObject(RAX, negate_result ? bool_false : bool_true); | 843 __ LoadObject(RAX, negate_result ? bool_false : bool_true); |
| 825 __ Bind(&done); | 844 __ Bind(&done); |
| 845 __ popq(RCX); // Remove pushed instantiator. |
| 826 } | 846 } |
| 827 | 847 |
| 828 | 848 |
| 829 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { | 849 void FlowGraphCompiler::VisitInstanceOf(InstanceOfComp* comp) { |
| 830 if (comp->type_arguments() != NULL) { | 850 const Immediate raw_null = |
| 831 __ popq(RDX); | 851 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 852 if (comp->type_arguments() == NULL) { |
| 853 __ movq(RDX, raw_null); |
| 854 } else { |
| 855 LoadValue(RDX, comp->type_arguments()); |
| 856 } |
| 857 if (comp->instantiator() == NULL) { |
| 858 __ movq(RCX, raw_null); |
| 859 } else { |
| 860 LoadValue(RCX, comp->instantiator()); |
| 832 } | 861 } |
| 833 LoadValue(RAX, comp->value()); | 862 LoadValue(RAX, comp->value()); |
| 834 GenerateInstanceOf(comp->cid(), | 863 GenerateInstanceOf(comp->cid(), |
| 835 comp->token_index(), | 864 comp->token_index(), |
| 836 comp->try_index(), | 865 comp->try_index(), |
| 837 comp->type(), | 866 comp->type(), |
| 838 comp->negate_result()); | 867 comp->negate_result()); |
| 839 } | 868 } |
| 840 | 869 |
| 841 | 870 |
| (...skipping 855 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1697 ASSERT(exception_handlers_list_ != NULL); | 1726 ASSERT(exception_handlers_list_ != NULL); |
| 1698 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( | 1727 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( |
| 1699 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint())); | 1728 exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint())); |
| 1700 code.set_exception_handlers(handlers); | 1729 code.set_exception_handlers(handlers); |
| 1701 } | 1730 } |
| 1702 | 1731 |
| 1703 | 1732 |
| 1704 } // namespace dart | 1733 } // namespace dart |
| 1705 | 1734 |
| 1706 #endif // defined TARGET_ARCH_X64 | 1735 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |