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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 | 60 |
61 | 61 |
62 bool FlowGraphCompiler::SupportsHardwareDivision() { | 62 bool FlowGraphCompiler::SupportsHardwareDivision() { |
63 return true; | 63 return true; |
64 } | 64 } |
65 | 65 |
66 | 66 |
67 void FlowGraphCompiler::EnterIntrinsicMode() { | 67 void FlowGraphCompiler::EnterIntrinsicMode() { |
68 ASSERT(!intrinsic_mode()); | 68 ASSERT(!intrinsic_mode()); |
69 intrinsic_mode_ = true; | 69 intrinsic_mode_ = true; |
70 assembler()->set_constant_pool_allowed(false); | 70 ASSERT(!assembler()->constant_pool_allowed()); |
71 } | 71 } |
72 | 72 |
73 | 73 |
74 void FlowGraphCompiler::ExitIntrinsicMode() { | 74 void FlowGraphCompiler::ExitIntrinsicMode() { |
75 ASSERT(intrinsic_mode()); | 75 ASSERT(intrinsic_mode()); |
76 intrinsic_mode_ = false; | 76 intrinsic_mode_ = false; |
77 assembler()->set_constant_pool_allowed(true); | |
srdjan
2015/07/30 22:44:11
SHouldn't this be set (if at all) to whatever it w
regis
2015/07/30 23:04:16
The improved code maintains the state of constant_
| |
78 } | 77 } |
79 | 78 |
80 | 79 |
81 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 80 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, |
82 DeoptInfoBuilder* builder, | 81 DeoptInfoBuilder* builder, |
83 const Array& deopt_table) { | 82 const Array& deopt_table) { |
84 if (deopt_env_ == NULL) { | 83 if (deopt_env_ == NULL) { |
85 ++builder->current_info_number_; | 84 ++builder->current_info_number_; |
86 return TypedData::null(); | 85 return TypedData::null(); |
87 } | 86 } |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 Assembler* assem = compiler->assembler(); | 181 Assembler* assem = compiler->assembler(); |
183 #define __ assem-> | 182 #define __ assem-> |
184 __ Comment("%s", Name()); | 183 __ Comment("%s", Name()); |
185 __ Bind(entry_label()); | 184 __ Bind(entry_label()); |
186 if (FLAG_trap_on_deoptimization) { | 185 if (FLAG_trap_on_deoptimization) { |
187 __ int3(); | 186 __ int3(); |
188 } | 187 } |
189 | 188 |
190 ASSERT(deopt_env() != NULL); | 189 ASSERT(deopt_env() != NULL); |
191 | 190 |
192 __ Call(&StubCode::DeoptimizeLabel(), PP); | 191 __ Call(&StubCode::DeoptimizeLabel()); |
193 set_pc_offset(assem->CodeSize()); | 192 set_pc_offset(assem->CodeSize()); |
194 __ int3(); | 193 __ int3(); |
195 #undef __ | 194 #undef __ |
196 } | 195 } |
197 | 196 |
198 | 197 |
199 #define __ assembler()-> | 198 #define __ assembler()-> |
200 | 199 |
201 | 200 |
202 // Fall through if bool_register contains null. | 201 // Fall through if bool_register contains null. |
203 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 202 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
204 Label* is_true, | 203 Label* is_true, |
205 Label* is_false) { | 204 Label* is_false) { |
206 Label fall_through; | 205 Label fall_through; |
207 __ CompareObject(bool_register, Object::null_object(), PP); | 206 __ CompareObject(bool_register, Object::null_object()); |
208 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 207 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
209 __ CompareObject(bool_register, Bool::True(), PP); | 208 __ CompareObject(bool_register, Bool::True()); |
210 __ j(EQUAL, is_true); | 209 __ j(EQUAL, is_true); |
211 __ jmp(is_false); | 210 __ jmp(is_false); |
212 __ Bind(&fall_through); | 211 __ Bind(&fall_through); |
213 } | 212 } |
214 | 213 |
215 | 214 |
216 // Clobbers RCX. | 215 // Clobbers RCX. |
217 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 216 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
218 TypeTestStubKind test_kind, | 217 TypeTestStubKind test_kind, |
219 Register instance_reg, | 218 Register instance_reg, |
220 Register type_arguments_reg, | 219 Register type_arguments_reg, |
221 Register temp_reg, | 220 Register temp_reg, |
222 Label* is_instance_lbl, | 221 Label* is_instance_lbl, |
223 Label* is_not_instance_lbl) { | 222 Label* is_not_instance_lbl) { |
224 const SubtypeTestCache& type_test_cache = | 223 const SubtypeTestCache& type_test_cache = |
225 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 224 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
226 __ LoadUniqueObject(temp_reg, type_test_cache, PP); | 225 __ LoadUniqueObject(temp_reg, type_test_cache); |
227 __ pushq(temp_reg); // Subtype test cache. | 226 __ pushq(temp_reg); // Subtype test cache. |
228 __ pushq(instance_reg); // Instance. | 227 __ pushq(instance_reg); // Instance. |
229 if (test_kind == kTestTypeOneArg) { | 228 if (test_kind == kTestTypeOneArg) { |
230 ASSERT(type_arguments_reg == kNoRegister); | 229 ASSERT(type_arguments_reg == kNoRegister); |
231 __ PushObject(Object::null_object(), PP); | 230 __ PushObject(Object::null_object()); |
232 __ Call(&StubCode::Subtype1TestCacheLabel(), PP); | 231 __ Call(&StubCode::Subtype1TestCacheLabel()); |
233 } else if (test_kind == kTestTypeTwoArgs) { | 232 } else if (test_kind == kTestTypeTwoArgs) { |
234 ASSERT(type_arguments_reg == kNoRegister); | 233 ASSERT(type_arguments_reg == kNoRegister); |
235 __ PushObject(Object::null_object(), PP); | 234 __ PushObject(Object::null_object()); |
236 __ Call(&StubCode::Subtype2TestCacheLabel(), PP); | 235 __ Call(&StubCode::Subtype2TestCacheLabel()); |
237 } else if (test_kind == kTestTypeThreeArgs) { | 236 } else if (test_kind == kTestTypeThreeArgs) { |
238 __ pushq(type_arguments_reg); | 237 __ pushq(type_arguments_reg); |
239 __ Call(&StubCode::Subtype3TestCacheLabel(), PP); | 238 __ Call(&StubCode::Subtype3TestCacheLabel()); |
240 } else { | 239 } else { |
241 UNREACHABLE(); | 240 UNREACHABLE(); |
242 } | 241 } |
243 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. | 242 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
244 ASSERT(instance_reg != RCX); | 243 ASSERT(instance_reg != RCX); |
245 ASSERT(temp_reg != RCX); | 244 ASSERT(temp_reg != RCX); |
246 __ popq(instance_reg); // Discard. | 245 __ popq(instance_reg); // Discard. |
247 __ popq(instance_reg); // Restore receiver. | 246 __ popq(instance_reg); // Restore receiver. |
248 __ popq(temp_reg); // Discard. | 247 __ popq(temp_reg); // Discard. |
249 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); | 248 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 // interfaces. | 376 // interfaces. |
378 // Bool interface can be implemented only by core class Bool. | 377 // Bool interface can be implemented only by core class Bool. |
379 if (type.IsBoolType()) { | 378 if (type.IsBoolType()) { |
380 __ cmpl(kClassIdReg, Immediate(kBoolCid)); | 379 __ cmpl(kClassIdReg, Immediate(kBoolCid)); |
381 __ j(EQUAL, is_instance_lbl); | 380 __ j(EQUAL, is_instance_lbl); |
382 __ jmp(is_not_instance_lbl); | 381 __ jmp(is_not_instance_lbl); |
383 return false; | 382 return false; |
384 } | 383 } |
385 if (type.IsFunctionType()) { | 384 if (type.IsFunctionType()) { |
386 // Check if instance is a closure. | 385 // Check if instance is a closure. |
387 __ LoadClassById(R13, kClassIdReg, PP); | 386 __ LoadClassById(R13, kClassIdReg); |
388 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); | 387 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); |
389 __ CompareObject(R13, Object::null_object(), PP); | 388 __ CompareObject(R13, Object::null_object()); |
390 __ j(NOT_EQUAL, is_instance_lbl); | 389 __ j(NOT_EQUAL, is_instance_lbl); |
391 } | 390 } |
392 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 391 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
393 // Note that instance is not Smi (checked above). | 392 // Note that instance is not Smi (checked above). |
394 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 393 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
395 GenerateNumberTypeCheck( | 394 GenerateNumberTypeCheck( |
396 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 395 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
397 return false; | 396 return false; |
398 } | 397 } |
399 if (type.IsStringType()) { | 398 if (type.IsStringType()) { |
(...skipping 12 matching lines...) Expand all Loading... | |
412 // TODO(srdjan): Implement a quicker subtype check, as type test | 411 // TODO(srdjan): Implement a quicker subtype check, as type test |
413 // arrays can grow too high, but they may be useful when optimizing | 412 // arrays can grow too high, but they may be useful when optimizing |
414 // code (type-feedback). | 413 // code (type-feedback). |
415 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 414 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
416 intptr_t token_pos, | 415 intptr_t token_pos, |
417 const Class& type_class, | 416 const Class& type_class, |
418 Label* is_instance_lbl, | 417 Label* is_instance_lbl, |
419 Label* is_not_instance_lbl) { | 418 Label* is_not_instance_lbl) { |
420 __ Comment("Subtype1TestCacheLookup"); | 419 __ Comment("Subtype1TestCacheLookup"); |
421 const Register kInstanceReg = RAX; | 420 const Register kInstanceReg = RAX; |
422 __ LoadClass(R10, kInstanceReg, PP); | 421 __ LoadClass(R10, kInstanceReg); |
423 // R10: instance class. | 422 // R10: instance class. |
424 // Check immediate superclass equality. | 423 // Check immediate superclass equality. |
425 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); | 424 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); |
426 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); | 425 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); |
427 __ CompareObject(R13, type_class, PP); | 426 __ CompareObject(R13, type_class); |
428 __ j(EQUAL, is_instance_lbl); | 427 __ j(EQUAL, is_instance_lbl); |
429 | 428 |
430 const Register kTypeArgumentsReg = kNoRegister; | 429 const Register kTypeArgumentsReg = kNoRegister; |
431 const Register kTempReg = R10; | 430 const Register kTempReg = R10; |
432 return GenerateCallSubtypeTestStub(kTestTypeOneArg, | 431 return GenerateCallSubtypeTestStub(kTestTypeOneArg, |
433 kInstanceReg, | 432 kInstanceReg, |
434 kTypeArgumentsReg, | 433 kTypeArgumentsReg, |
435 kTempReg, | 434 kTempReg, |
436 is_instance_lbl, | 435 is_instance_lbl, |
437 is_not_instance_lbl); | 436 is_not_instance_lbl); |
(...skipping 10 matching lines...) Expand all Loading... | |
448 Label* is_not_instance_lbl) { | 447 Label* is_not_instance_lbl) { |
449 __ Comment("UninstantiatedTypeTest"); | 448 __ Comment("UninstantiatedTypeTest"); |
450 ASSERT(!type.IsInstantiated()); | 449 ASSERT(!type.IsInstantiated()); |
451 // Skip check if destination is a dynamic type. | 450 // Skip check if destination is a dynamic type. |
452 if (type.IsTypeParameter()) { | 451 if (type.IsTypeParameter()) { |
453 const TypeParameter& type_param = TypeParameter::Cast(type); | 452 const TypeParameter& type_param = TypeParameter::Cast(type); |
454 // Load instantiator (or null) and instantiator type arguments on stack. | 453 // Load instantiator (or null) and instantiator type arguments on stack. |
455 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 454 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
456 // RDX: instantiator type arguments. | 455 // RDX: instantiator type arguments. |
457 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 456 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
458 __ CompareObject(RDX, Object::null_object(), PP); | 457 __ CompareObject(RDX, Object::null_object()); |
459 __ j(EQUAL, is_instance_lbl); | 458 __ j(EQUAL, is_instance_lbl); |
460 __ movq(RDI, | 459 __ movq(RDI, |
461 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 460 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); |
462 // RDI: Concrete type of type. | 461 // RDI: Concrete type of type. |
463 // Check if type argument is dynamic. | 462 // Check if type argument is dynamic. |
464 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()), PP); | 463 __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType())); |
465 __ j(EQUAL, is_instance_lbl); | 464 __ j(EQUAL, is_instance_lbl); |
466 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 465 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
467 __ CompareObject(RDI, object_type, PP); | 466 __ CompareObject(RDI, object_type); |
468 __ j(EQUAL, is_instance_lbl); | 467 __ j(EQUAL, is_instance_lbl); |
469 | 468 |
470 // For Smi check quickly against int and num interfaces. | 469 // For Smi check quickly against int and num interfaces. |
471 Label not_smi; | 470 Label not_smi; |
472 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 471 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
473 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 472 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
474 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType()), PP); | 473 __ CompareObject(RDI, Type::ZoneHandle(Type::IntType())); |
475 __ j(EQUAL, is_instance_lbl); | 474 __ j(EQUAL, is_instance_lbl); |
476 __ CompareObject(RDI, Type::ZoneHandle(Type::Number()), PP); | 475 __ CompareObject(RDI, Type::ZoneHandle(Type::Number())); |
477 __ j(EQUAL, is_instance_lbl); | 476 __ j(EQUAL, is_instance_lbl); |
478 // Smi must be handled in runtime. | 477 // Smi must be handled in runtime. |
479 Label fall_through; | 478 Label fall_through; |
480 __ jmp(&fall_through); | 479 __ jmp(&fall_through); |
481 | 480 |
482 __ Bind(¬_smi); | 481 __ Bind(¬_smi); |
483 // RDX: instantiator type arguments. | 482 // RDX: instantiator type arguments. |
484 // RAX: instance. | 483 // RAX: instance. |
485 const Register kInstanceReg = RAX; | 484 const Register kInstanceReg = RAX; |
486 const Register kTypeArgumentsReg = RDX; | 485 const Register kTypeArgumentsReg = RDX; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
594 // If type is instantiated and non-parameterized, we can inline code | 593 // If type is instantiated and non-parameterized, we can inline code |
595 // checking whether the tested instance is a Smi. | 594 // checking whether the tested instance is a Smi. |
596 if (type.IsInstantiated()) { | 595 if (type.IsInstantiated()) { |
597 // A null object is only an instance of Object and dynamic, which has | 596 // A null object is only an instance of Object and dynamic, which has |
598 // already been checked above (if the type is instantiated). So we can | 597 // already been checked above (if the type is instantiated). So we can |
599 // return false here if the instance is null (and if the type is | 598 // return false here if the instance is null (and if the type is |
600 // instantiated). | 599 // instantiated). |
601 // We can only inline this null check if the type is instantiated at compile | 600 // We can only inline this null check if the type is instantiated at compile |
602 // time, since an uninstantiated type at compile time could be Object or | 601 // time, since an uninstantiated type at compile time could be Object or |
603 // dynamic at run time. | 602 // dynamic at run time. |
604 __ CompareObject(RAX, Object::null_object(), PP); | 603 __ CompareObject(RAX, Object::null_object()); |
605 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 604 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
606 } | 605 } |
607 | 606 |
608 // Generate inline instanceof test. | 607 // Generate inline instanceof test. |
609 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 608 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
610 test_cache = GenerateInlineInstanceof(token_pos, type, | 609 test_cache = GenerateInlineInstanceof(token_pos, type, |
611 &is_instance, &is_not_instance); | 610 &is_instance, &is_not_instance); |
612 | 611 |
613 // test_cache is null if there is no fall-through. | 612 // test_cache is null if there is no fall-through. |
614 Label done; | 613 Label done; |
615 if (!test_cache.IsNull()) { | 614 if (!test_cache.IsNull()) { |
616 // Generate runtime call. | 615 // Generate runtime call. |
617 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 616 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
618 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 617 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
619 __ PushObject(Object::null_object(), PP); // Make room for the result. | 618 __ PushObject(Object::null_object()); // Make room for the result. |
620 __ pushq(RAX); // Push the instance. | 619 __ pushq(RAX); // Push the instance. |
621 __ PushObject(type, PP); // Push the type. | 620 __ PushObject(type); // Push the type. |
622 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. | 621 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
623 __ pushq(RDX); // Instantiator type arguments. | 622 __ pushq(RDX); // Instantiator type arguments. |
624 __ LoadUniqueObject(RAX, test_cache, PP); | 623 __ LoadUniqueObject(RAX, test_cache); |
625 __ pushq(RAX); | 624 __ pushq(RAX); |
626 GenerateRuntimeCall(token_pos, | 625 GenerateRuntimeCall(token_pos, |
627 deopt_id, | 626 deopt_id, |
628 kInstanceofRuntimeEntry, | 627 kInstanceofRuntimeEntry, |
629 5, | 628 5, |
630 locs); | 629 locs); |
631 // Pop the parameters supplied to the runtime entry. The result of the | 630 // Pop the parameters supplied to the runtime entry. The result of the |
632 // instanceof runtime call will be left as the result of the operation. | 631 // instanceof runtime call will be left as the result of the operation. |
633 __ Drop(5); | 632 __ Drop(5); |
634 if (negate_result) { | 633 if (negate_result) { |
635 __ popq(RDX); | 634 __ popq(RDX); |
636 __ LoadObject(RAX, Bool::True(), PP); | 635 __ LoadObject(RAX, Bool::True()); |
637 __ cmpq(RDX, RAX); | 636 __ cmpq(RDX, RAX); |
638 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 637 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
639 __ LoadObject(RAX, Bool::False(), PP); | 638 __ LoadObject(RAX, Bool::False()); |
640 } else { | 639 } else { |
641 __ popq(RAX); | 640 __ popq(RAX); |
642 } | 641 } |
643 __ jmp(&done, Assembler::kNearJump); | 642 __ jmp(&done, Assembler::kNearJump); |
644 } | 643 } |
645 __ Bind(&is_not_instance); | 644 __ Bind(&is_not_instance); |
646 __ LoadObject(RAX, Bool::Get(negate_result), PP); | 645 __ LoadObject(RAX, Bool::Get(negate_result)); |
647 __ jmp(&done, Assembler::kNearJump); | 646 __ jmp(&done, Assembler::kNearJump); |
648 | 647 |
649 __ Bind(&is_instance); | 648 __ Bind(&is_instance); |
650 __ LoadObject(RAX, Bool::Get(!negate_result), PP); | 649 __ LoadObject(RAX, Bool::Get(!negate_result)); |
651 __ Bind(&done); | 650 __ Bind(&done); |
652 __ popq(RDX); // Remove pushed instantiator type arguments. | 651 __ popq(RDX); // Remove pushed instantiator type arguments. |
653 __ popq(RCX); // Remove pushed instantiator. | 652 __ popq(RCX); // Remove pushed instantiator. |
654 } | 653 } |
655 | 654 |
656 | 655 |
657 // Optimize assignable type check by adding inlined tests for: | 656 // Optimize assignable type check by adding inlined tests for: |
658 // - NULL -> return NULL. | 657 // - NULL -> return NULL. |
659 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 658 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
660 // - Class equality (only if class is not parameterized). | 659 // - Class equality (only if class is not parameterized). |
(...skipping 13 matching lines...) Expand all Loading... | |
674 ASSERT(token_pos >= 0); | 673 ASSERT(token_pos >= 0); |
675 ASSERT(!dst_type.IsNull()); | 674 ASSERT(!dst_type.IsNull()); |
676 ASSERT(dst_type.IsFinalized()); | 675 ASSERT(dst_type.IsFinalized()); |
677 // Assignable check is skipped in FlowGraphBuilder, not here. | 676 // Assignable check is skipped in FlowGraphBuilder, not here. |
678 ASSERT(dst_type.IsMalformedOrMalbounded() || | 677 ASSERT(dst_type.IsMalformedOrMalbounded() || |
679 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 678 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
680 __ pushq(RCX); // Store instantiator. | 679 __ pushq(RCX); // Store instantiator. |
681 __ pushq(RDX); // Store instantiator type arguments. | 680 __ pushq(RDX); // Store instantiator type arguments. |
682 // A null object is always assignable and is returned as result. | 681 // A null object is always assignable and is returned as result. |
683 Label is_assignable, runtime_call; | 682 Label is_assignable, runtime_call; |
684 __ CompareObject(RAX, Object::null_object(), PP); | 683 __ CompareObject(RAX, Object::null_object()); |
685 __ j(EQUAL, &is_assignable); | 684 __ j(EQUAL, &is_assignable); |
686 | 685 |
687 // Generate throw new TypeError() if the type is malformed or malbounded. | 686 // Generate throw new TypeError() if the type is malformed or malbounded. |
688 if (dst_type.IsMalformedOrMalbounded()) { | 687 if (dst_type.IsMalformedOrMalbounded()) { |
689 __ PushObject(Object::null_object(), PP); // Make room for the result. | 688 __ PushObject(Object::null_object()); // Make room for the result. |
690 __ pushq(RAX); // Push the source object. | 689 __ pushq(RAX); // Push the source object. |
691 __ PushObject(dst_name, PP); // Push the name of the destination. | 690 __ PushObject(dst_name); // Push the name of the destination. |
692 __ PushObject(dst_type, PP); // Push the type of the destination. | 691 __ PushObject(dst_type); // Push the type of the destination. |
693 GenerateRuntimeCall(token_pos, | 692 GenerateRuntimeCall(token_pos, |
694 deopt_id, | 693 deopt_id, |
695 kBadTypeErrorRuntimeEntry, | 694 kBadTypeErrorRuntimeEntry, |
696 3, | 695 3, |
697 locs); | 696 locs); |
698 // We should never return here. | 697 // We should never return here. |
699 __ int3(); | 698 __ int3(); |
700 | 699 |
701 __ Bind(&is_assignable); // For a null object. | 700 __ Bind(&is_assignable); // For a null object. |
702 __ popq(RDX); // Remove pushed instantiator type arguments. | 701 __ popq(RDX); // Remove pushed instantiator type arguments. |
703 __ popq(RCX); // Remove pushed instantiator. | 702 __ popq(RCX); // Remove pushed instantiator. |
704 return; | 703 return; |
705 } | 704 } |
706 | 705 |
707 // Generate inline type check, linking to runtime call if not assignable. | 706 // Generate inline type check, linking to runtime call if not assignable. |
708 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 707 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
709 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 708 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
710 &is_assignable, &runtime_call); | 709 &is_assignable, &runtime_call); |
711 | 710 |
712 __ Bind(&runtime_call); | 711 __ Bind(&runtime_call); |
713 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 712 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
714 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | 713 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
715 __ PushObject(Object::null_object(), PP); // Make room for the result. | 714 __ PushObject(Object::null_object()); // Make room for the result. |
716 __ pushq(RAX); // Push the source object. | 715 __ pushq(RAX); // Push the source object. |
717 __ PushObject(dst_type, PP); // Push the type of the destination. | 716 __ PushObject(dst_type); // Push the type of the destination. |
718 __ pushq(RCX); // Instantiator. | 717 __ pushq(RCX); // Instantiator. |
719 __ pushq(RDX); // Instantiator type arguments. | 718 __ pushq(RDX); // Instantiator type arguments. |
720 __ PushObject(dst_name, PP); // Push the name of the destination. | 719 __ PushObject(dst_name); // Push the name of the destination. |
721 __ LoadUniqueObject(RAX, test_cache, PP); | 720 __ LoadUniqueObject(RAX, test_cache); |
722 __ pushq(RAX); | 721 __ pushq(RAX); |
723 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 722 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
724 // Pop the parameters supplied to the runtime entry. The result of the | 723 // Pop the parameters supplied to the runtime entry. The result of the |
725 // type check runtime call is the checked value. | 724 // type check runtime call is the checked value. |
726 __ Drop(6); | 725 __ Drop(6); |
727 __ popq(RAX); | 726 __ popq(RAX); |
728 | 727 |
729 __ Bind(&is_assignable); | 728 __ Bind(&is_assignable); |
730 __ popq(RDX); // Remove pushed instantiator type arguments. | 729 __ popq(RDX); // Remove pushed instantiator type arguments. |
731 __ popq(RCX); // Remove pushed instantiator. | 730 __ popq(RCX); // Remove pushed instantiator. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
763 | 762 |
764 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, | 763 // Check that min_num_pos_args <= num_pos_args <= max_num_pos_args, |
765 // where num_pos_args is the number of positional arguments passed in. | 764 // where num_pos_args is the number of positional arguments passed in. |
766 const int min_num_pos_args = num_fixed_params; | 765 const int min_num_pos_args = num_fixed_params; |
767 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; | 766 const int max_num_pos_args = num_fixed_params + num_opt_pos_params; |
768 | 767 |
769 __ movq(RCX, | 768 __ movq(RCX, |
770 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 769 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
771 // Check that min_num_pos_args <= num_pos_args. | 770 // Check that min_num_pos_args <= num_pos_args. |
772 Label wrong_num_arguments; | 771 Label wrong_num_arguments; |
773 __ CompareImmediate(RCX, Immediate(Smi::RawValue(min_num_pos_args)), PP); | 772 __ CompareImmediate(RCX, Immediate(Smi::RawValue(min_num_pos_args))); |
774 __ j(LESS, &wrong_num_arguments); | 773 __ j(LESS, &wrong_num_arguments); |
775 // Check that num_pos_args <= max_num_pos_args. | 774 // Check that num_pos_args <= max_num_pos_args. |
776 __ CompareImmediate(RCX, Immediate(Smi::RawValue(max_num_pos_args)), PP); | 775 __ CompareImmediate(RCX, Immediate(Smi::RawValue(max_num_pos_args))); |
777 __ j(GREATER, &wrong_num_arguments); | 776 __ j(GREATER, &wrong_num_arguments); |
778 | 777 |
779 // Copy positional arguments. | 778 // Copy positional arguments. |
780 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied | 779 // Argument i passed at fp[kParamEndSlotFromFp + num_args - i] is copied |
781 // to fp[kFirstLocalSlotFromFp - i]. | 780 // to fp[kFirstLocalSlotFromFp - i]. |
782 | 781 |
783 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 782 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
784 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. | 783 // Since RBX and RCX are Smi, use TIMES_4 instead of TIMES_8. |
785 // Let RBX point to the last passed positional argument, i.e. to | 784 // Let RBX point to the last passed positional argument, i.e. to |
786 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. | 785 // fp[kParamEndSlotFromFp + num_args - (num_pos_args - 1)]. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
848 // Let RDI point to the entry of the first named argument. | 847 // Let RDI point to the entry of the first named argument. |
849 __ leaq(RDI, | 848 __ leaq(RDI, |
850 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); | 849 FieldAddress(R10, ArgumentsDescriptor::first_named_entry_offset())); |
851 for (int i = 0; i < num_opt_named_params; i++) { | 850 for (int i = 0; i < num_opt_named_params; i++) { |
852 Label load_default_value, assign_optional_parameter; | 851 Label load_default_value, assign_optional_parameter; |
853 const int param_pos = opt_param_position[i]; | 852 const int param_pos = opt_param_position[i]; |
854 // Check if this named parameter was passed in. | 853 // Check if this named parameter was passed in. |
855 // Load RAX with the name of the argument. | 854 // Load RAX with the name of the argument. |
856 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); | 855 __ movq(RAX, Address(RDI, ArgumentsDescriptor::name_offset())); |
857 ASSERT(opt_param[i]->name().IsSymbol()); | 856 ASSERT(opt_param[i]->name().IsSymbol()); |
858 __ CompareObject(RAX, opt_param[i]->name(), PP); | 857 __ CompareObject(RAX, opt_param[i]->name()); |
859 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); | 858 __ j(NOT_EQUAL, &load_default_value, Assembler::kNearJump); |
860 // Load RAX with passed-in argument at provided arg_pos, i.e. at | 859 // Load RAX with passed-in argument at provided arg_pos, i.e. at |
861 // fp[kParamEndSlotFromFp + num_args - arg_pos]. | 860 // fp[kParamEndSlotFromFp + num_args - arg_pos]. |
862 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); | 861 __ movq(RAX, Address(RDI, ArgumentsDescriptor::position_offset())); |
863 // RAX is arg_pos as Smi. | 862 // RAX is arg_pos as Smi. |
864 // Point to next named entry. | 863 // Point to next named entry. |
865 __ AddImmediate( | 864 __ AddImmediate( |
866 RDI, Immediate(ArgumentsDescriptor::named_entry_size()), PP); | 865 RDI, Immediate(ArgumentsDescriptor::named_entry_size())); |
867 __ negq(RAX); | 866 __ negq(RAX); |
868 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. | 867 Address argument_addr(RBX, RAX, TIMES_4, 0); // RAX is a negative Smi. |
869 __ movq(RAX, argument_addr); | 868 __ movq(RAX, argument_addr); |
870 __ jmp(&assign_optional_parameter, Assembler::kNearJump); | 869 __ jmp(&assign_optional_parameter, Assembler::kNearJump); |
871 __ Bind(&load_default_value); | 870 __ Bind(&load_default_value); |
872 // Load RAX with default argument. | 871 // Load RAX with default argument. |
873 const Object& value = Object::ZoneHandle( | 872 const Object& value = Object::ZoneHandle( |
874 parsed_function().default_parameter_values().At( | 873 parsed_function().default_parameter_values().At( |
875 param_pos - num_fixed_params)); | 874 param_pos - num_fixed_params)); |
876 __ LoadObject(RAX, value, PP); | 875 __ LoadObject(RAX, value); |
877 __ Bind(&assign_optional_parameter); | 876 __ Bind(&assign_optional_parameter); |
878 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. | 877 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
879 // We do not use the final allocation index of the variable here, i.e. | 878 // We do not use the final allocation index of the variable here, i.e. |
880 // scope->VariableAt(i)->index(), because captured variables still need | 879 // scope->VariableAt(i)->index(), because captured variables still need |
881 // to be copied to the context that is not yet allocated. | 880 // to be copied to the context that is not yet allocated. |
882 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 881 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
883 const Address param_addr(RBP, computed_param_pos * kWordSize); | 882 const Address param_addr(RBP, computed_param_pos * kWordSize); |
884 __ movq(param_addr, RAX); | 883 __ movq(param_addr, RAX); |
885 } | 884 } |
886 delete[] opt_param; | 885 delete[] opt_param; |
887 delete[] opt_param_position; | 886 delete[] opt_param_position; |
888 if (check_correct_named_args) { | 887 if (check_correct_named_args) { |
889 // Check that RDI now points to the null terminator in the arguments | 888 // Check that RDI now points to the null terminator in the arguments |
890 // descriptor. | 889 // descriptor. |
891 __ LoadObject(TMP, Object::null_object(), PP); | 890 __ LoadObject(TMP, Object::null_object()); |
892 __ cmpq(Address(RDI, 0), TMP); | 891 __ cmpq(Address(RDI, 0), TMP); |
893 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 892 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
894 } | 893 } |
895 } else { | 894 } else { |
896 ASSERT(num_opt_pos_params > 0); | 895 ASSERT(num_opt_pos_params > 0); |
897 __ movq(RCX, | 896 __ movq(RCX, |
898 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); | 897 FieldAddress(R10, ArgumentsDescriptor::positional_count_offset())); |
899 __ SmiUntag(RCX); | 898 __ SmiUntag(RCX); |
900 for (int i = 0; i < num_opt_pos_params; i++) { | 899 for (int i = 0; i < num_opt_pos_params; i++) { |
901 Label next_parameter; | 900 Label next_parameter; |
902 // Handle this optional positional parameter only if k or fewer positional | 901 // Handle this optional positional parameter only if k or fewer positional |
903 // arguments have been passed, where k is param_pos, the position of this | 902 // arguments have been passed, where k is param_pos, the position of this |
904 // optional parameter in the formal parameter list. | 903 // optional parameter in the formal parameter list. |
905 const int param_pos = num_fixed_params + i; | 904 const int param_pos = num_fixed_params + i; |
906 __ CompareImmediate(RCX, Immediate(param_pos), PP); | 905 __ CompareImmediate(RCX, Immediate(param_pos)); |
907 __ j(GREATER, &next_parameter, Assembler::kNearJump); | 906 __ j(GREATER, &next_parameter, Assembler::kNearJump); |
908 // Load RAX with default argument. | 907 // Load RAX with default argument. |
909 const Object& value = Object::ZoneHandle( | 908 const Object& value = Object::ZoneHandle( |
910 parsed_function().default_parameter_values().At(i)); | 909 parsed_function().default_parameter_values().At(i)); |
911 __ LoadObject(RAX, value, PP); | 910 __ LoadObject(RAX, value); |
912 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. | 911 // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
913 // We do not use the final allocation index of the variable here, i.e. | 912 // We do not use the final allocation index of the variable here, i.e. |
914 // scope->VariableAt(i)->index(), because captured variables still need | 913 // scope->VariableAt(i)->index(), because captured variables still need |
915 // to be copied to the context that is not yet allocated. | 914 // to be copied to the context that is not yet allocated. |
916 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 915 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
917 const Address param_addr(RBP, computed_param_pos * kWordSize); | 916 const Address param_addr(RBP, computed_param_pos * kWordSize); |
918 __ movq(param_addr, RAX); | 917 __ movq(param_addr, RAX); |
919 __ Bind(&next_parameter); | 918 __ Bind(&next_parameter); |
920 } | 919 } |
921 if (check_correct_named_args) { | 920 if (check_correct_named_args) { |
922 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 921 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
923 __ SmiUntag(RBX); | 922 __ SmiUntag(RBX); |
924 // Check that RCX equals RBX, i.e. no named arguments passed. | 923 // Check that RCX equals RBX, i.e. no named arguments passed. |
925 __ cmpq(RCX, RBX); | 924 __ cmpq(RCX, RBX); |
926 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); | 925 __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
927 } | 926 } |
928 } | 927 } |
929 | 928 |
930 __ Bind(&wrong_num_arguments); | 929 __ Bind(&wrong_num_arguments); |
931 if (function.IsClosureFunction()) { | 930 if (function.IsClosureFunction()) { |
931 ASSERT(assembler()->constant_pool_allowed()); | |
932 __ LeaveDartFrame(); // The arguments are still on the stack. | 932 __ LeaveDartFrame(); // The arguments are still on the stack. |
933 ASSERT(!assembler()->constant_pool_allowed()); | |
933 __ jmp(&StubCode::CallClosureNoSuchMethodLabel()); | 934 __ jmp(&StubCode::CallClosureNoSuchMethodLabel()); |
935 __ set_constant_pool_allowed(true); | |
934 // The noSuchMethod call may return to the caller, but not here. | 936 // The noSuchMethod call may return to the caller, but not here. |
935 } else if (check_correct_named_args) { | 937 } else if (check_correct_named_args) { |
936 __ Stop("Wrong arguments"); | 938 __ Stop("Wrong arguments"); |
937 } | 939 } |
938 | 940 |
939 __ Bind(&all_arguments_processed); | 941 __ Bind(&all_arguments_processed); |
940 // Nullify originally passed arguments only after they have been copied and | 942 // Nullify originally passed arguments only after they have been copied and |
941 // checked, otherwise noSuchMethod would not see their original values. | 943 // checked, otherwise noSuchMethod would not see their original values. |
942 // This step can be skipped in case we decide that formal parameters are | 944 // This step can be skipped in case we decide that formal parameters are |
943 // implicitly final, since garbage collecting the unmodified value is not | 945 // implicitly final, since garbage collecting the unmodified value is not |
944 // an issue anymore. | 946 // an issue anymore. |
945 | 947 |
946 // R10 : arguments descriptor array. | 948 // R10 : arguments descriptor array. |
947 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 949 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
948 __ SmiUntag(RCX); | 950 __ SmiUntag(RCX); |
949 __ LoadObject(R12, Object::null_object(), PP); | 951 __ LoadObject(R12, Object::null_object()); |
950 Label null_args_loop, null_args_loop_condition; | 952 Label null_args_loop, null_args_loop_condition; |
951 __ jmp(&null_args_loop_condition, Assembler::kNearJump); | 953 __ jmp(&null_args_loop_condition, Assembler::kNearJump); |
952 const Address original_argument_addr( | 954 const Address original_argument_addr( |
953 RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize); | 955 RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize); |
954 __ Bind(&null_args_loop); | 956 __ Bind(&null_args_loop); |
955 __ movq(original_argument_addr, R12); | 957 __ movq(original_argument_addr, R12); |
956 __ Bind(&null_args_loop_condition); | 958 __ Bind(&null_args_loop_condition); |
957 __ decq(RCX); | 959 __ decq(RCX); |
958 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); | 960 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); |
959 } | 961 } |
(...skipping 12 matching lines...) Expand all Loading... | |
972 | 974 |
973 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 975 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
974 // TOS: return address. | 976 // TOS: return address. |
975 // +1 : value | 977 // +1 : value |
976 // +2 : receiver. | 978 // +2 : receiver. |
977 // Sequence node has one store node and one return NULL node. | 979 // Sequence node has one store node and one return NULL node. |
978 __ Comment("Inlined Setter"); | 980 __ Comment("Inlined Setter"); |
979 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. | 981 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. |
980 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. | 982 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. |
981 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); | 983 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); |
982 __ LoadObject(RAX, Object::null_object(), PP); | 984 __ LoadObject(RAX, Object::null_object()); |
983 __ ret(); | 985 __ ret(); |
984 } | 986 } |
985 | 987 |
986 | 988 |
987 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc | 989 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc |
988 // needs to be updated to match. | 990 // needs to be updated to match. |
989 void FlowGraphCompiler::EmitFrameEntry() { | 991 void FlowGraphCompiler::EmitFrameEntry() { |
990 ASSERT(Assembler::EntryPointToPcMarkerOffset() == 0); | 992 ASSERT(Assembler::EntryPointToPcMarkerOffset() == 0); |
991 | 993 |
992 const Function& function = parsed_function().function(); | 994 const Function& function = parsed_function().function(); |
(...skipping 16 matching lines...) Expand all Loading... | |
1009 - flow_graph().num_stack_locals() | 1011 - flow_graph().num_stack_locals() |
1010 - flow_graph().num_copied_params(); | 1012 - flow_graph().num_copied_params(); |
1011 ASSERT(extra_slots >= 0); | 1013 ASSERT(extra_slots >= 0); |
1012 __ EnterOsrFrame(extra_slots * kWordSize, new_pp, new_pc); | 1014 __ EnterOsrFrame(extra_slots * kWordSize, new_pp, new_pc); |
1013 } else { | 1015 } else { |
1014 if (CanOptimizeFunction() && | 1016 if (CanOptimizeFunction() && |
1015 function.IsOptimizable() && | 1017 function.IsOptimizable() && |
1016 (!is_optimizing() || may_reoptimize())) { | 1018 (!is_optimizing() || may_reoptimize())) { |
1017 const Register function_reg = RDI; | 1019 const Register function_reg = RDI; |
1018 // Load function object using the callee's pool pointer. | 1020 // Load function object using the callee's pool pointer. |
1019 __ LoadObject(function_reg, function, new_pp); | 1021 __ LoadFunctionFromNewPool(function_reg, function, new_pp); |
1020 | 1022 |
1021 // Patch point is after the eventually inlined function object. | 1023 // Patch point is after the eventually inlined function object. |
1022 entry_patch_pc_offset_ = assembler()->CodeSize(); | 1024 entry_patch_pc_offset_ = assembler()->CodeSize(); |
1023 | 1025 |
1024 // Reoptimization of an optimized function is triggered by counting in | 1026 // Reoptimization of an optimized function is triggered by counting in |
1025 // IC stubs, but not at the entry of the function. | 1027 // IC stubs, but not at the entry of the function. |
1026 if (!is_optimizing()) { | 1028 if (!is_optimizing()) { |
1027 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); | 1029 __ incl(FieldAddress(function_reg, Function::usage_counter_offset())); |
1028 } | 1030 } |
1029 __ cmpl( | 1031 __ cmpl( |
(...skipping 12 matching lines...) Expand all Loading... | |
1042 } | 1044 } |
1043 } | 1045 } |
1044 | 1046 |
1045 | 1047 |
1046 void FlowGraphCompiler::CompileGraph() { | 1048 void FlowGraphCompiler::CompileGraph() { |
1047 InitCompiler(); | 1049 InitCompiler(); |
1048 | 1050 |
1049 TryIntrinsify(); | 1051 TryIntrinsify(); |
1050 | 1052 |
1051 EmitFrameEntry(); | 1053 EmitFrameEntry(); |
1054 ASSERT(assembler()->constant_pool_allowed()); | |
1052 | 1055 |
1053 const Function& function = parsed_function().function(); | 1056 const Function& function = parsed_function().function(); |
1054 | 1057 |
1055 const int num_fixed_params = function.num_fixed_parameters(); | 1058 const int num_fixed_params = function.num_fixed_parameters(); |
1056 const int num_copied_params = parsed_function().num_copied_params(); | 1059 const int num_copied_params = parsed_function().num_copied_params(); |
1057 const int num_locals = parsed_function().num_stack_locals(); | 1060 const int num_locals = parsed_function().num_stack_locals(); |
1058 | 1061 |
1059 // We check the number of passed arguments when we have to copy them due to | 1062 // We check the number of passed arguments when we have to copy them due to |
1060 // the presence of optional parameters. | 1063 // the presence of optional parameters. |
1061 // No such checking code is generated if only fixed parameters are declared, | 1064 // No such checking code is generated if only fixed parameters are declared, |
1062 // unless we are in debug mode or unless we are compiling a closure. | 1065 // unless we are in debug mode or unless we are compiling a closure. |
1063 if (num_copied_params == 0) { | 1066 if (num_copied_params == 0) { |
1064 #ifdef DEBUG | 1067 #ifdef DEBUG |
1065 ASSERT(!parsed_function().function().HasOptionalParameters()); | 1068 ASSERT(!parsed_function().function().HasOptionalParameters()); |
1066 const bool check_arguments = !flow_graph().IsCompiledForOsr(); | 1069 const bool check_arguments = !flow_graph().IsCompiledForOsr(); |
1067 #else | 1070 #else |
1068 const bool check_arguments = | 1071 const bool check_arguments = |
1069 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | 1072 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); |
1070 #endif | 1073 #endif |
1071 if (check_arguments) { | 1074 if (check_arguments) { |
1072 __ Comment("Check argument count"); | 1075 __ Comment("Check argument count"); |
1073 // Check that exactly num_fixed arguments are passed in. | 1076 // Check that exactly num_fixed arguments are passed in. |
1074 Label correct_num_arguments, wrong_num_arguments; | 1077 Label correct_num_arguments, wrong_num_arguments; |
1075 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1078 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
1076 __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params)), PP); | 1079 __ CompareImmediate(RAX, Immediate(Smi::RawValue(num_fixed_params))); |
1077 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); | 1080 __ j(NOT_EQUAL, &wrong_num_arguments, Assembler::kNearJump); |
1078 __ cmpq(RAX, | 1081 __ cmpq(RAX, |
1079 FieldAddress(R10, | 1082 FieldAddress(R10, |
1080 ArgumentsDescriptor::positional_count_offset())); | 1083 ArgumentsDescriptor::positional_count_offset())); |
1081 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); | 1084 __ j(EQUAL, &correct_num_arguments, Assembler::kNearJump); |
1082 | 1085 |
1083 __ Bind(&wrong_num_arguments); | 1086 __ Bind(&wrong_num_arguments); |
1084 if (function.IsClosureFunction()) { | 1087 if (function.IsClosureFunction()) { |
1088 ASSERT(assembler()->constant_pool_allowed()); | |
1085 __ LeaveDartFrame(); // The arguments are still on the stack. | 1089 __ LeaveDartFrame(); // The arguments are still on the stack. |
1090 ASSERT(!assembler()->constant_pool_allowed()); | |
1086 __ jmp(&StubCode::CallClosureNoSuchMethodLabel()); | 1091 __ jmp(&StubCode::CallClosureNoSuchMethodLabel()); |
1092 __ set_constant_pool_allowed(true); | |
1087 // The noSuchMethod call may return to the caller, but not here. | 1093 // The noSuchMethod call may return to the caller, but not here. |
1088 } else { | 1094 } else { |
1089 __ Stop("Wrong number of arguments"); | 1095 __ Stop("Wrong number of arguments"); |
1090 } | 1096 } |
1091 __ Bind(&correct_num_arguments); | 1097 __ Bind(&correct_num_arguments); |
1092 } | 1098 } |
1093 } else if (!flow_graph().IsCompiledForOsr()) { | 1099 } else if (!flow_graph().IsCompiledForOsr()) { |
1094 CopyParameters(); | 1100 CopyParameters(); |
1095 } | 1101 } |
1096 | 1102 |
(...skipping 15 matching lines...) Expand all Loading... | |
1112 | 1118 |
1113 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1119 // In unoptimized code, initialize (non-argument) stack allocated slots to |
1114 // null. | 1120 // null. |
1115 if (!is_optimizing()) { | 1121 if (!is_optimizing()) { |
1116 ASSERT(num_locals > 0); // There is always at least context_var. | 1122 ASSERT(num_locals > 0); // There is always at least context_var. |
1117 __ Comment("Initialize spill slots"); | 1123 __ Comment("Initialize spill slots"); |
1118 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1124 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
1119 const intptr_t context_index = | 1125 const intptr_t context_index = |
1120 parsed_function().current_context_var()->index(); | 1126 parsed_function().current_context_var()->index(); |
1121 if (num_locals > 1) { | 1127 if (num_locals > 1) { |
1122 __ LoadObject(RAX, Object::null_object(), PP); | 1128 __ LoadObject(RAX, Object::null_object()); |
1123 } | 1129 } |
1124 for (intptr_t i = 0; i < num_locals; ++i) { | 1130 for (intptr_t i = 0; i < num_locals; ++i) { |
1125 // Subtract index i (locals lie at lower addresses than RBP). | 1131 // Subtract index i (locals lie at lower addresses than RBP). |
1126 if (((slot_base - i) == context_index)) { | 1132 if (((slot_base - i) == context_index)) { |
1127 if (function.IsClosureFunction()) { | 1133 if (function.IsClosureFunction()) { |
1128 __ movq(Address(RBP, (slot_base - i) * kWordSize), CTX); | 1134 __ movq(Address(RBP, (slot_base - i) * kWordSize), CTX); |
1129 } else { | 1135 } else { |
1130 const Context& empty_context = Context::ZoneHandle( | 1136 const Context& empty_context = Context::ZoneHandle( |
1131 zone(), isolate()->object_store()->empty_context()); | 1137 zone(), isolate()->object_store()->empty_context()); |
1132 __ StoreObject( | 1138 __ StoreObject( |
1133 Address(RBP, (slot_base - i) * kWordSize), empty_context, PP); | 1139 Address(RBP, (slot_base - i) * kWordSize), empty_context); |
1134 } | 1140 } |
1135 } else { | 1141 } else { |
1136 ASSERT(num_locals > 1); | 1142 ASSERT(num_locals > 1); |
1137 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); | 1143 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); |
1138 } | 1144 } |
1139 } | 1145 } |
1140 } | 1146 } |
1141 | 1147 |
1142 ASSERT(!block_order().is_empty()); | 1148 ASSERT(!block_order().is_empty()); |
1143 VisitBlocks(); | 1149 VisitBlocks(); |
1144 | 1150 |
1145 __ int3(); | 1151 __ int3(); |
1152 ASSERT(assembler()->constant_pool_allowed()); | |
1146 GenerateDeferredCode(); | 1153 GenerateDeferredCode(); |
1147 // Emit function patching code. This will be swapped with the first 13 bytes | 1154 // Emit function patching code. This will be swapped with the first 13 bytes |
1148 // at entry point. | 1155 // at entry point. |
1149 patch_code_pc_offset_ = assembler()->CodeSize(); | 1156 patch_code_pc_offset_ = assembler()->CodeSize(); |
1150 // This is patched up to a point in FrameEntry where the PP for the | 1157 // This is patched up to a point in FrameEntry where the PP for the |
1151 // current function is in R13 instead of PP. | 1158 // current function is in R13 instead of PP. |
1152 __ JmpPatchable(&StubCode::FixCallersTargetLabel(), R13); | 1159 __ JmpPatchable(&StubCode::FixCallersTargetLabel(), R13); |
1153 | 1160 |
1154 if (is_optimizing()) { | 1161 if (is_optimizing()) { |
1155 lazy_deopt_pc_offset_ = assembler()->CodeSize(); | 1162 lazy_deopt_pc_offset_ = assembler()->CodeSize(); |
1156 __ Jmp(&StubCode::DeoptimizeLazyLabel(), PP); | 1163 __ Jmp(&StubCode::DeoptimizeLazyLabel(), PP); |
1157 } | 1164 } |
1158 } | 1165 } |
1159 | 1166 |
1160 | 1167 |
1161 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1168 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
1162 const ExternalLabel* label, | 1169 const ExternalLabel* label, |
1163 RawPcDescriptors::Kind kind, | 1170 RawPcDescriptors::Kind kind, |
1164 LocationSummary* locs) { | 1171 LocationSummary* locs) { |
1165 __ Call(label, PP); | 1172 __ Call(label); |
1166 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); | 1173 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); |
1167 RecordSafepoint(locs); | 1174 RecordSafepoint(locs); |
1168 } | 1175 } |
1169 | 1176 |
1170 | 1177 |
1171 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 1178 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
1172 intptr_t token_pos, | 1179 intptr_t token_pos, |
1173 const ExternalLabel* label, | 1180 const ExternalLabel* label, |
1174 RawPcDescriptors::Kind kind, | 1181 RawPcDescriptors::Kind kind, |
1175 LocationSummary* locs) { | 1182 LocationSummary* locs) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1214 | 1221 |
1215 void FlowGraphCompiler::EmitUnoptimizedStaticCall( | 1222 void FlowGraphCompiler::EmitUnoptimizedStaticCall( |
1216 intptr_t argument_count, | 1223 intptr_t argument_count, |
1217 intptr_t deopt_id, | 1224 intptr_t deopt_id, |
1218 intptr_t token_pos, | 1225 intptr_t token_pos, |
1219 LocationSummary* locs, | 1226 LocationSummary* locs, |
1220 const ICData& ic_data) { | 1227 const ICData& ic_data) { |
1221 const uword label_address = | 1228 const uword label_address = |
1222 StubCode::UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested()); | 1229 StubCode::UnoptimizedStaticCallEntryPoint(ic_data.NumArgsTested()); |
1223 ExternalLabel target_label(label_address); | 1230 ExternalLabel target_label(label_address); |
1224 __ LoadObject(RBX, ic_data, PP); | 1231 __ LoadObject(RBX, ic_data); |
1225 GenerateDartCall(deopt_id, | 1232 GenerateDartCall(deopt_id, |
1226 token_pos, | 1233 token_pos, |
1227 &target_label, | 1234 &target_label, |
1228 RawPcDescriptors::kUnoptStaticCall, | 1235 RawPcDescriptors::kUnoptStaticCall, |
1229 locs); | 1236 locs); |
1230 __ Drop(argument_count, RCX); | 1237 __ Drop(argument_count, RCX); |
1231 } | 1238 } |
1232 | 1239 |
1233 | 1240 |
1234 void FlowGraphCompiler::EmitEdgeCounter() { | 1241 void FlowGraphCompiler::EmitEdgeCounter() { |
1235 // We do not check for overflow when incrementing the edge counter. The | 1242 // We do not check for overflow when incrementing the edge counter. The |
1236 // function should normally be optimized long before the counter can | 1243 // function should normally be optimized long before the counter can |
1237 // overflow; and though we do not reset the counters when we optimize or | 1244 // overflow; and though we do not reset the counters when we optimize or |
1238 // deoptimize, there is a bound on the number of | 1245 // deoptimize, there is a bound on the number of |
1239 // optimization/deoptimization cycles we will attempt. | 1246 // optimization/deoptimization cycles we will attempt. |
1247 ASSERT(assembler_->constant_pool_allowed()); | |
1240 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | 1248 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); |
1241 counter.SetAt(0, Smi::Handle(Smi::New(0))); | 1249 counter.SetAt(0, Smi::Handle(Smi::New(0))); |
1242 __ Comment("Edge counter"); | 1250 __ Comment("Edge counter"); |
1243 __ LoadUniqueObject(RAX, counter, PP); | 1251 __ LoadUniqueObject(RAX, counter); |
1244 intptr_t increment_start = assembler_->CodeSize(); | 1252 intptr_t increment_start = assembler_->CodeSize(); |
1245 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1); | 1253 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1); |
1246 int32_t size = assembler_->CodeSize() - increment_start; | 1254 int32_t size = assembler_->CodeSize() - increment_start; |
1247 if (isolate()->edge_counter_increment_size() == -1) { | 1255 if (isolate()->edge_counter_increment_size() == -1) { |
1248 isolate()->set_edge_counter_increment_size(size); | 1256 isolate()->set_edge_counter_increment_size(size); |
1249 } else { | 1257 } else { |
1250 ASSERT(size == isolate()->edge_counter_increment_size()); | 1258 ASSERT(size == isolate()->edge_counter_increment_size()); |
1251 } | 1259 } |
1252 } | 1260 } |
1253 | 1261 |
(...skipping 12 matching lines...) Expand all Loading... | |
1266 intptr_t deopt_id, | 1274 intptr_t deopt_id, |
1267 intptr_t token_pos, | 1275 intptr_t token_pos, |
1268 LocationSummary* locs) { | 1276 LocationSummary* locs) { |
1269 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1277 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1270 // Each ICData propagated from unoptimized to optimized code contains the | 1278 // Each ICData propagated from unoptimized to optimized code contains the |
1271 // function that corresponds to the Dart function of that IC call. Due | 1279 // function that corresponds to the Dart function of that IC call. Due |
1272 // to inlining in optimized code, that function may not correspond to the | 1280 // to inlining in optimized code, that function may not correspond to the |
1273 // top-level function (parsed_function().function()) which could be | 1281 // top-level function (parsed_function().function()) which could be |
1274 // reoptimized and which counter needs to be incremented. | 1282 // reoptimized and which counter needs to be incremented. |
1275 // Pass the function explicitly, it is used in IC stub. | 1283 // Pass the function explicitly, it is used in IC stub. |
1276 __ LoadObject(RDI, parsed_function().function(), PP); | 1284 __ LoadObject(RDI, parsed_function().function()); |
1277 __ LoadUniqueObject(RBX, ic_data, PP); | 1285 __ LoadUniqueObject(RBX, ic_data); |
1278 GenerateDartCall(deopt_id, | 1286 GenerateDartCall(deopt_id, |
1279 token_pos, | 1287 token_pos, |
1280 target_label, | 1288 target_label, |
1281 RawPcDescriptors::kIcCall, | 1289 RawPcDescriptors::kIcCall, |
1282 locs); | 1290 locs); |
1283 __ Drop(argument_count, RCX); | 1291 __ Drop(argument_count, RCX); |
1284 } | 1292 } |
1285 | 1293 |
1286 | 1294 |
1287 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1295 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
1288 const ICData& ic_data, | 1296 const ICData& ic_data, |
1289 intptr_t argument_count, | 1297 intptr_t argument_count, |
1290 intptr_t deopt_id, | 1298 intptr_t deopt_id, |
1291 intptr_t token_pos, | 1299 intptr_t token_pos, |
1292 LocationSummary* locs) { | 1300 LocationSummary* locs) { |
1293 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); | 1301 ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0); |
1294 __ LoadUniqueObject(RBX, ic_data, PP); | 1302 __ LoadUniqueObject(RBX, ic_data); |
1295 GenerateDartCall(deopt_id, | 1303 GenerateDartCall(deopt_id, |
1296 token_pos, | 1304 token_pos, |
1297 target_label, | 1305 target_label, |
1298 RawPcDescriptors::kIcCall, | 1306 RawPcDescriptors::kIcCall, |
1299 locs); | 1307 locs); |
1300 __ Drop(argument_count, RCX); | 1308 __ Drop(argument_count, RCX); |
1301 } | 1309 } |
1302 | 1310 |
1303 | 1311 |
1304 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1312 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
1305 const ICData& ic_data, | 1313 const ICData& ic_data, |
1306 intptr_t argument_count, | 1314 intptr_t argument_count, |
1307 intptr_t deopt_id, | 1315 intptr_t deopt_id, |
1308 intptr_t token_pos, | 1316 intptr_t token_pos, |
1309 LocationSummary* locs) { | 1317 LocationSummary* locs) { |
1310 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); | 1318 MegamorphicCacheTable* table = isolate()->megamorphic_cache_table(); |
1311 const String& name = String::Handle(ic_data.target_name()); | 1319 const String& name = String::Handle(ic_data.target_name()); |
1312 const Array& arguments_descriptor = | 1320 const Array& arguments_descriptor = |
1313 Array::ZoneHandle(ic_data.arguments_descriptor()); | 1321 Array::ZoneHandle(ic_data.arguments_descriptor()); |
1314 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); | 1322 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); |
1315 const MegamorphicCache& cache = | 1323 const MegamorphicCache& cache = |
1316 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); | 1324 MegamorphicCache::ZoneHandle(table->Lookup(name, arguments_descriptor)); |
1317 const Register receiverR = RDI; | 1325 const Register receiverR = RDI; |
1318 const Register cacheR = RBX; | 1326 const Register cacheR = RBX; |
1319 const Register targetR = RCX; | 1327 const Register targetR = RCX; |
1320 __ movq(receiverR, Address(RSP, (argument_count - 1) * kWordSize)); | 1328 __ movq(receiverR, Address(RSP, (argument_count - 1) * kWordSize)); |
1321 __ LoadObject(cacheR, cache, PP); | 1329 __ LoadObject(cacheR, cache); |
1322 | 1330 |
1323 if (FLAG_use_megamorphic_stub) { | 1331 if (FLAG_use_megamorphic_stub) { |
1324 __ call(&StubCode::MegamorphicLookupLabel()); | 1332 __ call(&StubCode::MegamorphicLookupLabel()); |
1325 } else { | 1333 } else { |
1326 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); | 1334 StubCode::EmitMegamorphicLookup(assembler(), receiverR, cacheR, targetR); |
1327 } | 1335 } |
1328 __ LoadObject(RBX, ic_data, PP); | 1336 __ LoadObject(RBX, ic_data); |
1329 __ LoadObject(R10, arguments_descriptor, PP); | 1337 __ LoadObject(R10, arguments_descriptor); |
1330 __ call(targetR); | 1338 __ call(targetR); |
1331 AddCurrentDescriptor(RawPcDescriptors::kOther, | 1339 AddCurrentDescriptor(RawPcDescriptors::kOther, |
1332 Isolate::kNoDeoptId, token_pos); | 1340 Isolate::kNoDeoptId, token_pos); |
1333 RecordSafepoint(locs); | 1341 RecordSafepoint(locs); |
1334 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | 1342 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); |
1335 if (is_optimizing()) { | 1343 if (is_optimizing()) { |
1336 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 1344 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
1337 } else { | 1345 } else { |
1338 // Add deoptimization continuation point after the call and before the | 1346 // Add deoptimization continuation point after the call and before the |
1339 // arguments are removed. | 1347 // arguments are removed. |
1340 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 1348 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); |
1341 } | 1349 } |
1342 __ Drop(argument_count, RCX); | 1350 __ Drop(argument_count, RCX); |
1343 } | 1351 } |
1344 | 1352 |
1345 | 1353 |
1346 void FlowGraphCompiler::EmitOptimizedStaticCall( | 1354 void FlowGraphCompiler::EmitOptimizedStaticCall( |
1347 const Function& function, | 1355 const Function& function, |
1348 const Array& arguments_descriptor, | 1356 const Array& arguments_descriptor, |
1349 intptr_t argument_count, | 1357 intptr_t argument_count, |
1350 intptr_t deopt_id, | 1358 intptr_t deopt_id, |
1351 intptr_t token_pos, | 1359 intptr_t token_pos, |
1352 LocationSummary* locs) { | 1360 LocationSummary* locs) { |
1353 __ LoadObject(R10, arguments_descriptor, PP); | 1361 __ LoadObject(R10, arguments_descriptor); |
1354 // Do not use the code from the function, but let the code be patched so that | 1362 // Do not use the code from the function, but let the code be patched so that |
1355 // we can record the outgoing edges to other code. | 1363 // we can record the outgoing edges to other code. |
1356 GenerateDartCall(deopt_id, | 1364 GenerateDartCall(deopt_id, |
1357 token_pos, | 1365 token_pos, |
1358 &StubCode::CallStaticFunctionLabel(), | 1366 &StubCode::CallStaticFunctionLabel(), |
1359 RawPcDescriptors::kOther, | 1367 RawPcDescriptors::kOther, |
1360 locs); | 1368 locs); |
1361 AddStaticCallTarget(function); | 1369 AddStaticCallTarget(function); |
1362 __ Drop(argument_count, RCX); | 1370 __ Drop(argument_count, RCX); |
1363 } | 1371 } |
1364 | 1372 |
1365 | 1373 |
1366 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( | 1374 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( |
1367 Register reg, | 1375 Register reg, |
1368 const Object& obj, | 1376 const Object& obj, |
1369 bool needs_number_check, | 1377 bool needs_number_check, |
1370 intptr_t token_pos) { | 1378 intptr_t token_pos) { |
1371 ASSERT(!needs_number_check || | 1379 ASSERT(!needs_number_check || |
1372 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); | 1380 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); |
1373 | 1381 |
1374 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { | 1382 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { |
1375 ASSERT(!needs_number_check); | 1383 ASSERT(!needs_number_check); |
1376 __ testq(reg, reg); | 1384 __ testq(reg, reg); |
1377 return EQUAL; | 1385 return EQUAL; |
1378 } | 1386 } |
1379 | 1387 |
1380 if (needs_number_check) { | 1388 if (needs_number_check) { |
1381 __ pushq(reg); | 1389 __ pushq(reg); |
1382 __ PushObject(obj, PP); | 1390 __ PushObject(obj); |
1383 if (is_optimizing()) { | 1391 if (is_optimizing()) { |
1384 __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); | 1392 __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel()); |
1385 } else { | 1393 } else { |
1386 __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); | 1394 __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel()); |
1387 } | 1395 } |
1388 if (token_pos != Scanner::kNoSourcePos) { | 1396 if (token_pos != Scanner::kNoSourcePos) { |
1389 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, | 1397 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, |
1390 Isolate::kNoDeoptId, | 1398 Isolate::kNoDeoptId, |
1391 token_pos); | 1399 token_pos); |
1392 } | 1400 } |
1393 // Stub returns result in flags (result of a cmpq, we need ZF computed). | 1401 // Stub returns result in flags (result of a cmpq, we need ZF computed). |
1394 __ popq(reg); // Discard constant. | 1402 __ popq(reg); // Discard constant. |
1395 __ popq(reg); // Restore 'reg'. | 1403 __ popq(reg); // Restore 'reg'. |
1396 } else { | 1404 } else { |
1397 __ CompareObject(reg, obj, PP); | 1405 __ CompareObject(reg, obj); |
1398 } | 1406 } |
1399 return EQUAL; | 1407 return EQUAL; |
1400 } | 1408 } |
1401 | 1409 |
1402 | 1410 |
1403 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1411 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
1404 Register right, | 1412 Register right, |
1405 bool needs_number_check, | 1413 bool needs_number_check, |
1406 intptr_t token_pos) { | 1414 intptr_t token_pos) { |
1407 if (needs_number_check) { | 1415 if (needs_number_check) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1472 LocationSummary* locs) { | 1480 LocationSummary* locs) { |
1473 ASSERT(is_optimizing()); | 1481 ASSERT(is_optimizing()); |
1474 | 1482 |
1475 __ Comment("EmitTestAndCall"); | 1483 __ Comment("EmitTestAndCall"); |
1476 const Array& arguments_descriptor = | 1484 const Array& arguments_descriptor = |
1477 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1485 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
1478 argument_names)); | 1486 argument_names)); |
1479 // Load receiver into RAX. | 1487 // Load receiver into RAX. |
1480 __ movq(RAX, | 1488 __ movq(RAX, |
1481 Address(RSP, (argument_count - 1) * kWordSize)); | 1489 Address(RSP, (argument_count - 1) * kWordSize)); |
1482 __ LoadObject(R10, arguments_descriptor, PP); | 1490 __ LoadObject(R10, arguments_descriptor); |
1483 | 1491 |
1484 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; | 1492 const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid; |
1485 const intptr_t kNumChecks = ic_data.NumberOfChecks(); | 1493 const intptr_t kNumChecks = ic_data.NumberOfChecks(); |
1486 | 1494 |
1487 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); | 1495 ASSERT(!ic_data.IsNull() && (kNumChecks > 0)); |
1488 | 1496 |
1489 Label after_smi_test; | 1497 Label after_smi_test; |
1490 __ testq(RAX, Immediate(kSmiTagMask)); | 1498 __ testq(RAX, Immediate(kSmiTagMask)); |
1491 if (kFirstCheckIsSmi) { | 1499 if (kFirstCheckIsSmi) { |
1492 // Jump if receiver is not Smi. | 1500 // Jump if receiver is not Smi. |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1610 } else { | 1618 } else { |
1611 ASSERT(source.IsConstant()); | 1619 ASSERT(source.IsConstant()); |
1612 const Object& constant = source.constant(); | 1620 const Object& constant = source.constant(); |
1613 if (destination.IsRegister()) { | 1621 if (destination.IsRegister()) { |
1614 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { | 1622 if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { |
1615 __ xorq(destination.reg(), destination.reg()); | 1623 __ xorq(destination.reg(), destination.reg()); |
1616 } else if (constant.IsSmi() && | 1624 } else if (constant.IsSmi() && |
1617 (source.constant_instruction()->representation() == kUnboxedInt32)) { | 1625 (source.constant_instruction()->representation() == kUnboxedInt32)) { |
1618 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); | 1626 __ movl(destination.reg(), Immediate(Smi::Cast(constant).Value())); |
1619 } else { | 1627 } else { |
1620 __ LoadObject(destination.reg(), constant, PP); | 1628 __ LoadObject(destination.reg(), constant); |
1621 } | 1629 } |
1622 } else if (destination.IsFpuRegister()) { | 1630 } else if (destination.IsFpuRegister()) { |
1623 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { | 1631 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { |
1624 __ xorps(destination.fpu_reg(), destination.fpu_reg()); | 1632 __ xorps(destination.fpu_reg(), destination.fpu_reg()); |
1625 } else { | 1633 } else { |
1626 __ LoadObject(TMP, constant, PP); | 1634 __ LoadObject(TMP, constant); |
1627 __ movsd(destination.fpu_reg(), | 1635 __ movsd(destination.fpu_reg(), |
1628 FieldAddress(TMP, Double::value_offset())); | 1636 FieldAddress(TMP, Double::value_offset())); |
1629 } | 1637 } |
1630 } else if (destination.IsDoubleStackSlot()) { | 1638 } else if (destination.IsDoubleStackSlot()) { |
1631 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { | 1639 if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) { |
1632 __ xorps(XMM0, XMM0); | 1640 __ xorps(XMM0, XMM0); |
1633 } else { | 1641 } else { |
1634 __ LoadObject(TMP, constant, PP); | 1642 __ LoadObject(TMP, constant); |
1635 __ movsd(XMM0, FieldAddress(TMP, Double::value_offset())); | 1643 __ movsd(XMM0, FieldAddress(TMP, Double::value_offset())); |
1636 } | 1644 } |
1637 __ movsd(destination.ToStackSlotAddress(), XMM0); | 1645 __ movsd(destination.ToStackSlotAddress(), XMM0); |
1638 } else { | 1646 } else { |
1639 ASSERT(destination.IsStackSlot()); | 1647 ASSERT(destination.IsStackSlot()); |
1640 if (constant.IsSmi() && | 1648 if (constant.IsSmi() && |
1641 (source.constant_instruction()->representation() == kUnboxedInt32)) { | 1649 (source.constant_instruction()->representation() == kUnboxedInt32)) { |
1642 __ movl(destination.ToStackSlotAddress(), | 1650 __ movl(destination.ToStackSlotAddress(), |
1643 Immediate(Smi::Cast(constant).Value())); | 1651 Immediate(Smi::Cast(constant).Value())); |
1644 } else { | 1652 } else { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1729 } | 1737 } |
1730 | 1738 |
1731 | 1739 |
1732 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, | 1740 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, |
1733 const Address& src) { | 1741 const Address& src) { |
1734 __ MoveMemoryToMemory(dst, src); | 1742 __ MoveMemoryToMemory(dst, src); |
1735 } | 1743 } |
1736 | 1744 |
1737 | 1745 |
1738 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { | 1746 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { |
1739 __ StoreObject(dst, obj, PP); | 1747 __ StoreObject(dst, obj); |
1740 } | 1748 } |
1741 | 1749 |
1742 | 1750 |
1743 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { | 1751 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { |
1744 __ Exchange(reg, mem); | 1752 __ Exchange(reg, mem); |
1745 } | 1753 } |
1746 | 1754 |
1747 | 1755 |
1748 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1756 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
1749 __ Exchange(mem1, mem2); | 1757 __ Exchange(mem1, mem2); |
(...skipping 19 matching lines...) Expand all Loading... | |
1769 __ pushq(reg); | 1777 __ pushq(reg); |
1770 } | 1778 } |
1771 | 1779 |
1772 | 1780 |
1773 void ParallelMoveResolver::RestoreScratch(Register reg) { | 1781 void ParallelMoveResolver::RestoreScratch(Register reg) { |
1774 __ popq(reg); | 1782 __ popq(reg); |
1775 } | 1783 } |
1776 | 1784 |
1777 | 1785 |
1778 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { | 1786 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { |
1779 __ AddImmediate(RSP, Immediate(-kFpuRegisterSize), PP); | 1787 __ AddImmediate(RSP, Immediate(-kFpuRegisterSize)); |
1780 __ movups(Address(RSP, 0), reg); | 1788 __ movups(Address(RSP, 0), reg); |
1781 } | 1789 } |
1782 | 1790 |
1783 | 1791 |
1784 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1792 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
1785 __ movups(reg, Address(RSP, 0)); | 1793 __ movups(reg, Address(RSP, 0)); |
1786 __ AddImmediate(RSP, Immediate(kFpuRegisterSize), PP); | 1794 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
1787 } | 1795 } |
1788 | 1796 |
1789 | 1797 |
1790 #undef __ | 1798 #undef __ |
1791 | 1799 |
1792 } // namespace dart | 1800 } // namespace dart |
1793 | 1801 |
1794 #endif // defined TARGET_ARCH_X64 | 1802 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |