| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 | 156 |
| 157 | 157 |
| 158 #define __ assembler()-> | 158 #define __ assembler()-> |
| 159 | 159 |
| 160 | 160 |
| 161 // Fall through if bool_register contains null. | 161 // Fall through if bool_register contains null. |
| 162 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 162 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 163 Label* is_true, | 163 Label* is_true, |
| 164 Label* is_false) { | 164 Label* is_false) { |
| 165 Label fall_through; | 165 Label fall_through; |
| 166 __ CompareObject(bool_register, Object::null_object()); | 166 __ CompareObject(bool_register, Object::null_object(), PP); |
| 167 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 167 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 168 __ CompareObject(bool_register, Bool::True()); | 168 __ CompareObject(bool_register, Bool::True(), PP); |
| 169 __ j(EQUAL, is_true); | 169 __ j(EQUAL, is_true); |
| 170 __ jmp(is_false); | 170 __ jmp(is_false); |
| 171 __ Bind(&fall_through); | 171 __ Bind(&fall_through); |
| 172 } | 172 } |
| 173 | 173 |
| 174 | 174 |
| 175 // Clobbers RCX. | 175 // Clobbers RCX. |
| 176 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 176 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 177 TypeTestStubKind test_kind, | 177 TypeTestStubKind test_kind, |
| 178 Register instance_reg, | 178 Register instance_reg, |
| 179 Register type_arguments_reg, | 179 Register type_arguments_reg, |
| 180 Register temp_reg, | 180 Register temp_reg, |
| 181 Label* is_instance_lbl, | 181 Label* is_instance_lbl, |
| 182 Label* is_not_instance_lbl) { | 182 Label* is_not_instance_lbl) { |
| 183 const SubtypeTestCache& type_test_cache = | 183 const SubtypeTestCache& type_test_cache = |
| 184 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 184 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 185 __ LoadObject(temp_reg, type_test_cache, PP); | 185 __ LoadObject(temp_reg, type_test_cache, PP); |
| 186 __ pushq(temp_reg); // Subtype test cache. | 186 __ pushq(temp_reg); // Subtype test cache. |
| 187 __ pushq(instance_reg); // Instance. | 187 __ pushq(instance_reg); // Instance. |
| 188 if (test_kind == kTestTypeOneArg) { | 188 if (test_kind == kTestTypeOneArg) { |
| 189 ASSERT(type_arguments_reg == kNoRegister); | 189 ASSERT(type_arguments_reg == kNoRegister); |
| 190 __ PushObject(Object::null_object()); | 190 __ PushObject(Object::null_object(), PP); |
| 191 __ Call(&StubCode::Subtype1TestCacheLabel(), PP); | 191 __ Call(&StubCode::Subtype1TestCacheLabel(), PP); |
| 192 } else if (test_kind == kTestTypeTwoArgs) { | 192 } else if (test_kind == kTestTypeTwoArgs) { |
| 193 ASSERT(type_arguments_reg == kNoRegister); | 193 ASSERT(type_arguments_reg == kNoRegister); |
| 194 __ PushObject(Object::null_object()); | 194 __ PushObject(Object::null_object(), PP); |
| 195 __ Call(&StubCode::Subtype2TestCacheLabel(), PP); | 195 __ Call(&StubCode::Subtype2TestCacheLabel(), PP); |
| 196 } else if (test_kind == kTestTypeThreeArgs) { | 196 } else if (test_kind == kTestTypeThreeArgs) { |
| 197 __ pushq(type_arguments_reg); | 197 __ pushq(type_arguments_reg); |
| 198 __ Call(&StubCode::Subtype3TestCacheLabel(), PP); | 198 __ Call(&StubCode::Subtype3TestCacheLabel(), PP); |
| 199 } else { | 199 } else { |
| 200 UNREACHABLE(); | 200 UNREACHABLE(); |
| 201 } | 201 } |
| 202 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. | 202 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
| 203 ASSERT(instance_reg != RCX); | 203 ASSERT(instance_reg != RCX); |
| 204 ASSERT(temp_reg != RCX); | 204 ASSERT(temp_reg != RCX); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 if (type.IsBoolType()) { | 335 if (type.IsBoolType()) { |
| 336 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 336 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
| 337 __ j(EQUAL, is_instance_lbl); | 337 __ j(EQUAL, is_instance_lbl); |
| 338 __ jmp(is_not_instance_lbl); | 338 __ jmp(is_not_instance_lbl); |
| 339 return false; | 339 return false; |
| 340 } | 340 } |
| 341 if (type.IsFunctionType()) { | 341 if (type.IsFunctionType()) { |
| 342 // Check if instance is a closure. | 342 // Check if instance is a closure. |
| 343 __ LoadClassById(R13, kClassIdReg); | 343 __ LoadClassById(R13, kClassIdReg); |
| 344 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); | 344 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); |
| 345 __ CompareObject(R13, Object::null_object()); | 345 __ CompareObject(R13, Object::null_object(), PP); |
| 346 __ j(NOT_EQUAL, is_instance_lbl); | 346 __ j(NOT_EQUAL, is_instance_lbl); |
| 347 } | 347 } |
| 348 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 348 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 349 // Note that instance is not Smi (checked above). | 349 // Note that instance is not Smi (checked above). |
| 350 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 350 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 351 GenerateNumberTypeCheck( | 351 GenerateNumberTypeCheck( |
| 352 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 352 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 353 return false; | 353 return false; |
| 354 } | 354 } |
| 355 if (type.IsStringType()) { | 355 if (type.IsStringType()) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 373 const Class& type_class, | 373 const Class& type_class, |
| 374 Label* is_instance_lbl, | 374 Label* is_instance_lbl, |
| 375 Label* is_not_instance_lbl) { | 375 Label* is_not_instance_lbl) { |
| 376 __ Comment("Subtype1TestCacheLookup"); | 376 __ Comment("Subtype1TestCacheLookup"); |
| 377 const Register kInstanceReg = RAX; | 377 const Register kInstanceReg = RAX; |
| 378 __ LoadClass(R10, kInstanceReg); | 378 __ LoadClass(R10, kInstanceReg); |
| 379 // R10: instance class. | 379 // R10: instance class. |
| 380 // Check immediate superclass equality. | 380 // Check immediate superclass equality. |
| 381 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); | 381 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); |
| 382 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); | 382 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); |
| 383 __ CompareObject(R13, type_class); | 383 __ CompareObject(R13, type_class, PP); |
| 384 __ j(EQUAL, is_instance_lbl); | 384 __ j(EQUAL, is_instance_lbl); |
| 385 | 385 |
| 386 const Register kTypeArgumentsReg = kNoRegister; | 386 const Register kTypeArgumentsReg = kNoRegister; |
| 387 const Register kTempReg = R10; | 387 const Register kTempReg = R10; |
| 388 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 388 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
| 389 kInstanceReg, | 389 kInstanceReg, |
| 390 kTypeArgumentsReg, | 390 kTypeArgumentsReg, |
| 391 kTempReg, | 391 kTempReg, |
| 392 is_instance_lbl, | 392 is_instance_lbl, |
| 393 is_not_instance_lbl); | 393 is_not_instance_lbl); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 404 Label* is_not_instance_lbl) { | 404 Label* is_not_instance_lbl) { |
| 405 __ Comment("UninstantiatedTypeTest"); | 405 __ Comment("UninstantiatedTypeTest"); |
| 406 ASSERT(!type.IsInstantiated()); | 406 ASSERT(!type.IsInstantiated()); |
| 407 // Skip check if destination is a dynamic type. | 407 // Skip check if destination is a dynamic type. |
| 408 if (type.IsTypeParameter()) { | 408 if (type.IsTypeParameter()) { |
| 409 const TypeParameter& type_param = TypeParameter::Cast(type); | 409 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 410 // Load instantiator (or null) and instantiator type arguments on stack. | 410 // Load instantiator (or null) and instantiator type arguments on stack. |
| 411 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 411 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 412 // RDX: instantiator type arguments. | 412 // RDX: instantiator type arguments. |
| 413 // Check if type argument is dynamic. | 413 // Check if type argument is dynamic. |
| 414 __ CompareObject(RDX, Object::null_object()); | 414 __ CompareObject(RDX, Object::null_object(), PP); |
| 415 __ j(EQUAL, is_instance_lbl); | 415 __ j(EQUAL, is_instance_lbl); |
| 416 // Can handle only type arguments that are instances of TypeArguments. | 416 // Can handle only type arguments that are instances of TypeArguments. |
| 417 // (runtime checks canonicalize type arguments). | 417 // (runtime checks canonicalize type arguments). |
| 418 Label fall_through; | 418 Label fall_through; |
| 419 __ CompareClassId(RDX, kTypeArgumentsCid); | 419 __ CompareClassId(RDX, kTypeArgumentsCid); |
| 420 __ j(NOT_EQUAL, &fall_through); | 420 __ j(NOT_EQUAL, &fall_through); |
| 421 __ movq(RDI, | 421 __ movq(RDI, |
| 422 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 422 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); |
| 423 // RDI: Concrete type of type. | 423 // RDI: Concrete type of type. |
| 424 // Check if type argument is dynamic. | 424 // Check if type argument is dynamic. |
| 425 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); | 425 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()), PP); |
| 426 __ j(EQUAL, is_instance_lbl); | 426 __ j(EQUAL, is_instance_lbl); |
| 427 __ CompareObject(RDI, Object::null_object()); | 427 __ CompareObject(RDI, Object::null_object(), PP); |
| 428 __ j(EQUAL, is_instance_lbl); | 428 __ j(EQUAL, is_instance_lbl); |
| 429 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 429 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
| 430 __ CompareObject(RDI, object_type); | 430 __ CompareObject(RDI, object_type, PP); |
| 431 __ j(EQUAL, is_instance_lbl); | 431 __ j(EQUAL, is_instance_lbl); |
| 432 | 432 |
| 433 // For Smi check quickly against int and num interfaces. | 433 // For Smi check quickly against int and num interfaces. |
| 434 Label not_smi; | 434 Label not_smi; |
| 435 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 435 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 436 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 436 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 437 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType())); | 437 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType()), PP); |
| 438 __ j(EQUAL, is_instance_lbl); | 438 __ j(EQUAL, is_instance_lbl); |
| 439 __ CompareObject(RDI, Type::ZoneHandle(Type::Number())); | 439 __ CompareObject(RDI, Type::ZoneHandle(Type::Number()), PP); |
| 440 __ j(EQUAL, is_instance_lbl); | 440 __ j(EQUAL, is_instance_lbl); |
| 441 // Smi must be handled in runtime. | 441 // Smi must be handled in runtime. |
| 442 __ jmp(&fall_through); | 442 __ jmp(&fall_through); |
| 443 | 443 |
| 444 __ Bind(¬_smi); | 444 __ Bind(¬_smi); |
| 445 // RDX: instantiator type arguments. | 445 // RDX: instantiator type arguments. |
| 446 // RAX: instance. | 446 // RAX: instance. |
| 447 const Register kInstanceReg = RAX; | 447 const Register kInstanceReg = RAX; |
| 448 const Register kTypeArgumentsReg = RDX; | 448 const Register kTypeArgumentsReg = RDX; |
| 449 const Register kTempReg = R10; | 449 const Register kTempReg = R10; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 // If type is instantiated and non-parameterized, we can inline code | 570 // If type is instantiated and non-parameterized, we can inline code |
| 571 // checking whether the tested instance is a Smi. | 571 // checking whether the tested instance is a Smi. |
| 572 if (type.IsInstantiated()) { | 572 if (type.IsInstantiated()) { |
| 573 // A null object is only an instance of Object and dynamic, which has | 573 // A null object is only an instance of Object and dynamic, which has |
| 574 // already been checked above (if the type is instantiated). So we can | 574 // already been checked above (if the type is instantiated). So we can |
| 575 // return false here if the instance is null (and if the type is | 575 // return false here if the instance is null (and if the type is |
| 576 // instantiated). | 576 // instantiated). |
| 577 // We can only inline this null check if the type is instantiated at compile | 577 // We can only inline this null check if the type is instantiated at compile |
| 578 // time, since an uninstantiated type at compile time could be Object or | 578 // time, since an uninstantiated type at compile time could be Object or |
| 579 // dynamic at run time. | 579 // dynamic at run time. |
| 580 __ CompareObject(RAX, Object::null_object()); | 580 __ CompareObject(RAX, Object::null_object(), PP); |
| 581 __ j(EQUAL, &is_not_instance); | 581 __ j(EQUAL, &is_not_instance); |
| 582 } | 582 } |
| 583 | 583 |
| 584 // Generate inline instanceof test. | 584 // Generate inline instanceof test. |
| 585 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 585 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 586 test_cache = GenerateInlineInstanceof(token_pos, type, | 586 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 587 &is_instance, &is_not_instance); | 587 &is_instance, &is_not_instance); |
| 588 | 588 |
| 589 // test_cache is null if there is no fall-through. | 589 // test_cache is null if there is no fall-through. |
| 590 Label done; | 590 Label done; |
| 591 if (!test_cache.IsNull()) { | 591 if (!test_cache.IsNull()) { |
| 592 // Generate runtime call. | 592 // Generate runtime call. |
| 593 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 593 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 594 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 594 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 595 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 595 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. |
| 596 __ pushq(RAX); // Push the instance. | 596 __ pushq(RAX); // Push the instance. |
| 597 __ PushObject(type); // Push the type. | 597 __ PushObject(type, PP); // Push the type. |
| 598 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. | 598 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
| 599 __ pushq(RDX); // Instantiator type arguments. | 599 __ pushq(RDX); // Instantiator type arguments. |
| 600 __ LoadObject(RAX, test_cache, PP); | 600 __ LoadObject(RAX, test_cache, PP); |
| 601 __ pushq(RAX); | 601 __ pushq(RAX); |
| 602 GenerateCallRuntime(token_pos, | 602 GenerateCallRuntime(token_pos, |
| 603 deopt_id, | 603 deopt_id, |
| 604 kInstanceofRuntimeEntry, | 604 kInstanceofRuntimeEntry, |
| 605 5, | 605 5, |
| 606 locs); | 606 locs); |
| 607 // Pop the parameters supplied to the runtime entry. The result of the | 607 // Pop the parameters supplied to the runtime entry. The result of the |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 ASSERT(token_pos >= 0); | 650 ASSERT(token_pos >= 0); |
| 651 ASSERT(!dst_type.IsNull()); | 651 ASSERT(!dst_type.IsNull()); |
| 652 ASSERT(dst_type.IsFinalized()); | 652 ASSERT(dst_type.IsFinalized()); |
| 653 // Assignable check is skipped in FlowGraphBuilder, not here. | 653 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 654 ASSERT(dst_type.IsMalformed() || dst_type.IsMalbounded() || | 654 ASSERT(dst_type.IsMalformed() || dst_type.IsMalbounded() || |
| 655 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 655 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 656 __ pushq(RCX); // Store instantiator. | 656 __ pushq(RCX); // Store instantiator. |
| 657 __ pushq(RDX); // Store instantiator type arguments. | 657 __ pushq(RDX); // Store instantiator type arguments. |
| 658 // A null object is always assignable and is returned as result. | 658 // A null object is always assignable and is returned as result. |
| 659 Label is_assignable, runtime_call; | 659 Label is_assignable, runtime_call; |
| 660 __ CompareObject(RAX, Object::null_object()); | 660 __ CompareObject(RAX, Object::null_object(), PP); |
| 661 __ j(EQUAL, &is_assignable); | 661 __ j(EQUAL, &is_assignable); |
| 662 | 662 |
| 663 if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) { | 663 if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) { |
| 664 // If type checks are not eliminated during the graph building then | 664 // If type checks are not eliminated during the graph building then |
| 665 // a transition sentinel can be seen here. | 665 // a transition sentinel can be seen here. |
| 666 __ CompareObject(RAX, Object::transition_sentinel()); | 666 __ CompareObject(RAX, Object::transition_sentinel(), PP); |
| 667 __ j(EQUAL, &is_assignable); | 667 __ j(EQUAL, &is_assignable); |
| 668 } | 668 } |
| 669 | 669 |
| 670 // Generate throw new TypeError() if the type is malformed or malbounded. | 670 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 671 if (dst_type.IsMalformed() || dst_type.IsMalbounded()) { | 671 if (dst_type.IsMalformed() || dst_type.IsMalbounded()) { |
| 672 Error& error = Error::Handle(); | 672 Error& error = Error::Handle(); |
| 673 if (dst_type.IsMalformed()) { | 673 if (dst_type.IsMalformed()) { |
| 674 error = dst_type.malformed_error(); | 674 error = dst_type.malformed_error(); |
| 675 } else { | 675 } else { |
| 676 const bool is_malbounded = dst_type.IsMalboundedWithError(&error); | 676 const bool is_malbounded = dst_type.IsMalboundedWithError(&error); |
| 677 ASSERT(is_malbounded); | 677 ASSERT(is_malbounded); |
| 678 } | 678 } |
| 679 const String& error_message = String::ZoneHandle( | 679 const String& error_message = String::ZoneHandle( |
| 680 Symbols::New(error.ToErrorCString())); | 680 Symbols::New(error.ToErrorCString())); |
| 681 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 681 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. |
| 682 __ pushq(RAX); // Push the source object. | 682 __ pushq(RAX); // Push the source object. |
| 683 __ PushObject(dst_name); // Push the name of the destination. | 683 __ PushObject(dst_name, PP); // Push the name of the destination. |
| 684 __ PushObject(error_message); | 684 __ PushObject(error_message, PP); |
| 685 GenerateCallRuntime(token_pos, | 685 GenerateCallRuntime(token_pos, |
| 686 deopt_id, | 686 deopt_id, |
| 687 kMalformedTypeErrorRuntimeEntry, | 687 kMalformedTypeErrorRuntimeEntry, |
| 688 3, | 688 3, |
| 689 locs); | 689 locs); |
| 690 // We should never return here. | 690 // We should never return here. |
| 691 __ int3(); | 691 __ int3(); |
| 692 | 692 |
| 693 __ Bind(&is_assignable); // For a null object. | 693 __ Bind(&is_assignable); // For a null object. |
| 694 __ popq(RDX); // Remove pushed instantiator type arguments. | 694 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 695 __ popq(RCX); // Remove pushed instantiator. | 695 __ popq(RCX); // Remove pushed instantiator. |
| 696 return; | 696 return; |
| 697 } | 697 } |
| 698 | 698 |
| 699 // Generate inline type check, linking to runtime call if not assignable. | 699 // Generate inline type check, linking to runtime call if not assignable. |
| 700 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 700 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 701 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 701 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 702 &is_assignable, &runtime_call); | 702 &is_assignable, &runtime_call); |
| 703 | 703 |
| 704 __ Bind(&runtime_call); | 704 __ Bind(&runtime_call); |
| 705 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 705 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 706 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 706 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 707 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 707 __ PushObject(Object::ZoneHandle(), PP); // Make room for the result. |
| 708 __ pushq(RAX); // Push the source object. | 708 __ pushq(RAX); // Push the source object. |
| 709 __ PushObject(dst_type); // Push the type of the destination. | 709 __ PushObject(dst_type, PP); // Push the type of the destination. |
| 710 __ pushq(RCX); // Instantiator. | 710 __ pushq(RCX); // Instantiator. |
| 711 __ pushq(RDX); // Instantiator type arguments. | 711 __ pushq(RDX); // Instantiator type arguments. |
| 712 __ PushObject(dst_name); // Push the name of the destination. | 712 __ PushObject(dst_name, PP); // Push the name of the destination. |
| 713 __ LoadObject(RAX, test_cache, PP); | 713 __ LoadObject(RAX, test_cache, PP); |
| 714 __ pushq(RAX); | 714 __ pushq(RAX); |
| 715 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 715 GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| 716 // Pop the parameters supplied to the runtime entry. The result of the | 716 // Pop the parameters supplied to the runtime entry. The result of the |
| 717 // type check runtime call is the checked value. | 717 // type check runtime call is the checked value. |
| 718 __ Drop(6); | 718 __ Drop(6); |
| 719 __ popq(RAX); | 719 __ popq(RAX); |
| 720 | 720 |
| 721 __ Bind(&is_assignable); | 721 __ Bind(&is_assignable); |
| 722 __ popq(RDX); // Remove pushed instantiator type arguments. | 722 __ popq(RDX); // Remove pushed instantiator type arguments. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 | 837 |
| 838 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 838 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
| 839 // where num_pos_args is the number of positional arguments passed in. | 839 // where num_pos_args is the number of positional arguments passed in. |
| 840 const int min_num_pos_args = num_fixed_params; | 840 const int min_num_pos_args = num_fixed_params; |
| 841 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 841 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 842 | 842 |
| 843 __ movq(RCX, | 843 __ movq(RCX, |
| 844 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 844 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 845 // Check that min_num_pos_args <= num_pos_args. | 845 // Check that min_num_pos_args <= num_pos_args. |
| 846 Label wrong_num_arguments; | 846 Label wrong_num_arguments; |
| 847 __ cmpq(RCX, Immediate(Smi::RawValue(min_num_pos_args))); | 847 __ CompareImmediate(RCX, Immediate(Smi::RawValue(min_num_pos_args)), PP); |
| 848 __ j(LESS, &wrong_num_arguments); | 848 __ j(LESS, &wrong_num_arguments); |
| 849 // Check that num_pos_args <= max_num_pos_args. | 849 // Check that num_pos_args <= max_num_pos_args. |
| 850 __ cmpq(RCX, Immediate(Smi::RawValue(max_num_pos_args))); | 850 __ CompareImmediate(RCX, Immediate(Smi::RawValue(max_num_pos_args)), PP); |
| 851 __ j(GREATER, &wrong_num_arguments); | 851 __ j(GREATER, &wrong_num_arguments); |
| 852 | 852 |
| 853 // Copy positional arguments. | 853 // Copy positional arguments. |
| 854 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 854 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
| 855 // to fp[kFirstLocalSlotFromFp - i]. | 855 // to fp[kFirstLocalSlotFromFp - i]. |
| 856 | 856 |
| 857 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 857 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 858 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. | 858 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
| 859 // Let RBX point to the last passed positional argument, i.e. to | 859 // Let RBX point to the last passed positional argument, i.e. to |
| 860 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 860 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 // Let RDI point to the entry of the first named argument. | 922 // Let RDI point to the entry of the first named argument. |
| 923 __ leaq(RDI, | 923 __ leaq(RDI, |
| 924 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); | 924 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); |
| 925 for (int i = 0; i < num_opt_named_params; i++) { | 925 for (int i = 0; i < num_opt_named_params; i++) { |
| 926 Label load_default_value, assign_optional_parameter; | 926 Label load_default_value, assign_optional_parameter; |
| 927 const int param_pos = opt_param_position[i]; | 927 const int param_pos = opt_param_position[i]; |
| 928 // Check if this named parameter was passed in. | 928 // Check if this named parameter was passed in. |
| 929 // Load RAX with the name of the argument. | 929 // Load RAX with the name of the argument. |
| 930 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); | 930 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); |
| 931 ASSERT(opt_param[i]->name().IsSymbol()); | 931 ASSERT(opt_param[i]->name().IsSymbol()); |
| 932 __ CompareObject(RAX, opt_param[i]->name()); | 932 __ CompareObject(RAX, opt_param[i]->name(), PP); |
| 933 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | 933 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
| 934 // Load RAX with passed-in argument at provided arg_pos, i.e. at | 934 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
| 935 // fp[kParamEndSlotFromFp + num_args - arg_pos]. | 935 // fp[kParamEndSlotFromFp + num_args - arg_pos]. |
| 936 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); | 936 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); |
| 937 // RAX is arg_pos as Smi. | 937 // RAX is arg_pos as Smi. |
| 938 // Point to next named entry. | 938 // Point to next named entry. |
| 939 __ addq(RDI, Immediate(ArgumentsDescriptor::named_entry_size())); | 939 __ AddImmediate( |
| 940 RDI, Immediate(ArgumentsDescriptor::named_entry_size()), PP); |
| 940 __ negq(RAX); | 941 __ negq(RAX); |
| 941 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. | 942 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
| 942 __ movq(RAX, argument_addr); | 943 __ movq(RAX, argument_addr); |
| 943 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 944 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
| 944 __ Bind(&load_default_value); | 945 __ Bind(&load_default_value); |
| 945 // Load RAX with default argument. | 946 // Load RAX with default argument. |
| 946 const Object& value = Object::ZoneHandle( | 947 const Object& value = Object::ZoneHandle( |
| 947 parsed_function().default_parameter_values().At( | 948 parsed_function().default_parameter_values().At( |
| 948 param_pos - num_fixed_params)); | 949 param_pos - num_fixed_params)); |
| 949 __ LoadObject(RAX, value, PP); | 950 __ LoadObject(RAX, value, PP); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 969 ASSERT(num_opt_pos_params > 0); | 970 ASSERT(num_opt_pos_params > 0); |
| 970 __ movq(RCX, | 971 __ movq(RCX, |
| 971 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 972 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
| 972 __ SmiUntag(RCX); | 973 __ SmiUntag(RCX); |
| 973 for (int i = 0; i < num_opt_pos_params; i++) { | 974 for (int i = 0; i < num_opt_pos_params; i++) { |
| 974 Label next_parameter; | 975 Label next_parameter; |
| 975 // Handle this optional positional parameter only if k or fewer positional | 976 // Handle this optional positional parameter only if k or fewer positional |
| 976 // arguments have been passed, where k is param_pos, the position of this | 977 // arguments have been passed, where k is param_pos, the position of this |
| 977 // optional parameter in the formal parameter list. | 978 // optional parameter in the formal parameter list. |
| 978 const int param_pos = num_fixed_params + i; | 979 const int param_pos = num_fixed_params + i; |
| 979 __ cmpq(RCX, Immediate(param_pos)); | 980 __ CompareImmediate(RCX, Immediate(param_pos), PP); |
| 980 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 981 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
| 981 // Load RAX with default argument. | 982 // Load RAX with default argument. |
| 982 const Object& value = Object::ZoneHandle( | 983 const Object& value = Object::ZoneHandle( |
| 983 parsed_function().default_parameter_values().At(i)); | 984 parsed_function().default_parameter_values().At(i)); |
| 984 __ LoadObject(RAX, value, PP); | 985 __ LoadObject(RAX, value, PP); |
| 985 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. | 986 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| 986 // We do not use the final allocation index of the variable here, i.e. | 987 // We do not use the final allocation index of the variable here, i.e. |
| 987 // scope->VariableAt(i)->index(), because captured variables still need | 988 // scope->VariableAt(i)->index(), because captured variables still need |
| 988 // to be copied to the context that is not yet allocated. | 989 // to be copied to the context that is not yet allocated. |
| 989 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 990 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1094 // Load function object using the callee's pool pointer. | 1095 // Load function object using the callee's pool pointer. |
| 1095 __ LoadObject(function_reg, function, new_pp); | 1096 __ LoadObject(function_reg, function, new_pp); |
| 1096 | 1097 |
| 1097 // Patch point is after the eventually inlined function object. | 1098 // Patch point is after the eventually inlined function object. |
| 1098 AddCurrentDescriptor(PcDescriptors::kEntryPatch, | 1099 AddCurrentDescriptor(PcDescriptors::kEntryPatch, |
| 1099 Isolate::kNoDeoptId, | 1100 Isolate::kNoDeoptId, |
| 1100 0); // No token position. | 1101 0); // No token position. |
| 1101 if (is_optimizing()) { | 1102 if (is_optimizing()) { |
| 1102 // Reoptimization of an optimized function is triggered by counting in | 1103 // Reoptimization of an optimized function is triggered by counting in |
| 1103 // IC stubs, but not at the entry of the function. | 1104 // IC stubs, but not at the entry of the function. |
| 1104 __ cmpq(FieldAddress(function_reg, Function::usage_counter_offset()), | 1105 __ CompareImmediate( |
| 1105 Immediate(FLAG_reoptimization_counter_threshold)); | 1106 FieldAddress(function_reg, Function::usage_counter_offset()), |
| 1107 Immediate(FLAG_reoptimization_counter_threshold), |
| 1108 new_pp); |
| 1106 } else { | 1109 } else { |
| 1107 __ incq(FieldAddress(function_reg, Function::usage_counter_offset())); | 1110 __ incq(FieldAddress(function_reg, Function::usage_counter_offset())); |
| 1108 __ cmpq(FieldAddress(function_reg, Function::usage_counter_offset()), | 1111 __ CompareImmediate( |
| 1109 Immediate(FLAG_optimization_counter_threshold)); | 1112 FieldAddress(function_reg, Function::usage_counter_offset()), |
| 1113 Immediate(FLAG_optimization_counter_threshold), |
| 1114 new_pp); |
| 1110 } | 1115 } |
| 1111 ASSERT(function_reg == RDI); | 1116 ASSERT(function_reg == RDI); |
| 1112 __ J(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel(), R13); | 1117 __ J(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel(), R13); |
| 1113 } else if (!flow_graph().IsCompiledForOsr()) { | 1118 } else if (!flow_graph().IsCompiledForOsr()) { |
| 1114 // We have to load the PP here too because a load of an external label | 1119 // We have to load the PP here too because a load of an external label |
| 1115 // may be patched at the AddCurrentDescriptor below. | 1120 // may be patched at the AddCurrentDescriptor below. |
| 1116 new_pp = R13; | 1121 new_pp = R13; |
| 1117 new_pc = R12; | 1122 new_pc = R12; |
| 1118 | 1123 |
| 1119 Label next; | 1124 Label next; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1174 const bool check_arguments = !flow_graph().IsCompiledForOsr(); | 1179 const bool check_arguments = !flow_graph().IsCompiledForOsr(); |
| 1175 #else | 1180 #else |
| 1176 const bool check_arguments = | 1181 const bool check_arguments = |
| 1177 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1182 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
| 1178 #endif | 1183 #endif |
| 1179 if (check_arguments) { | 1184 if (check_arguments) { |
| 1180 __ Comment("Check argument count"); | 1185 __ Comment("Check argument count"); |
| 1181 // Check that exactly num_fixed arguments are passed in. | 1186 // Check that exactly num_fixed arguments are passed in. |
| 1182 Label correct_num_arguments, wrong_num_arguments; | 1187 Label correct_num_arguments, wrong_num_arguments; |
| 1183 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1188 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1184 __ cmpq(RAX, Immediate(Smi::RawValue(num_fixed_params))); | 1189 __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params)), PP); |
| 1185 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); | 1190 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); |
| 1186 __ cmpq(RAX, | 1191 __ cmpq(RAX, |
| 1187 FieldAddress(R10, | 1192 FieldAddress(R10, |
| 1188 ArgumentsDescriptor::positional_count_offset())); | 1193 ArgumentsDescriptor::positional_count_offset())); |
| 1189 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); | 1194 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); |
| 1190 | 1195 |
| 1191 __ Bind(&wrong_num_arguments); | 1196 __ Bind(&wrong_num_arguments); |
| 1192 if (function.IsClosureFunction()) { | 1197 if (function.IsClosureFunction()) { |
| 1193 // Invoke noSuchMethod function passing the original function name. | 1198 // Invoke noSuchMethod function passing the original function name. |
| 1194 // For closure functions, use "call" as the original name. | 1199 // For closure functions, use "call" as the original name. |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1403 const String& name = String::Handle(ic_data.target_name()); | 1408 const String& name = String::Handle(ic_data.target_name()); |
| 1404 const Array& arguments_descriptor = | 1409 const Array& arguments_descriptor = |
| 1405 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1410 Array::ZoneHandle(ic_data.arguments_descriptor()); |
| 1406 ASSERT(!arguments_descriptor.IsNull()); | 1411 ASSERT(!arguments_descriptor.IsNull()); |
| 1407 const MegamorphicCache& cache = | 1412 const MegamorphicCache& cache = |
| 1408 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1413 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); |
| 1409 Label not_smi, load_cache; | 1414 Label not_smi, load_cache; |
| 1410 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); | 1415 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); |
| 1411 __ testq(RAX, Immediate(kSmiTagMask)); | 1416 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1412 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 1417 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1413 __ movq(RAX, Immediate(Smi::RawValue(kSmiCid))); | 1418 __ LoadImmediate(RAX, Immediate(Smi::RawValue(kSmiCid)), PP); |
| 1414 __ jmp(&load_cache); | 1419 __ jmp(&load_cache); |
| 1415 | 1420 |
| 1416 __ Bind(¬_smi); | 1421 __ Bind(¬_smi); |
| 1417 __ LoadClassId(RAX, RAX); | 1422 __ LoadClassId(RAX, RAX); |
| 1418 __ SmiTag(RAX); | 1423 __ SmiTag(RAX); |
| 1419 | 1424 |
| 1420 // RAX: class ID of the receiver (smi). | 1425 // RAX: class ID of the receiver (smi). |
| 1421 __ Bind(&load_cache); | 1426 __ Bind(&load_cache); |
| 1422 __ LoadObject(RBX, cache, PP); | 1427 __ LoadObject(RBX, cache, PP); |
| 1423 __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset())); | 1428 __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset())); |
| 1424 __ movq(RBX, FieldAddress(RBX, MegamorphicCache::mask_offset())); | 1429 __ movq(RBX, FieldAddress(RBX, MegamorphicCache::mask_offset())); |
| 1425 // RDI: cache buckets array. | 1430 // RDI: cache buckets array. |
| 1426 // RBX: mask. | 1431 // RBX: mask. |
| 1427 __ movq(RCX, RAX); | 1432 __ movq(RCX, RAX); |
| 1428 | 1433 |
| 1429 Label loop, update, call_target_function; | 1434 Label loop, update, call_target_function; |
| 1430 __ jmp(&loop); | 1435 __ jmp(&loop); |
| 1431 | 1436 |
| 1432 __ Bind(&update); | 1437 __ Bind(&update); |
| 1433 __ addq(RCX, Immediate(Smi::RawValue(1))); | 1438 __ AddImmediate(RCX, Immediate(Smi::RawValue(1)), PP); |
| 1434 __ Bind(&loop); | 1439 __ Bind(&loop); |
| 1435 __ andq(RCX, RBX); | 1440 __ andq(RCX, RBX); |
| 1436 const intptr_t base = Array::data_offset(); | 1441 const intptr_t base = Array::data_offset(); |
| 1437 // RCX is smi tagged, but table entries are two words, so TIMES_8. | 1442 // RCX is smi tagged, but table entries are two words, so TIMES_8. |
| 1438 __ movq(RDX, FieldAddress(RDI, RCX, TIMES_8, base)); | 1443 __ movq(RDX, FieldAddress(RDI, RCX, TIMES_8, base)); |
| 1439 | 1444 |
| 1440 ASSERT(kIllegalCid == 0); | 1445 ASSERT(kIllegalCid == 0); |
| 1441 __ testq(RDX, RDX); | 1446 __ testq(RDX, RDX); |
| 1442 __ j(ZERO, &call_target_function, Assembler::kNearJump); | 1447 __ j(ZERO, &call_target_function, Assembler::kNearJump); |
| 1443 __ cmpq(RDX, RAX); | 1448 __ cmpq(RDX, RAX); |
| 1444 __ j(NOT_EQUAL, &update, Assembler::kNearJump); | 1449 __ j(NOT_EQUAL, &update, Assembler::kNearJump); |
| 1445 | 1450 |
| 1446 __ Bind(&call_target_function); | 1451 __ Bind(&call_target_function); |
| 1447 // Call the target found in the cache. For a class id match, this is a | 1452 // Call the target found in the cache. For a class id match, this is a |
| 1448 // proper target for the given name and arguments descriptor. If the | 1453 // proper target for the given name and arguments descriptor. If the |
| 1449 // illegal class id was found, the target is a cache miss handler that can | 1454 // illegal class id was found, the target is a cache miss handler that can |
| 1450 // be invoked as a normal Dart function. | 1455 // be invoked as a normal Dart function. |
| 1451 __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize)); | 1456 __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize)); |
| 1452 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); | 1457 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
| 1453 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); | 1458 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| 1454 __ LoadObject(RBX, ic_data, PP); | 1459 __ LoadObject(RBX, ic_data, PP); |
| 1455 __ LoadObject(R10, arguments_descriptor, PP); | 1460 __ LoadObject(R10, arguments_descriptor, PP); |
| 1456 __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1461 __ AddImmediate( |
| 1462 RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag), PP); |
| 1457 __ call(RAX); | 1463 __ call(RAX); |
| 1458 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); | 1464 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| 1459 RecordSafepoint(locs); | 1465 RecordSafepoint(locs); |
| 1460 AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos); | 1466 AddDeoptIndexAtCall(Isolate::ToDeoptAfter(deopt_id), token_pos); |
| 1461 __ Drop(argument_count); | 1467 __ Drop(argument_count); |
| 1462 } | 1468 } |
| 1463 | 1469 |
| 1464 | 1470 |
| 1465 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1471 void FlowGraphCompiler::EmitOptimizedStaticCall( |
| 1466 const Function& function, | 1472 const Function& function, |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1493 } | 1499 } |
| 1494 | 1500 |
| 1495 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { | 1501 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { |
| 1496 ASSERT(!needs_number_check); | 1502 ASSERT(!needs_number_check); |
| 1497 __ testq(reg, reg); | 1503 __ testq(reg, reg); |
| 1498 return; | 1504 return; |
| 1499 } | 1505 } |
| 1500 | 1506 |
| 1501 if (needs_number_check) { | 1507 if (needs_number_check) { |
| 1502 __ pushq(reg); | 1508 __ pushq(reg); |
| 1503 __ PushObject(obj); | 1509 __ PushObject(obj, PP); |
| 1504 if (is_optimizing()) { | 1510 if (is_optimizing()) { |
| 1505 __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); | 1511 __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); |
| 1506 } else { | 1512 } else { |
| 1507 __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1513 __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); |
| 1508 } | 1514 } |
| 1509 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1515 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1510 Isolate::kNoDeoptId, | 1516 Isolate::kNoDeoptId, |
| 1511 token_pos); | 1517 token_pos); |
| 1512 __ popq(reg); // Discard constant. | 1518 __ popq(reg); // Discard constant. |
| 1513 __ popq(reg); // Restore 'reg'. | 1519 __ popq(reg); // Restore 'reg'. |
| 1514 return; | 1520 return; |
| 1515 } | 1521 } |
| 1516 | 1522 |
| 1517 __ CompareObject(reg, obj); | 1523 __ CompareObject(reg, obj, PP); |
| 1518 } | 1524 } |
| 1519 | 1525 |
| 1520 | 1526 |
| 1521 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1527 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1522 Register right, | 1528 Register right, |
| 1523 bool needs_number_check, | 1529 bool needs_number_check, |
| 1524 intptr_t token_pos) { | 1530 intptr_t token_pos) { |
| 1525 if (needs_number_check) { | 1531 if (needs_number_check) { |
| 1526 __ pushq(left); | 1532 __ pushq(left); |
| 1527 __ pushq(right); | 1533 __ pushq(right); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1540 __ cmpl(left, right); | 1546 __ cmpl(left, right); |
| 1541 } | 1547 } |
| 1542 } | 1548 } |
| 1543 | 1549 |
| 1544 | 1550 |
| 1545 // This function must be in sync with FlowGraphCompiler::RecordSafepoint. | 1551 // This function must be in sync with FlowGraphCompiler::RecordSafepoint. |
| 1546 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1552 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 1547 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1553 // TODO(vegorov): consider saving only caller save (volatile) registers. |
| 1548 const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count(); | 1554 const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count(); |
| 1549 if (xmm_regs_count > 0) { | 1555 if (xmm_regs_count > 0) { |
| 1550 __ subq(RSP, Immediate(xmm_regs_count * kFpuRegisterSize)); | 1556 __ AddImmediate(RSP, Immediate(-xmm_regs_count * kFpuRegisterSize), PP); |
| 1551 // Store XMM registers with the lowest register number at the lowest | 1557 // Store XMM registers with the lowest register number at the lowest |
| 1552 // address. | 1558 // address. |
| 1553 intptr_t offset = 0; | 1559 intptr_t offset = 0; |
| 1554 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | 1560 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 1555 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | 1561 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 1556 if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { | 1562 if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { |
| 1557 __ movups(Address(RSP, offset), xmm_reg); | 1563 __ movups(Address(RSP, offset), xmm_reg); |
| 1558 offset += kFpuRegisterSize; | 1564 offset += kFpuRegisterSize; |
| 1559 } | 1565 } |
| 1560 } | 1566 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1587 // XMM registers have the lowest register number at the lowest address. | 1593 // XMM registers have the lowest register number at the lowest address. |
| 1588 intptr_t offset = 0; | 1594 intptr_t offset = 0; |
| 1589 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | 1595 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 1590 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | 1596 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 1591 if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { | 1597 if (locs->live_registers()->ContainsFpuRegister(xmm_reg)) { |
| 1592 __ movups(xmm_reg, Address(RSP, offset)); | 1598 __ movups(xmm_reg, Address(RSP, offset)); |
| 1593 offset += kFpuRegisterSize; | 1599 offset += kFpuRegisterSize; |
| 1594 } | 1600 } |
| 1595 } | 1601 } |
| 1596 ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); | 1602 ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); |
| 1597 __ addq(RSP, Immediate(offset)); | 1603 __ AddImmediate(RSP, Immediate(offset), PP); |
| 1598 } | 1604 } |
| 1599 } | 1605 } |
| 1600 | 1606 |
| 1601 | 1607 |
| 1602 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1608 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 1603 Register class_id_reg, | 1609 Register class_id_reg, |
| 1604 intptr_t argument_count, | 1610 intptr_t argument_count, |
| 1605 const Array& argument_names, | 1611 const Array& argument_names, |
| 1606 Label* deopt, | 1612 Label* deopt, |
| 1607 intptr_t deopt_id, | 1613 intptr_t deopt_id, |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1883 } | 1889 } |
| 1884 | 1890 |
| 1885 | 1891 |
| 1886 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, | 1892 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, |
| 1887 const Address& src) { | 1893 const Address& src) { |
| 1888 __ MoveMemoryToMemory(dst, src); | 1894 __ MoveMemoryToMemory(dst, src); |
| 1889 } | 1895 } |
| 1890 | 1896 |
| 1891 | 1897 |
| 1892 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { | 1898 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { |
| 1893 __ StoreObject(dst, obj); | 1899 __ StoreObject(dst, obj, PP); |
| 1894 } | 1900 } |
| 1895 | 1901 |
| 1896 | 1902 |
| 1897 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { | 1903 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { |
| 1898 __ Exchange(reg, mem); | 1904 __ Exchange(reg, mem); |
| 1899 } | 1905 } |
| 1900 | 1906 |
| 1901 | 1907 |
| 1902 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1908 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 1903 __ Exchange(mem1, mem2); | 1909 __ Exchange(mem1, mem2); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1919 __ pushq(reg); | 1925 __ pushq(reg); |
| 1920 } | 1926 } |
| 1921 | 1927 |
| 1922 | 1928 |
| 1923 void ParallelMoveResolver::RestoreScratch(Register reg) { | 1929 void ParallelMoveResolver::RestoreScratch(Register reg) { |
| 1924 __ popq(reg); | 1930 __ popq(reg); |
| 1925 } | 1931 } |
| 1926 | 1932 |
| 1927 | 1933 |
| 1928 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { | 1934 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { |
| 1929 __ subq(RSP, Immediate(kFpuRegisterSize)); | 1935 __ AddImmediate(RSP, Immediate(-kFpuRegisterSize), PP); |
| 1930 __ movups(Address(RSP, 0), reg); | 1936 __ movups(Address(RSP, 0), reg); |
| 1931 } | 1937 } |
| 1932 | 1938 |
| 1933 | 1939 |
| 1934 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1940 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1935 __ movups(reg, Address(RSP, 0)); | 1941 __ movups(reg, Address(RSP, 0)); |
| 1936 __ addq(RSP, Immediate(kFpuRegisterSize)); | 1942 __ AddImmediate(RSP, Immediate(kFpuRegisterSize), PP); |
| 1937 } | 1943 } |
| 1938 | 1944 |
| 1939 | 1945 |
| 1940 #undef __ | 1946 #undef __ |
| 1941 | 1947 |
| 1942 } // namespace dart | 1948 } // namespace dart |
| 1943 | 1949 |
| 1944 #endif // defined TARGET_ARCH_X64 | 1950 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |