| 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 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 // - NULL -> return false. | 444 // - NULL -> return false. |
| 445 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 445 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 446 // - Class equality (only if class is not parameterized). | 446 // - Class equality (only if class is not parameterized). |
| 447 // Inputs: | 447 // Inputs: |
| 448 // - RAX: object. | 448 // - RAX: object. |
| 449 // - RDX: instantiator type arguments or raw_null. | 449 // - RDX: instantiator type arguments or raw_null. |
| 450 // - RCX: instantiator or raw_null. | 450 // - RCX: instantiator or raw_null. |
| 451 // Clobbers RCX and RDX. | 451 // Clobbers RCX and RDX. |
| 452 // Returns: | 452 // Returns: |
| 453 // - true or false in RAX. | 453 // - true or false in RAX. |
| 454 void FlowGraphCompiler::GenerateInstanceOf(intptr_t deopt_id, | 454 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
| 455 intptr_t token_pos, | |
| 456 const AbstractType& type, | 455 const AbstractType& type, |
| 457 bool negate_result, | 456 bool negate_result, |
| 458 LocationSummary* locs) { | 457 LocationSummary* locs) { |
| 459 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 458 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 460 | 459 |
| 461 const Immediate raw_null = | 460 const Immediate raw_null = |
| 462 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 461 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 463 Label is_instance, is_not_instance; | 462 Label is_instance, is_not_instance; |
| 464 __ pushq(RCX); // Store instantiator on stack. | 463 __ pushq(RCX); // Store instantiator on stack. |
| 465 __ pushq(RDX); // Store instantiator type arguments. | 464 __ pushq(RDX); // Store instantiator type arguments. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 488 // Generate runtime call. | 487 // Generate runtime call. |
| 489 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 488 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 490 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 489 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 491 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 490 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 492 __ pushq(RAX); // Push the instance. | 491 __ pushq(RAX); // Push the instance. |
| 493 __ PushObject(type); // Push the type. | 492 __ PushObject(type); // Push the type. |
| 494 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. | 493 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
| 495 __ pushq(RDX); // Instantiator type arguments. | 494 __ pushq(RDX); // Instantiator type arguments. |
| 496 __ LoadObject(RAX, test_cache); | 495 __ LoadObject(RAX, test_cache); |
| 497 __ pushq(RAX); | 496 __ pushq(RAX); |
| 498 GenerateCallRuntime(deopt_id, token_pos, kInstanceofRuntimeEntry, locs); | 497 GenerateCallRuntime(token_pos, kInstanceofRuntimeEntry, locs); |
| 499 // Pop the parameters supplied to the runtime entry. The result of the | 498 // Pop the parameters supplied to the runtime entry. The result of the |
| 500 // instanceof runtime call will be left as the result of the operation. | 499 // instanceof runtime call will be left as the result of the operation. |
| 501 __ Drop(5); | 500 __ Drop(5); |
| 502 if (negate_result) { | 501 if (negate_result) { |
| 503 __ popq(RDX); | 502 __ popq(RDX); |
| 504 __ LoadObject(RAX, bool_true()); | 503 __ LoadObject(RAX, bool_true()); |
| 505 __ cmpq(RDX, RAX); | 504 __ cmpq(RDX, RAX); |
| 506 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 505 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 507 __ LoadObject(RAX, bool_false()); | 506 __ LoadObject(RAX, bool_false()); |
| 508 } else { | 507 } else { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 527 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 526 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 528 // - Class equality (only if class is not parameterized). | 527 // - Class equality (only if class is not parameterized). |
| 529 // Inputs: | 528 // Inputs: |
| 530 // - RAX: object. | 529 // - RAX: object. |
| 531 // - RDX: instantiator type arguments or raw_null. | 530 // - RDX: instantiator type arguments or raw_null. |
| 532 // - RCX: instantiator or raw_null. | 531 // - RCX: instantiator or raw_null. |
| 533 // Returns: | 532 // Returns: |
| 534 // - object in RAX for successful assignable check (or throws TypeError). | 533 // - object in RAX for successful assignable check (or throws TypeError). |
| 535 // Performance notes: positive checks must be quick, negative checks can be slow | 534 // Performance notes: positive checks must be quick, negative checks can be slow |
| 536 // as they throw an exception. | 535 // as they throw an exception. |
| 537 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t deopt_id, | 536 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
| 538 intptr_t token_pos, | |
| 539 const AbstractType& dst_type, | 537 const AbstractType& dst_type, |
| 540 const String& dst_name, | 538 const String& dst_name, |
| 541 LocationSummary* locs) { | 539 LocationSummary* locs) { |
| 542 ASSERT(token_pos >= 0); | 540 ASSERT(token_pos >= 0); |
| 543 ASSERT(!dst_type.IsNull()); | 541 ASSERT(!dst_type.IsNull()); |
| 544 ASSERT(dst_type.IsFinalized()); | 542 ASSERT(dst_type.IsFinalized()); |
| 545 // Assignable check is skipped in FlowGraphBuilder, not here. | 543 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 546 ASSERT(dst_type.IsMalformed() || | 544 ASSERT(dst_type.IsMalformed() || |
| 547 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 545 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 548 __ pushq(RCX); // Store instantiator. | 546 __ pushq(RCX); // Store instantiator. |
| 549 __ pushq(RDX); // Store instantiator type arguments. | 547 __ pushq(RDX); // Store instantiator type arguments. |
| 550 // A null object is always assignable and is returned as result. | 548 // A null object is always assignable and is returned as result. |
| 551 const Immediate raw_null = | 549 const Immediate raw_null = |
| 552 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 550 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 553 Label is_assignable, runtime_call; | 551 Label is_assignable, runtime_call; |
| 554 __ cmpq(RAX, raw_null); | 552 __ cmpq(RAX, raw_null); |
| 555 __ j(EQUAL, &is_assignable); | 553 __ j(EQUAL, &is_assignable); |
| 556 | 554 |
| 557 // Generate throw new TypeError() if the type is malformed. | 555 // Generate throw new TypeError() if the type is malformed. |
| 558 if (dst_type.IsMalformed()) { | 556 if (dst_type.IsMalformed()) { |
| 559 const Error& error = Error::Handle(dst_type.malformed_error()); | 557 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 560 const String& error_message = String::ZoneHandle( | 558 const String& error_message = String::ZoneHandle( |
| 561 Symbols::New(error.ToErrorCString())); | 559 Symbols::New(error.ToErrorCString())); |
| 562 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 560 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 563 __ pushq(RAX); // Push the source object. | 561 __ pushq(RAX); // Push the source object. |
| 564 __ PushObject(dst_name); // Push the name of the destination. | 562 __ PushObject(dst_name); // Push the name of the destination. |
| 565 __ PushObject(error_message); | 563 __ PushObject(error_message); |
| 566 GenerateCallRuntime(deopt_id, | 564 GenerateCallRuntime(token_pos, |
| 567 token_pos, | |
| 568 kMalformedTypeErrorRuntimeEntry, | 565 kMalformedTypeErrorRuntimeEntry, |
| 569 locs); | 566 locs); |
| 570 // We should never return here. | 567 // We should never return here. |
| 571 __ int3(); | 568 __ int3(); |
| 572 | 569 |
| 573 __ Bind(&is_assignable); // For a null object. | 570 __ Bind(&is_assignable); // For a null object. |
| 574 __ popq(RDX); // Remove pushed instantiator type arguments. | 571 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 575 __ popq(RCX); // Remove pushed instantiator. | 572 __ popq(RCX); // Remove pushed instantiator. |
| 576 return; | 573 return; |
| 577 } | 574 } |
| 578 | 575 |
| 579 // Generate inline type check, linking to runtime call if not assignable. | 576 // Generate inline type check, linking to runtime call if not assignable. |
| 580 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 577 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 581 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 578 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 582 &is_assignable, &runtime_call); | 579 &is_assignable, &runtime_call); |
| 583 | 580 |
| 584 __ Bind(&runtime_call); | 581 __ Bind(&runtime_call); |
| 585 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 582 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 586 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 583 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 587 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 584 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 588 __ pushq(RAX); // Push the source object. | 585 __ pushq(RAX); // Push the source object. |
| 589 __ PushObject(dst_type); // Push the type of the destination. | 586 __ PushObject(dst_type); // Push the type of the destination. |
| 590 __ pushq(RCX); // Instantiator. | 587 __ pushq(RCX); // Instantiator. |
| 591 __ pushq(RDX); // Instantiator type arguments. | 588 __ pushq(RDX); // Instantiator type arguments. |
| 592 __ PushObject(dst_name); // Push the name of the destination. | 589 __ PushObject(dst_name); // Push the name of the destination. |
| 593 __ LoadObject(RAX, test_cache); | 590 __ LoadObject(RAX, test_cache); |
| 594 __ pushq(RAX); | 591 __ pushq(RAX); |
| 595 GenerateCallRuntime(deopt_id, | 592 GenerateCallRuntime(token_pos, |
| 596 token_pos, | |
| 597 kTypeCheckRuntimeEntry, | 593 kTypeCheckRuntimeEntry, |
| 598 locs); | 594 locs); |
| 599 // Pop the parameters supplied to the runtime entry. The result of the | 595 // Pop the parameters supplied to the runtime entry. The result of the |
| 600 // type check runtime call is the checked value. | 596 // type check runtime call is the checked value. |
| 601 __ Drop(6); | 597 __ Drop(6); |
| 602 __ popq(RAX); | 598 __ popq(RAX); |
| 603 | 599 |
| 604 __ Bind(&is_assignable); | 600 __ Bind(&is_assignable); |
| 605 __ popq(RDX); // Remove pushed instantiator type arguments. | 601 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 606 __ popq(RCX); // Remove pushed instantiator. | 602 __ popq(RCX); // Remove pushed instantiator. |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 942 #endif | 938 #endif |
| 943 if (check_arguments) { | 939 if (check_arguments) { |
| 944 __ Comment("Check argument count"); | 940 __ Comment("Check argument count"); |
| 945 // Check that num_fixed <= argc <= num_params. | 941 // Check that num_fixed <= argc <= num_params. |
| 946 Label argc_in_range; | 942 Label argc_in_range; |
| 947 // Total number of args is the first Smi in args descriptor array (R10). | 943 // Total number of args is the first Smi in args descriptor array (R10). |
| 948 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 944 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 949 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); | 945 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); |
| 950 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 946 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 951 if (function.IsClosureFunction()) { | 947 if (function.IsClosureFunction()) { |
| 952 GenerateCallRuntime(Isolate::kNoDeoptId, | 948 GenerateCallRuntime(function.token_pos(), |
| 953 function.token_pos(), | |
| 954 kClosureArgumentMismatchRuntimeEntry, | 949 kClosureArgumentMismatchRuntimeEntry, |
| 955 prologue_locs); | 950 prologue_locs); |
| 956 } else { | 951 } else { |
| 957 __ Stop("Wrong number of arguments"); | 952 __ Stop("Wrong number of arguments"); |
| 958 } | 953 } |
| 959 __ Bind(&argc_in_range); | 954 __ Bind(&argc_in_range); |
| 960 } | 955 } |
| 961 // The arguments descriptor is never saved in the absence of optional | 956 // The arguments descriptor is never saved in the absence of optional |
| 962 // parameters, since any argument definition test would always yield true. | 957 // parameters, since any argument definition test would always yield true. |
| 963 ASSERT(saved_args_desc_var == NULL); | 958 ASSERT(saved_args_desc_var == NULL); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1043 } else { | 1038 } else { |
| 1044 // Add deoptimization continuation point after the call and before the | 1039 // Add deoptimization continuation point after the call and before the |
| 1045 // arguments are removed. | 1040 // arguments are removed. |
| 1046 AddCurrentDescriptor(PcDescriptors::kDeoptAfter, | 1041 AddCurrentDescriptor(PcDescriptors::kDeoptAfter, |
| 1047 deopt_id, | 1042 deopt_id, |
| 1048 token_pos); | 1043 token_pos); |
| 1049 } | 1044 } |
| 1050 } | 1045 } |
| 1051 | 1046 |
| 1052 | 1047 |
| 1053 void FlowGraphCompiler::GenerateCallRuntime(intptr_t deopt_id, | 1048 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, |
| 1054 intptr_t token_pos, | |
| 1055 const RuntimeEntry& entry, | 1049 const RuntimeEntry& entry, |
| 1056 LocationSummary* locs) { | 1050 LocationSummary* locs) { |
| 1057 ASSERT(!IsLeaf()); | 1051 ASSERT(!IsLeaf()); |
| 1058 __ CallRuntime(entry); | 1052 __ CallRuntime(entry); |
| 1059 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | 1053 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| 1060 RecordSafepoint(locs); | 1054 RecordSafepoint(locs); |
| 1061 } | 1055 } |
| 1062 | 1056 |
| 1063 | 1057 |
| 1064 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1058 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1065 const ICData& ic_data, | 1059 const ICData& ic_data, |
| 1066 const Array& arguments_descriptor, | 1060 const Array& arguments_descriptor, |
| 1067 intptr_t argument_count, | 1061 intptr_t argument_count, |
| 1068 intptr_t deopt_id, | 1062 intptr_t deopt_id, |
| 1069 intptr_t token_pos, | 1063 intptr_t token_pos, |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1309 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1303 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 1310 __ Exchange(mem1, mem2); | 1304 __ Exchange(mem1, mem2); |
| 1311 } | 1305 } |
| 1312 | 1306 |
| 1313 | 1307 |
| 1314 #undef __ | 1308 #undef __ |
| 1315 | 1309 |
| 1316 } // namespace dart | 1310 } // namespace dart |
| 1317 | 1311 |
| 1318 #endif // defined TARGET_ARCH_X64 | 1312 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |