Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Side by Side Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 25118002: Eliminates more large immediates from x64 code. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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, &not_smi, Assembler::kNearJump); 436 __ j(NOT_ZERO, &not_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(&not_smi); 444 __ Bind(&not_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
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
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
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
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
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
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
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
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, &not_smi, Assembler::kNearJump); 1417 __ j(NOT_ZERO, &not_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(&not_smi); 1421 __ Bind(&not_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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698