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

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

Issue 2974233002: VM: Re-format to use at most one newline between functions (Closed)
Patch Set: Rebase and merge Created 3 years, 5 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
« no previous file with comments | « runtime/vm/flow_graph_compiler_ia32.cc ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 #include "vm/compiler.h" 11 #include "vm/compiler.h"
12 #include "vm/dart_entry.h" 12 #include "vm/dart_entry.h"
13 #include "vm/deopt_instructions.h" 13 #include "vm/deopt_instructions.h"
14 #include "vm/il_printer.h" 14 #include "vm/il_printer.h"
15 #include "vm/instructions.h" 15 #include "vm/instructions.h"
16 #include "vm/locations.h" 16 #include "vm/locations.h"
17 #include "vm/object_store.h" 17 #include "vm/object_store.h"
18 #include "vm/parser.h" 18 #include "vm/parser.h"
19 #include "vm/stack_frame.h" 19 #include "vm/stack_frame.h"
20 #include "vm/stub_code.h" 20 #include "vm/stub_code.h"
21 #include "vm/symbols.h" 21 #include "vm/symbols.h"
22 22
23 namespace dart { 23 namespace dart {
24 24
25 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization."); 25 DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
26 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic."); 26 DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
27 DECLARE_FLAG(bool, enable_simd_inline); 27 DECLARE_FLAG(bool, enable_simd_inline);
28 28
29
30 FlowGraphCompiler::~FlowGraphCompiler() { 29 FlowGraphCompiler::~FlowGraphCompiler() {
31 // BlockInfos are zone-allocated, so their destructors are not called. 30 // BlockInfos are zone-allocated, so their destructors are not called.
32 // Verify the labels explicitly here. 31 // Verify the labels explicitly here.
33 for (int i = 0; i < block_info_.length(); ++i) { 32 for (int i = 0; i < block_info_.length(); ++i) {
34 ASSERT(!block_info_[i]->jump_label()->IsLinked()); 33 ASSERT(!block_info_[i]->jump_label()->IsLinked());
35 ASSERT(!block_info_[i]->jump_label()->HasNear()); 34 ASSERT(!block_info_[i]->jump_label()->HasNear());
36 } 35 }
37 } 36 }
38 37
39
40 bool FlowGraphCompiler::SupportsUnboxedDoubles() { 38 bool FlowGraphCompiler::SupportsUnboxedDoubles() {
41 return true; 39 return true;
42 } 40 }
43 41
44
45 bool FlowGraphCompiler::SupportsUnboxedMints() { 42 bool FlowGraphCompiler::SupportsUnboxedMints() {
46 return FLAG_unbox_mints; 43 return FLAG_unbox_mints;
47 } 44 }
48 45
49
50 bool FlowGraphCompiler::SupportsUnboxedSimd128() { 46 bool FlowGraphCompiler::SupportsUnboxedSimd128() {
51 return FLAG_enable_simd_inline; 47 return FLAG_enable_simd_inline;
52 } 48 }
53 49
54
55 bool FlowGraphCompiler::SupportsHardwareDivision() { 50 bool FlowGraphCompiler::SupportsHardwareDivision() {
56 return true; 51 return true;
57 } 52 }
58 53
59
60 bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() { 54 bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
61 return false; 55 return false;
62 } 56 }
63 57
64
65 void FlowGraphCompiler::EnterIntrinsicMode() { 58 void FlowGraphCompiler::EnterIntrinsicMode() {
66 ASSERT(!intrinsic_mode()); 59 ASSERT(!intrinsic_mode());
67 intrinsic_mode_ = true; 60 intrinsic_mode_ = true;
68 ASSERT(!assembler()->constant_pool_allowed()); 61 ASSERT(!assembler()->constant_pool_allowed());
69 } 62 }
70 63
71
72 void FlowGraphCompiler::ExitIntrinsicMode() { 64 void FlowGraphCompiler::ExitIntrinsicMode() {
73 ASSERT(intrinsic_mode()); 65 ASSERT(intrinsic_mode());
74 intrinsic_mode_ = false; 66 intrinsic_mode_ = false;
75 } 67 }
76 68
77
78 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, 69 RawTypedData* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
79 DeoptInfoBuilder* builder, 70 DeoptInfoBuilder* builder,
80 const Array& deopt_table) { 71 const Array& deopt_table) {
81 if (deopt_env_ == NULL) { 72 if (deopt_env_ == NULL) {
82 ++builder->current_info_number_; 73 ++builder->current_info_number_;
83 return TypedData::null(); 74 return TypedData::null();
84 } 75 }
85 76
86 intptr_t stack_height = compiler->StackSize(); 77 intptr_t stack_height = compiler->StackSize();
87 AllocateIncomingParametersRecursive(deopt_env_, &stack_height); 78 AllocateIncomingParametersRecursive(deopt_env_, &stack_height);
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 builder->AddCallerPc(slot_ix++); 145 builder->AddCallerPc(slot_ix++);
155 146
156 // For the outermost environment, set the incoming arguments. 147 // For the outermost environment, set the incoming arguments.
157 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { 148 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) {
158 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); 149 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++);
159 } 150 }
160 151
161 return builder->CreateDeoptInfo(deopt_table); 152 return builder->CreateDeoptInfo(deopt_table);
162 } 153 }
163 154
164
165 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, 155 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
166 intptr_t stub_ix) { 156 intptr_t stub_ix) {
167 // Calls do not need stubs, they share a deoptimization trampoline. 157 // Calls do not need stubs, they share a deoptimization trampoline.
168 ASSERT(reason() != ICData::kDeoptAtCall); 158 ASSERT(reason() != ICData::kDeoptAtCall);
169 Assembler* assembler = compiler->assembler(); 159 Assembler* assembler = compiler->assembler();
170 #define __ assembler-> 160 #define __ assembler->
171 __ Comment("%s", Name()); 161 __ Comment("%s", Name());
172 __ Bind(entry_label()); 162 __ Bind(entry_label());
173 if (FLAG_trap_on_deoptimization) { 163 if (FLAG_trap_on_deoptimization) {
174 __ int3(); 164 __ int3();
175 } 165 }
176 166
177 ASSERT(deopt_env() != NULL); 167 ASSERT(deopt_env() != NULL);
178 168
179 __ pushq(CODE_REG); 169 __ pushq(CODE_REG);
180 __ Call(*StubCode::Deoptimize_entry()); 170 __ Call(*StubCode::Deoptimize_entry());
181 set_pc_offset(assembler->CodeSize()); 171 set_pc_offset(assembler->CodeSize());
182 __ int3(); 172 __ int3();
183 #undef __ 173 #undef __
184 } 174 }
185 175
186
187 #define __ assembler()-> 176 #define __ assembler()->
188 177
189
190 // Fall through if bool_register contains null. 178 // Fall through if bool_register contains null.
191 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, 179 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
192 Label* is_true, 180 Label* is_true,
193 Label* is_false) { 181 Label* is_false) {
194 Label fall_through; 182 Label fall_through;
195 __ CompareObject(bool_register, Object::null_object()); 183 __ CompareObject(bool_register, Object::null_object());
196 __ j(EQUAL, &fall_through, Assembler::kNearJump); 184 __ j(EQUAL, &fall_through, Assembler::kNearJump);
197 __ CompareObject(bool_register, Bool::True()); 185 __ CompareObject(bool_register, Bool::True());
198 __ j(EQUAL, is_true); 186 __ j(EQUAL, is_true);
199 __ jmp(is_false); 187 __ jmp(is_false);
200 __ Bind(&fall_through); 188 __ Bind(&fall_through);
201 } 189 }
202 190
203
204 // Clobbers RCX. 191 // Clobbers RCX.
205 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( 192 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
206 TypeTestStubKind test_kind, 193 TypeTestStubKind test_kind,
207 Register instance_reg, 194 Register instance_reg,
208 Register instantiator_type_arguments_reg, 195 Register instantiator_type_arguments_reg,
209 Register function_type_arguments_reg, 196 Register function_type_arguments_reg,
210 Register temp_reg, 197 Register temp_reg,
211 Label* is_instance_lbl, 198 Label* is_instance_lbl,
212 Label* is_not_instance_lbl) { 199 Label* is_not_instance_lbl) {
213 const SubtypeTestCache& type_test_cache = 200 const SubtypeTestCache& type_test_cache =
(...skipping 23 matching lines...) Expand all
237 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. 224 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
238 ASSERT(instance_reg != RCX); 225 ASSERT(instance_reg != RCX);
239 ASSERT(temp_reg != RCX); 226 ASSERT(temp_reg != RCX);
240 __ Drop(2); 227 __ Drop(2);
241 __ popq(instance_reg); // Restore receiver. 228 __ popq(instance_reg); // Restore receiver.
242 __ popq(temp_reg); // Discard. 229 __ popq(temp_reg); // Discard.
243 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); 230 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl);
244 return type_test_cache.raw(); 231 return type_test_cache.raw();
245 } 232 }
246 233
247
248 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 234 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
249 // type test is conclusive, otherwise fallthrough if a type test could not 235 // type test is conclusive, otherwise fallthrough if a type test could not
250 // be completed. 236 // be completed.
251 // RAX: instance (must survive). 237 // RAX: instance (must survive).
252 // Clobbers R10. 238 // Clobbers R10.
253 RawSubtypeTestCache* 239 RawSubtypeTestCache*
254 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 240 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
255 TokenPosition token_pos, 241 TokenPosition token_pos,
256 const AbstractType& type, 242 const AbstractType& type,
257 Label* is_instance_lbl, 243 Label* is_instance_lbl,
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 // Regular subtype test cache involving instance's type arguments. 301 // Regular subtype test cache involving instance's type arguments.
316 const Register kInstantiatorTypeArgumentsReg = kNoRegister; 302 const Register kInstantiatorTypeArgumentsReg = kNoRegister;
317 const Register kFunctionTypeArgumentsReg = kNoRegister; 303 const Register kFunctionTypeArgumentsReg = kNoRegister;
318 const Register kTempReg = R10; 304 const Register kTempReg = R10;
319 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, 305 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg,
320 kInstantiatorTypeArgumentsReg, 306 kInstantiatorTypeArgumentsReg,
321 kFunctionTypeArgumentsReg, kTempReg, 307 kFunctionTypeArgumentsReg, kTempReg,
322 is_instance_lbl, is_not_instance_lbl); 308 is_instance_lbl, is_not_instance_lbl);
323 } 309 }
324 310
325
326 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, 311 void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
327 const GrowableArray<intptr_t>& class_ids, 312 const GrowableArray<intptr_t>& class_ids,
328 Label* is_equal_lbl, 313 Label* is_equal_lbl,
329 Label* is_not_equal_lbl) { 314 Label* is_not_equal_lbl) {
330 for (intptr_t i = 0; i < class_ids.length(); i++) { 315 for (intptr_t i = 0; i < class_ids.length(); i++) {
331 __ cmpl(class_id_reg, Immediate(class_ids[i])); 316 __ cmpl(class_id_reg, Immediate(class_ids[i]));
332 __ j(EQUAL, is_equal_lbl); 317 __ j(EQUAL, is_equal_lbl);
333 } 318 }
334 __ jmp(is_not_equal_lbl); 319 __ jmp(is_not_equal_lbl);
335 } 320 }
336 321
337
338 // Testing against an instantiated type with no arguments, without 322 // Testing against an instantiated type with no arguments, without
339 // SubtypeTestCache. 323 // SubtypeTestCache.
340 // RAX: instance to test against (preserved). 324 // RAX: instance to test against (preserved).
341 // Clobbers R10, R13. 325 // Clobbers R10, R13.
342 // Returns true if there is a fallthrough. 326 // Returns true if there is a fallthrough.
343 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 327 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
344 TokenPosition token_pos, 328 TokenPosition token_pos,
345 const AbstractType& type, 329 const AbstractType& type,
346 Label* is_instance_lbl, 330 Label* is_instance_lbl,
347 Label* is_not_instance_lbl) { 331 Label* is_not_instance_lbl) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 } 379 }
396 // Compare if the classes are equal. 380 // Compare if the classes are equal.
397 if (!type_class.is_abstract()) { 381 if (!type_class.is_abstract()) {
398 __ cmpl(kClassIdReg, Immediate(type_class.id())); 382 __ cmpl(kClassIdReg, Immediate(type_class.id()));
399 __ j(EQUAL, is_instance_lbl); 383 __ j(EQUAL, is_instance_lbl);
400 } 384 }
401 // Otherwise fallthrough. 385 // Otherwise fallthrough.
402 return true; 386 return true;
403 } 387 }
404 388
405
406 // Uses SubtypeTestCache to store instance class and result. 389 // Uses SubtypeTestCache to store instance class and result.
407 // RAX: instance to test. 390 // RAX: instance to test.
408 // Clobbers R10, R13. 391 // Clobbers R10, R13.
409 // Immediate class test already done. 392 // Immediate class test already done.
410 // TODO(srdjan): Implement a quicker subtype check, as type test 393 // TODO(srdjan): Implement a quicker subtype check, as type test
411 // arrays can grow too high, but they may be useful when optimizing 394 // arrays can grow too high, but they may be useful when optimizing
412 // code (type-feedback). 395 // code (type-feedback).
413 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 396 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
414 TokenPosition token_pos, 397 TokenPosition token_pos,
415 const Class& type_class, 398 const Class& type_class,
(...skipping 11 matching lines...) Expand all
427 410
428 const Register kInstantiatorTypeArgumentsReg = kNoRegister; 411 const Register kInstantiatorTypeArgumentsReg = kNoRegister;
429 const Register kFunctionTypeArgumentsReg = kNoRegister; 412 const Register kFunctionTypeArgumentsReg = kNoRegister;
430 const Register kTempReg = R10; 413 const Register kTempReg = R10;
431 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, 414 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg,
432 kInstantiatorTypeArgumentsReg, 415 kInstantiatorTypeArgumentsReg,
433 kFunctionTypeArgumentsReg, kTempReg, 416 kFunctionTypeArgumentsReg, kTempReg,
434 is_instance_lbl, is_not_instance_lbl); 417 is_instance_lbl, is_not_instance_lbl);
435 } 418 }
436 419
437
438 // Generates inlined check if 'type' is a type parameter or type itself 420 // Generates inlined check if 'type' is a type parameter or type itself
439 // RAX: instance (preserved). 421 // RAX: instance (preserved).
440 // Clobbers RDI, RDX, R10. 422 // Clobbers RDI, RDX, R10.
441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 423 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
442 TokenPosition token_pos, 424 TokenPosition token_pos,
443 const AbstractType& type, 425 const AbstractType& type,
444 Label* is_instance_lbl, 426 Label* is_instance_lbl,
445 Label* is_not_instance_lbl) { 427 Label* is_not_instance_lbl) {
446 __ Comment("UninstantiatedTypeTest"); 428 __ Comment("UninstantiatedTypeTest");
447 ASSERT(!type.IsInstantiated()); 429 ASSERT(!type.IsInstantiated());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // arguments are determined at runtime by the instantiator(s). 490 // arguments are determined at runtime by the instantiator(s).
509 const Register kTempReg = R10; 491 const Register kTempReg = R10;
510 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, 492 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg,
511 kInstantiatorTypeArgumentsReg, 493 kInstantiatorTypeArgumentsReg,
512 kFunctionTypeArgumentsReg, kTempReg, 494 kFunctionTypeArgumentsReg, kTempReg,
513 is_instance_lbl, is_not_instance_lbl); 495 is_instance_lbl, is_not_instance_lbl);
514 } 496 }
515 return SubtypeTestCache::null(); 497 return SubtypeTestCache::null();
516 } 498 }
517 499
518
519 // Inputs: 500 // Inputs:
520 // - RAX: instance to test against (preserved). 501 // - RAX: instance to test against (preserved).
521 // - RDX: optional instantiator type arguments (preserved). 502 // - RDX: optional instantiator type arguments (preserved).
522 // - RCX: optional function type arguments (preserved). 503 // - RCX: optional function type arguments (preserved).
523 // Clobbers R10, R13. 504 // Clobbers R10, R13.
524 // Returns: 505 // Returns:
525 // - preserved instance in RAX, optional instantiator type arguments in RDX, and 506 // - preserved instance in RAX, optional instantiator type arguments in RDX, and
526 // optional function type arguments in RCX. 507 // optional function type arguments in RCX.
527 // Note that this inlined code must be followed by the runtime_call code, as it 508 // Note that this inlined code must be followed by the runtime_call code, as it
528 // may fall through to it. Otherwise, this inline code will jump to the label 509 // may fall through to it. Otherwise, this inline code will jump to the label
(...skipping 22 matching lines...) Expand all
551 return GenerateSubtype1TestCacheLookup( 532 return GenerateSubtype1TestCacheLookup(
552 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 533 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
553 } else { 534 } else {
554 return SubtypeTestCache::null(); 535 return SubtypeTestCache::null();
555 } 536 }
556 } 537 }
557 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl, 538 return GenerateUninstantiatedTypeTest(token_pos, type, is_instance_lbl,
558 is_not_instance_lbl); 539 is_not_instance_lbl);
559 } 540 }
560 541
561
562 // If instanceof type test cannot be performed successfully at compile time and 542 // If instanceof type test cannot be performed successfully at compile time and
563 // therefore eliminated, optimize it by adding inlined tests for: 543 // therefore eliminated, optimize it by adding inlined tests for:
564 // - NULL -> return type == Null (type is not Object or dynamic). 544 // - NULL -> return type == Null (type is not Object or dynamic).
565 // - Smi -> compile time subtype check (only if dst class is not parameterized). 545 // - Smi -> compile time subtype check (only if dst class is not parameterized).
566 // - Class equality (only if class is not parameterized). 546 // - Class equality (only if class is not parameterized).
567 // Inputs: 547 // Inputs:
568 // - RAX: object. 548 // - RAX: object.
569 // - RDX: instantiator type arguments or raw_null. 549 // - RDX: instantiator type arguments or raw_null.
570 // - RCX: function type arguments or raw_null. 550 // - RCX: function type arguments or raw_null.
571 // Returns: 551 // Returns:
(...skipping 27 matching lines...) Expand all
599 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 579 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
600 test_cache = 580 test_cache =
601 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); 581 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance);
602 582
603 // test_cache is null if there is no fall-through. 583 // test_cache is null if there is no fall-through.
604 Label done; 584 Label done;
605 if (!test_cache.IsNull()) { 585 if (!test_cache.IsNull()) {
606 // Generate runtime call. 586 // Generate runtime call.
607 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. 587 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args.
608 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. 588 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args.
609 __ PushObject(Object::null_object()); // Make room for the result. 589 __ PushObject(Object::null_object()); // Make room for the result.
610 __ pushq(RAX); // Push the instance. 590 __ pushq(RAX); // Push the instance.
611 __ PushObject(type); // Push the type. 591 __ PushObject(type); // Push the type.
612 __ pushq(RDX); // Instantiator type arguments. 592 __ pushq(RDX); // Instantiator type arguments.
613 __ pushq(RCX); // Function type arguments. 593 __ pushq(RCX); // Function type arguments.
614 __ LoadUniqueObject(RAX, test_cache); 594 __ LoadUniqueObject(RAX, test_cache);
615 __ pushq(RAX); 595 __ pushq(RAX);
616 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); 596 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
617 // Pop the parameters supplied to the runtime entry. The result of the 597 // Pop the parameters supplied to the runtime entry. The result of the
618 // instanceof runtime call will be left as the result of the operation. 598 // instanceof runtime call will be left as the result of the operation.
619 __ Drop(5); 599 __ Drop(5);
620 __ popq(RAX); 600 __ popq(RAX);
621 __ jmp(&done, Assembler::kNearJump); 601 __ jmp(&done, Assembler::kNearJump);
622 } 602 }
623 __ Bind(&is_not_instance); 603 __ Bind(&is_not_instance);
624 __ LoadObject(RAX, Bool::Get(false)); 604 __ LoadObject(RAX, Bool::Get(false));
625 __ jmp(&done, Assembler::kNearJump); 605 __ jmp(&done, Assembler::kNearJump);
626 606
627 __ Bind(&is_instance); 607 __ Bind(&is_instance);
628 __ LoadObject(RAX, Bool::Get(true)); 608 __ LoadObject(RAX, Bool::Get(true));
629 __ Bind(&done); 609 __ Bind(&done);
630 __ popq(RCX); // Remove pushed function type arguments. 610 __ popq(RCX); // Remove pushed function type arguments.
631 __ popq(RDX); // Remove pushed instantiator type arguments. 611 __ popq(RDX); // Remove pushed instantiator type arguments.
632 } 612 }
633 613
634
635 // Optimize assignable type check by adding inlined tests for: 614 // Optimize assignable type check by adding inlined tests for:
636 // - NULL -> return NULL. 615 // - NULL -> return NULL.
637 // - Smi -> compile time subtype check (only if dst class is not parameterized). 616 // - Smi -> compile time subtype check (only if dst class is not parameterized).
638 // - Class equality (only if class is not parameterized). 617 // - Class equality (only if class is not parameterized).
639 // Inputs: 618 // Inputs:
640 // - RAX: object. 619 // - RAX: object.
641 // - RDX: instantiator type arguments or raw_null. 620 // - RDX: instantiator type arguments or raw_null.
642 // - RCX: function type arguments or raw_null. 621 // - RCX: function type arguments or raw_null.
643 // Returns: 622 // Returns:
644 // - object in RAX for successful assignable check (or throws TypeError). 623 // - object in RAX for successful assignable check (or throws TypeError).
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
681 } 660 }
682 661
683 // Generate inline type check, linking to runtime call if not assignable. 662 // Generate inline type check, linking to runtime call if not assignable.
684 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); 663 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone());
685 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, 664 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable,
686 &runtime_call); 665 &runtime_call);
687 666
688 __ Bind(&runtime_call); 667 __ Bind(&runtime_call);
689 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. 668 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args.
690 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. 669 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args.
691 __ PushObject(Object::null_object()); // Make room for the result. 670 __ PushObject(Object::null_object()); // Make room for the result.
692 __ pushq(RAX); // Push the source object. 671 __ pushq(RAX); // Push the source object.
693 __ PushObject(dst_type); // Push the type of the destination. 672 __ PushObject(dst_type); // Push the type of the destination.
694 __ pushq(RDX); // Instantiator type arguments. 673 __ pushq(RDX); // Instantiator type arguments.
695 __ pushq(RCX); // Function type arguments. 674 __ pushq(RCX); // Function type arguments.
696 __ PushObject(dst_name); // Push the name of the destination. 675 __ PushObject(dst_name); // Push the name of the destination.
697 __ LoadUniqueObject(RAX, test_cache); 676 __ LoadUniqueObject(RAX, test_cache);
698 __ pushq(RAX); 677 __ pushq(RAX);
699 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); 678 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
700 // Pop the parameters supplied to the runtime entry. The result of the 679 // Pop the parameters supplied to the runtime entry. The result of the
701 // type check runtime call is the checked value. 680 // type check runtime call is the checked value.
702 __ Drop(6); 681 __ Drop(6);
703 __ popq(RAX); 682 __ popq(RAX);
704 683
705 __ Bind(&is_assignable); 684 __ Bind(&is_assignable);
706 __ popq(RCX); // Remove pushed function type arguments. 685 __ popq(RCX); // Remove pushed function type arguments.
707 __ popq(RDX); // Remove pushed instantiator type arguments. 686 __ popq(RDX); // Remove pushed instantiator type arguments.
708 } 687 }
709 688
710
711 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { 689 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) {
712 if (is_optimizing()) { 690 if (is_optimizing()) {
713 return; 691 return;
714 } 692 }
715 Definition* defn = instr->AsDefinition(); 693 Definition* defn = instr->AsDefinition();
716 if ((defn != NULL) && defn->HasTemp()) { 694 if ((defn != NULL) && defn->HasTemp()) {
717 Location value = defn->locs()->out(0); 695 Location value = defn->locs()->out(0);
718 if (value.IsRegister()) { 696 if (value.IsRegister()) {
719 __ pushq(value.reg()); 697 __ pushq(value.reg());
720 } else if (value.IsConstant()) { 698 } else if (value.IsConstant()) {
721 __ PushObject(value.constant()); 699 __ PushObject(value.constant());
722 } else { 700 } else {
723 ASSERT(value.IsStackSlot()); 701 ASSERT(value.IsStackSlot());
724 __ pushq(value.ToStackSlotAddress()); 702 __ pushq(value.ToStackSlotAddress());
725 } 703 }
726 } 704 }
727 } 705 }
728 706
729
730 void FlowGraphCompiler::CopyParameters() { 707 void FlowGraphCompiler::CopyParameters() {
731 __ Comment("Copy parameters"); 708 __ Comment("Copy parameters");
732 const Function& function = parsed_function().function(); 709 const Function& function = parsed_function().function();
733 LocalScope* scope = parsed_function().node_sequence()->scope(); 710 LocalScope* scope = parsed_function().node_sequence()->scope();
734 const int num_fixed_params = function.num_fixed_parameters(); 711 const int num_fixed_params = function.num_fixed_parameters();
735 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); 712 const int num_opt_pos_params = function.NumOptionalPositionalParameters();
736 const int num_opt_named_params = function.NumOptionalNamedParameters(); 713 const int num_opt_named_params = function.NumOptionalNamedParameters();
737 const int num_params = 714 const int num_params =
738 num_fixed_params + num_opt_pos_params + num_opt_named_params; 715 num_fixed_params + num_opt_pos_params + num_opt_named_params;
739 ASSERT(function.NumParameters() == num_params); 716 ASSERT(function.NumParameters() == num_params);
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 __ jmp(&null_args_loop_condition, Assembler::kNearJump); 899 __ jmp(&null_args_loop_condition, Assembler::kNearJump);
923 const Address original_argument_addr(RBP, RCX, TIMES_8, 900 const Address original_argument_addr(RBP, RCX, TIMES_8,
924 (kParamEndSlotFromFp + 1) * kWordSize); 901 (kParamEndSlotFromFp + 1) * kWordSize);
925 __ Bind(&null_args_loop); 902 __ Bind(&null_args_loop);
926 __ movq(original_argument_addr, R12); 903 __ movq(original_argument_addr, R12);
927 __ Bind(&null_args_loop_condition); 904 __ Bind(&null_args_loop_condition);
928 __ decq(RCX); 905 __ decq(RCX);
929 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump); 906 __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
930 } 907 }
931 908
932
933 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { 909 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) {
934 // TOS: return address. 910 // TOS: return address.
935 // +1 : receiver. 911 // +1 : receiver.
936 // Sequence node has one return node, its input is load field node. 912 // Sequence node has one return node, its input is load field node.
937 __ Comment("Inlined Getter"); 913 __ Comment("Inlined Getter");
938 __ movq(RAX, Address(RSP, 1 * kWordSize)); 914 __ movq(RAX, Address(RSP, 1 * kWordSize));
939 __ movq(RAX, FieldAddress(RAX, offset)); 915 __ movq(RAX, FieldAddress(RAX, offset));
940 __ ret(); 916 __ ret();
941 } 917 }
942 918
943
944 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { 919 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
945 // TOS: return address. 920 // TOS: return address.
946 // +1 : value 921 // +1 : value
947 // +2 : receiver. 922 // +2 : receiver.
948 // Sequence node has one store node and one return NULL node. 923 // Sequence node has one store node and one return NULL node.
949 __ Comment("Inlined Setter"); 924 __ Comment("Inlined Setter");
950 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver. 925 __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver.
951 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value. 926 __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value.
952 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX); 927 __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX);
953 __ LoadObject(RAX, Object::null_object()); 928 __ LoadObject(RAX, Object::null_object());
954 __ ret(); 929 __ ret();
955 } 930 }
956 931
957
958 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc 932 // NOTE: If the entry code shape changes, ReturnAddressLocator in profiler.cc
959 // needs to be updated to match. 933 // needs to be updated to match.
960 void FlowGraphCompiler::EmitFrameEntry() { 934 void FlowGraphCompiler::EmitFrameEntry() {
961 if (flow_graph().IsCompiledForOsr()) { 935 if (flow_graph().IsCompiledForOsr()) {
962 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() - 936 intptr_t extra_slots = StackSize() - flow_graph().num_stack_locals() -
963 flow_graph().num_copied_params(); 937 flow_graph().num_copied_params();
964 ASSERT(extra_slots >= 0); 938 ASSERT(extra_slots >= 0);
965 __ EnterOsrFrame(extra_slots * kWordSize); 939 __ EnterOsrFrame(extra_slots * kWordSize);
966 } else { 940 } else {
967 const Register new_pp = R13; 941 const Register new_pp = R13;
(...skipping 16 matching lines...) Expand all
984 Immediate(GetOptimizationThreshold())); 958 Immediate(GetOptimizationThreshold()));
985 ASSERT(function_reg == RDI); 959 ASSERT(function_reg == RDI);
986 __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry(), new_pp); 960 __ J(GREATER_EQUAL, *StubCode::OptimizeFunction_entry(), new_pp);
987 } 961 }
988 ASSERT(StackSize() >= 0); 962 ASSERT(StackSize() >= 0);
989 __ Comment("Enter frame"); 963 __ Comment("Enter frame");
990 __ EnterDartFrame(StackSize() * kWordSize, new_pp); 964 __ EnterDartFrame(StackSize() * kWordSize, new_pp);
991 } 965 }
992 } 966 }
993 967
994
995 void FlowGraphCompiler::CompileGraph() { 968 void FlowGraphCompiler::CompileGraph() {
996 InitCompiler(); 969 InitCompiler();
997 const Function& function = parsed_function().function(); 970 const Function& function = parsed_function().function();
998 971
999 #ifdef DART_PRECOMPILER 972 #ifdef DART_PRECOMPILER
1000 if (function.IsDynamicFunction()) { 973 if (function.IsDynamicFunction()) {
1001 __ MonomorphicCheckedEntry(); 974 __ MonomorphicCheckedEntry();
1002 } 975 }
1003 #endif // DART_PRECOMPILER 976 #endif // DART_PRECOMPILER
1004 977
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1120 1093
1121 EndCodeSourceRange(TokenPosition::kDartCodePrologue); 1094 EndCodeSourceRange(TokenPosition::kDartCodePrologue);
1122 ASSERT(!block_order().is_empty()); 1095 ASSERT(!block_order().is_empty());
1123 VisitBlocks(); 1096 VisitBlocks();
1124 1097
1125 __ int3(); 1098 __ int3();
1126 ASSERT(assembler()->constant_pool_allowed()); 1099 ASSERT(assembler()->constant_pool_allowed());
1127 GenerateDeferredCode(); 1100 GenerateDeferredCode();
1128 } 1101 }
1129 1102
1130
1131 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos, 1103 void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
1132 const StubEntry& stub_entry, 1104 const StubEntry& stub_entry,
1133 RawPcDescriptors::Kind kind, 1105 RawPcDescriptors::Kind kind,
1134 LocationSummary* locs) { 1106 LocationSummary* locs) {
1135 __ Call(stub_entry); 1107 __ Call(stub_entry);
1136 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); 1108 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs);
1137 } 1109 }
1138 1110
1139
1140 void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos, 1111 void FlowGraphCompiler::GeneratePatchableCall(TokenPosition token_pos,
1141 const StubEntry& stub_entry, 1112 const StubEntry& stub_entry,
1142 RawPcDescriptors::Kind kind, 1113 RawPcDescriptors::Kind kind,
1143 LocationSummary* locs) { 1114 LocationSummary* locs) {
1144 __ CallPatchable(stub_entry); 1115 __ CallPatchable(stub_entry);
1145 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs); 1116 EmitCallsiteMetaData(token_pos, Thread::kNoDeoptId, kind, locs);
1146 } 1117 }
1147 1118
1148
1149 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, 1119 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
1150 TokenPosition token_pos, 1120 TokenPosition token_pos,
1151 const StubEntry& stub_entry, 1121 const StubEntry& stub_entry,
1152 RawPcDescriptors::Kind kind, 1122 RawPcDescriptors::Kind kind,
1153 LocationSummary* locs) { 1123 LocationSummary* locs) {
1154 __ CallPatchable(stub_entry); 1124 __ CallPatchable(stub_entry);
1155 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); 1125 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs);
1156 // Marks either the continuation point in unoptimized code or the 1126 // Marks either the continuation point in unoptimized code or the
1157 // deoptimization point in optimized code, after call. 1127 // deoptimization point in optimized code, after call.
1158 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); 1128 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
1159 if (is_optimizing()) { 1129 if (is_optimizing()) {
1160 AddDeoptIndexAtCall(deopt_id_after); 1130 AddDeoptIndexAtCall(deopt_id_after);
1161 } else { 1131 } else {
1162 // Add deoptimization continuation point after the call and before the 1132 // Add deoptimization continuation point after the call and before the
1163 // arguments are removed. 1133 // arguments are removed.
1164 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1134 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1165 } 1135 }
1166 } 1136 }
1167 1137
1168
1169 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id, 1138 void FlowGraphCompiler::GenerateStaticDartCall(intptr_t deopt_id,
1170 TokenPosition token_pos, 1139 TokenPosition token_pos,
1171 const StubEntry& stub_entry, 1140 const StubEntry& stub_entry,
1172 RawPcDescriptors::Kind kind, 1141 RawPcDescriptors::Kind kind,
1173 LocationSummary* locs, 1142 LocationSummary* locs,
1174 const Function& target) { 1143 const Function& target) {
1175 // Call sites to the same target can share object pool entries. These 1144 // Call sites to the same target can share object pool entries. These
1176 // call sites are never patched for breakpoints: the function is deoptimized 1145 // call sites are never patched for breakpoints: the function is deoptimized
1177 // and the unoptimized code with IC calls for static calls is patched instead. 1146 // and the unoptimized code with IC calls for static calls is patched instead.
1178 ASSERT(is_optimizing()); 1147 ASSERT(is_optimizing());
1179 __ CallWithEquivalence(stub_entry, target); 1148 __ CallWithEquivalence(stub_entry, target);
1180 1149
1181 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs); 1150 EmitCallsiteMetaData(token_pos, deopt_id, kind, locs);
1182 // Marks either the continuation point in unoptimized code or the 1151 // Marks either the continuation point in unoptimized code or the
1183 // deoptimization point in optimized code, after call. 1152 // deoptimization point in optimized code, after call.
1184 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); 1153 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
1185 if (is_optimizing()) { 1154 if (is_optimizing()) {
1186 AddDeoptIndexAtCall(deopt_id_after); 1155 AddDeoptIndexAtCall(deopt_id_after);
1187 } else { 1156 } else {
1188 // Add deoptimization continuation point after the call and before the 1157 // Add deoptimization continuation point after the call and before the
1189 // arguments are removed. 1158 // arguments are removed.
1190 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1159 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1191 } 1160 }
1192 AddStaticCallTarget(target); 1161 AddStaticCallTarget(target);
1193 } 1162 }
1194 1163
1195
1196 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos, 1164 void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
1197 intptr_t deopt_id, 1165 intptr_t deopt_id,
1198 const RuntimeEntry& entry, 1166 const RuntimeEntry& entry,
1199 intptr_t argument_count, 1167 intptr_t argument_count,
1200 LocationSummary* locs) { 1168 LocationSummary* locs) {
1201 __ CallRuntime(entry, argument_count); 1169 __ CallRuntime(entry, argument_count);
1202 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs); 1170 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs);
1203 if (deopt_id != Thread::kNoDeoptId) { 1171 if (deopt_id != Thread::kNoDeoptId) {
1204 // Marks either the continuation point in unoptimized code or the 1172 // Marks either the continuation point in unoptimized code or the
1205 // deoptimization point in optimized code, after call. 1173 // deoptimization point in optimized code, after call.
1206 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); 1174 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
1207 if (is_optimizing()) { 1175 if (is_optimizing()) {
1208 AddDeoptIndexAtCall(deopt_id_after); 1176 AddDeoptIndexAtCall(deopt_id_after);
1209 } else { 1177 } else {
1210 // Add deoptimization continuation point after the call and before the 1178 // Add deoptimization continuation point after the call and before the
1211 // arguments are removed. 1179 // arguments are removed.
1212 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1180 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1213 } 1181 }
1214 } 1182 }
1215 } 1183 }
1216 1184
1217
1218 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count, 1185 void FlowGraphCompiler::EmitUnoptimizedStaticCall(intptr_t argument_count,
1219 intptr_t deopt_id, 1186 intptr_t deopt_id,
1220 TokenPosition token_pos, 1187 TokenPosition token_pos,
1221 LocationSummary* locs, 1188 LocationSummary* locs,
1222 const ICData& ic_data) { 1189 const ICData& ic_data) {
1223 const StubEntry* stub_entry = 1190 const StubEntry* stub_entry =
1224 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested()); 1191 StubCode::UnoptimizedStaticCallEntry(ic_data.NumArgsTested());
1225 __ LoadObject(RBX, ic_data); 1192 __ LoadObject(RBX, ic_data);
1226 GenerateDartCall(deopt_id, token_pos, *stub_entry, 1193 GenerateDartCall(deopt_id, token_pos, *stub_entry,
1227 RawPcDescriptors::kUnoptStaticCall, locs); 1194 RawPcDescriptors::kUnoptStaticCall, locs);
1228 __ Drop(argument_count, RCX); 1195 __ Drop(argument_count, RCX);
1229 } 1196 }
1230 1197
1231
1232 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) { 1198 void FlowGraphCompiler::EmitEdgeCounter(intptr_t edge_id) {
1233 // We do not check for overflow when incrementing the edge counter. The 1199 // We do not check for overflow when incrementing the edge counter. The
1234 // function should normally be optimized long before the counter can 1200 // function should normally be optimized long before the counter can
1235 // overflow; and though we do not reset the counters when we optimize or 1201 // overflow; and though we do not reset the counters when we optimize or
1236 // deoptimize, there is a bound on the number of 1202 // deoptimize, there is a bound on the number of
1237 // optimization/deoptimization cycles we will attempt. 1203 // optimization/deoptimization cycles we will attempt.
1238 ASSERT(!edge_counters_array_.IsNull()); 1204 ASSERT(!edge_counters_array_.IsNull());
1239 ASSERT(assembler_->constant_pool_allowed()); 1205 ASSERT(assembler_->constant_pool_allowed());
1240 __ Comment("Edge counter"); 1206 __ Comment("Edge counter");
1241 __ LoadObject(RAX, edge_counters_array_); 1207 __ LoadObject(RAX, edge_counters_array_);
1242 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(edge_id)), 1); 1208 __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(edge_id)), 1);
1243 } 1209 }
1244 1210
1245
1246 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry, 1211 void FlowGraphCompiler::EmitOptimizedInstanceCall(const StubEntry& stub_entry,
1247 const ICData& ic_data, 1212 const ICData& ic_data,
1248 intptr_t argument_count, 1213 intptr_t argument_count,
1249 intptr_t deopt_id, 1214 intptr_t deopt_id,
1250 TokenPosition token_pos, 1215 TokenPosition token_pos,
1251 LocationSummary* locs) { 1216 LocationSummary* locs) {
1252 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); 1217 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
1253 // Each ICData propagated from unoptimized to optimized code contains the 1218 // Each ICData propagated from unoptimized to optimized code contains the
1254 // function that corresponds to the Dart function of that IC call. Due 1219 // function that corresponds to the Dart function of that IC call. Due
1255 // to inlining in optimized code, that function may not correspond to the 1220 // to inlining in optimized code, that function may not correspond to the
1256 // top-level function (parsed_function().function()) which could be 1221 // top-level function (parsed_function().function()) which could be
1257 // reoptimized and which counter needs to be incremented. 1222 // reoptimized and which counter needs to be incremented.
1258 // Pass the function explicitly, it is used in IC stub. 1223 // Pass the function explicitly, it is used in IC stub.
1259 __ LoadObject(RDI, parsed_function().function()); 1224 __ LoadObject(RDI, parsed_function().function());
1260 __ LoadUniqueObject(RBX, ic_data); 1225 __ LoadUniqueObject(RBX, ic_data);
1261 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, 1226 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
1262 locs); 1227 locs);
1263 __ Drop(argument_count, RCX); 1228 __ Drop(argument_count, RCX);
1264 } 1229 }
1265 1230
1266
1267 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry, 1231 void FlowGraphCompiler::EmitInstanceCall(const StubEntry& stub_entry,
1268 const ICData& ic_data, 1232 const ICData& ic_data,
1269 intptr_t argument_count, 1233 intptr_t argument_count,
1270 intptr_t deopt_id, 1234 intptr_t deopt_id,
1271 TokenPosition token_pos, 1235 TokenPosition token_pos,
1272 LocationSummary* locs) { 1236 LocationSummary* locs) {
1273 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0); 1237 ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
1274 __ LoadUniqueObject(RBX, ic_data); 1238 __ LoadUniqueObject(RBX, ic_data);
1275 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall, 1239 GenerateDartCall(deopt_id, token_pos, stub_entry, RawPcDescriptors::kIcCall,
1276 locs); 1240 locs);
1277 __ Drop(argument_count, RCX); 1241 __ Drop(argument_count, RCX);
1278 } 1242 }
1279 1243
1280
1281 void FlowGraphCompiler::EmitMegamorphicInstanceCall( 1244 void FlowGraphCompiler::EmitMegamorphicInstanceCall(
1282 const String& name, 1245 const String& name,
1283 const Array& arguments_descriptor, 1246 const Array& arguments_descriptor,
1284 intptr_t argument_count, 1247 intptr_t argument_count,
1285 intptr_t deopt_id, 1248 intptr_t deopt_id,
1286 TokenPosition token_pos, 1249 TokenPosition token_pos,
1287 LocationSummary* locs, 1250 LocationSummary* locs,
1288 intptr_t try_index, 1251 intptr_t try_index,
1289 intptr_t slow_path_argument_count) { 1252 intptr_t slow_path_argument_count) {
1290 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0)); 1253 ASSERT(!arguments_descriptor.IsNull() && (arguments_descriptor.Length() > 0));
(...skipping 24 matching lines...) Expand all
1315 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId, 1278 AddCurrentDescriptor(RawPcDescriptors::kOther, Thread::kNoDeoptId,
1316 token_pos); 1279 token_pos);
1317 // Add deoptimization continuation point after the call and before the 1280 // Add deoptimization continuation point after the call and before the
1318 // arguments are removed. 1281 // arguments are removed.
1319 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1282 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1320 } 1283 }
1321 EmitCatchEntryState(pending_deoptimization_env_, try_index); 1284 EmitCatchEntryState(pending_deoptimization_env_, try_index);
1322 __ Drop(argument_count, RCX); 1285 __ Drop(argument_count, RCX);
1323 } 1286 }
1324 1287
1325
1326 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data, 1288 void FlowGraphCompiler::EmitSwitchableInstanceCall(const ICData& ic_data,
1327 intptr_t argument_count, 1289 intptr_t argument_count,
1328 intptr_t deopt_id, 1290 intptr_t deopt_id,
1329 TokenPosition token_pos, 1291 TokenPosition token_pos,
1330 LocationSummary* locs) { 1292 LocationSummary* locs) {
1331 ASSERT(ic_data.NumArgsTested() == 1); 1293 ASSERT(ic_data.NumArgsTested() == 1);
1332 const Code& initial_stub = 1294 const Code& initial_stub =
1333 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code()); 1295 Code::ZoneHandle(StubCode::ICCallThroughFunction_entry()->code());
1334 1296
1335 __ Comment("SwitchableCall"); 1297 __ Comment("SwitchableCall");
1336 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize)); 1298 __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
1337 __ LoadUniqueObject(CODE_REG, initial_stub); 1299 __ LoadUniqueObject(CODE_REG, initial_stub);
1338 __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset())); 1300 __ movq(RCX, FieldAddress(CODE_REG, Code::checked_entry_point_offset()));
1339 __ LoadUniqueObject(RBX, ic_data); 1301 __ LoadUniqueObject(RBX, ic_data);
1340 __ call(RCX); 1302 __ call(RCX);
1341 1303
1342
1343 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs); 1304 EmitCallsiteMetaData(token_pos, deopt_id, RawPcDescriptors::kOther, locs);
1344 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); 1305 const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
1345 if (is_optimizing()) { 1306 if (is_optimizing()) {
1346 AddDeoptIndexAtCall(deopt_id_after); 1307 AddDeoptIndexAtCall(deopt_id_after);
1347 } else { 1308 } else {
1348 // Add deoptimization continuation point after the call and before the 1309 // Add deoptimization continuation point after the call and before the
1349 // arguments are removed. 1310 // arguments are removed.
1350 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); 1311 AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos);
1351 } 1312 }
1352 __ Drop(argument_count, RCX); 1313 __ Drop(argument_count, RCX);
1353 } 1314 }
1354 1315
1355
1356 void FlowGraphCompiler::EmitOptimizedStaticCall( 1316 void FlowGraphCompiler::EmitOptimizedStaticCall(
1357 const Function& function, 1317 const Function& function,
1358 const Array& arguments_descriptor, 1318 const Array& arguments_descriptor,
1359 intptr_t argument_count, 1319 intptr_t argument_count,
1360 intptr_t deopt_id, 1320 intptr_t deopt_id,
1361 TokenPosition token_pos, 1321 TokenPosition token_pos,
1362 LocationSummary* locs) { 1322 LocationSummary* locs) {
1363 ASSERT(!function.IsClosureFunction()); 1323 ASSERT(!function.IsClosureFunction());
1364 if (function.HasOptionalParameters() || 1324 if (function.HasOptionalParameters() ||
1365 (FLAG_reify_generic_functions && function.IsGeneric())) { 1325 (FLAG_reify_generic_functions && function.IsGeneric())) {
1366 __ LoadObject(R10, arguments_descriptor); 1326 __ LoadObject(R10, arguments_descriptor);
1367 } else { 1327 } else {
1368 __ xorq(R10, R10); // GC safe smi zero because of stub. 1328 __ xorq(R10, R10); // GC safe smi zero because of stub.
1369 } 1329 }
1370 // Do not use the code from the function, but let the code be patched so that 1330 // Do not use the code from the function, but let the code be patched so that
1371 // we can record the outgoing edges to other code. 1331 // we can record the outgoing edges to other code.
1372 GenerateStaticDartCall(deopt_id, token_pos, 1332 GenerateStaticDartCall(deopt_id, token_pos,
1373 *StubCode::CallStaticFunction_entry(), 1333 *StubCode::CallStaticFunction_entry(),
1374 RawPcDescriptors::kOther, locs, function); 1334 RawPcDescriptors::kOther, locs, function);
1375 __ Drop(argument_count, RCX); 1335 __ Drop(argument_count, RCX);
1376 } 1336 }
1377 1337
1378
1379 Condition FlowGraphCompiler::EmitEqualityRegConstCompare( 1338 Condition FlowGraphCompiler::EmitEqualityRegConstCompare(
1380 Register reg, 1339 Register reg,
1381 const Object& obj, 1340 const Object& obj,
1382 bool needs_number_check, 1341 bool needs_number_check,
1383 TokenPosition token_pos, 1342 TokenPosition token_pos,
1384 intptr_t deopt_id) { 1343 intptr_t deopt_id) {
1385 ASSERT(!needs_number_check || 1344 ASSERT(!needs_number_check ||
1386 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint())); 1345 (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
1387 1346
1388 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) { 1347 if (obj.IsSmi() && (Smi::Cast(obj).Value() == 0)) {
(...skipping 13 matching lines...) Expand all
1402 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); 1361 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
1403 // Stub returns result in flags (result of a cmpq, we need ZF computed). 1362 // Stub returns result in flags (result of a cmpq, we need ZF computed).
1404 __ popq(reg); // Discard constant. 1363 __ popq(reg); // Discard constant.
1405 __ popq(reg); // Restore 'reg'. 1364 __ popq(reg); // Restore 'reg'.
1406 } else { 1365 } else {
1407 __ CompareObject(reg, obj); 1366 __ CompareObject(reg, obj);
1408 } 1367 }
1409 return EQUAL; 1368 return EQUAL;
1410 } 1369 }
1411 1370
1412
1413 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, 1371 Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
1414 Register right, 1372 Register right,
1415 bool needs_number_check, 1373 bool needs_number_check,
1416 TokenPosition token_pos, 1374 TokenPosition token_pos,
1417 intptr_t deopt_id) { 1375 intptr_t deopt_id) {
1418 if (needs_number_check) { 1376 if (needs_number_check) {
1419 __ pushq(left); 1377 __ pushq(left);
1420 __ pushq(right); 1378 __ pushq(right);
1421 if (is_optimizing()) { 1379 if (is_optimizing()) {
1422 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry()); 1380 __ CallPatchable(*StubCode::OptimizedIdenticalWithNumberCheck_entry());
1423 } else { 1381 } else {
1424 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry()); 1382 __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
1425 } 1383 }
1426 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos); 1384 AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall, deopt_id, token_pos);
1427 // Stub returns result in flags (result of a cmpq, we need ZF computed). 1385 // Stub returns result in flags (result of a cmpq, we need ZF computed).
1428 __ popq(right); 1386 __ popq(right);
1429 __ popq(left); 1387 __ popq(left);
1430 } else { 1388 } else {
1431 __ CompareRegisters(left, right); 1389 __ CompareRegisters(left, right);
1432 } 1390 }
1433 return EQUAL; 1391 return EQUAL;
1434 } 1392 }
1435 1393
1436
1437 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and 1394 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and
1438 // FlowGraphCompiler::SlowPathEnvironmentFor. 1395 // FlowGraphCompiler::SlowPathEnvironmentFor.
1439 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { 1396 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
1440 #if defined(DEBUG) 1397 #if defined(DEBUG)
1441 locs->CheckWritableInputs(); 1398 locs->CheckWritableInputs();
1442 ClobberDeadTempRegisters(locs); 1399 ClobberDeadTempRegisters(locs);
1443 #endif 1400 #endif
1444 1401
1445 // TODO(vegorov): avoid saving non-volatile registers. 1402 // TODO(vegorov): avoid saving non-volatile registers.
1446 __ PushRegisters(locs->live_registers()->cpu_registers(), 1403 __ PushRegisters(locs->live_registers()->cpu_registers(),
1447 locs->live_registers()->fpu_registers()); 1404 locs->live_registers()->fpu_registers());
1448 } 1405 }
1449 1406
1450
1451 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { 1407 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) {
1452 __ PopRegisters(locs->live_registers()->cpu_registers(), 1408 __ PopRegisters(locs->live_registers()->cpu_registers(),
1453 locs->live_registers()->fpu_registers()); 1409 locs->live_registers()->fpu_registers());
1454 } 1410 }
1455 1411
1456
1457 #if defined(DEBUG) 1412 #if defined(DEBUG)
1458 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) { 1413 void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) {
1459 // Clobber temporaries that have not been manually preserved. 1414 // Clobber temporaries that have not been manually preserved.
1460 for (intptr_t i = 0; i < locs->temp_count(); ++i) { 1415 for (intptr_t i = 0; i < locs->temp_count(); ++i) {
1461 Location tmp = locs->temp(i); 1416 Location tmp = locs->temp(i);
1462 // TODO(zerny): clobber non-live temporary FPU registers. 1417 // TODO(zerny): clobber non-live temporary FPU registers.
1463 if (tmp.IsRegister() && 1418 if (tmp.IsRegister() &&
1464 !locs->live_registers()->ContainsRegister(tmp.reg())) { 1419 !locs->live_registers()->ContainsRegister(tmp.reg())) {
1465 __ movq(tmp.reg(), Immediate(0xf7)); 1420 __ movq(tmp.reg(), Immediate(0xf7));
1466 } 1421 }
1467 } 1422 }
1468 } 1423 }
1469 #endif 1424 #endif
1470 1425
1471
1472 void FlowGraphCompiler::EmitTestAndCallLoadReceiver( 1426 void FlowGraphCompiler::EmitTestAndCallLoadReceiver(
1473 intptr_t argument_count, 1427 intptr_t argument_count,
1474 const Array& arguments_descriptor) { 1428 const Array& arguments_descriptor) {
1475 __ Comment("EmitTestAndCall"); 1429 __ Comment("EmitTestAndCall");
1476 // Load receiver into RAX. 1430 // Load receiver into RAX.
1477 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize)); 1431 __ movq(RAX, Address(RSP, (argument_count - 1) * kWordSize));
1478 __ LoadObject(R10, arguments_descriptor); 1432 __ LoadObject(R10, arguments_descriptor);
1479 } 1433 }
1480 1434
1481
1482 void FlowGraphCompiler::EmitTestAndCallSmiBranch(Label* label, bool if_smi) { 1435 void FlowGraphCompiler::EmitTestAndCallSmiBranch(Label* label, bool if_smi) {
1483 __ testq(RAX, Immediate(kSmiTagMask)); 1436 __ testq(RAX, Immediate(kSmiTagMask));
1484 // Jump if receiver is (not) Smi. 1437 // Jump if receiver is (not) Smi.
1485 __ j(if_smi ? ZERO : NOT_ZERO, label); 1438 __ j(if_smi ? ZERO : NOT_ZERO, label);
1486 } 1439 }
1487 1440
1488
1489 void FlowGraphCompiler::EmitTestAndCallLoadCid() { 1441 void FlowGraphCompiler::EmitTestAndCallLoadCid() {
1490 __ LoadClassId(RDI, RAX); 1442 __ LoadClassId(RDI, RAX);
1491 } 1443 }
1492 1444
1493
1494 int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label, 1445 int FlowGraphCompiler::EmitTestAndCallCheckCid(Label* next_label,
1495 const CidRange& range, 1446 const CidRange& range,
1496 int bias) { 1447 int bias) {
1497 intptr_t cid_start = range.cid_start; 1448 intptr_t cid_start = range.cid_start;
1498 if (range.IsSingleCid()) { 1449 if (range.IsSingleCid()) {
1499 __ cmpl(RDI, Immediate(cid_start - bias)); 1450 __ cmpl(RDI, Immediate(cid_start - bias));
1500 __ j(NOT_EQUAL, next_label); 1451 __ j(NOT_EQUAL, next_label);
1501 } else { 1452 } else {
1502 __ addl(RDI, Immediate(bias - cid_start)); 1453 __ addl(RDI, Immediate(bias - cid_start));
1503 bias = cid_start; 1454 bias = cid_start;
1504 __ cmpl(RDI, Immediate(range.Extent())); 1455 __ cmpl(RDI, Immediate(range.Extent()));
1505 __ j(ABOVE, next_label); // Unsigned higher. 1456 __ j(ABOVE, next_label); // Unsigned higher.
1506 } 1457 }
1507 return bias; 1458 return bias;
1508 } 1459 }
1509 1460
1510
1511 #undef __ 1461 #undef __
1512 #define __ compiler_->assembler()-> 1462 #define __ compiler_->assembler()->
1513 1463
1514
1515 void ParallelMoveResolver::EmitMove(int index) { 1464 void ParallelMoveResolver::EmitMove(int index) {
1516 MoveOperands* move = moves_[index]; 1465 MoveOperands* move = moves_[index];
1517 const Location source = move->src(); 1466 const Location source = move->src();
1518 const Location destination = move->dest(); 1467 const Location destination = move->dest();
1519 1468
1520 if (source.IsRegister()) { 1469 if (source.IsRegister()) {
1521 if (destination.IsRegister()) { 1470 if (destination.IsRegister()) {
1522 __ movq(destination.reg(), source.reg()); 1471 __ movq(destination.reg(), source.reg());
1523 } else { 1472 } else {
1524 ASSERT(destination.IsStackSlot()); 1473 ASSERT(destination.IsStackSlot());
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1598 Immediate(Smi::Cast(constant).Value())); 1547 Immediate(Smi::Cast(constant).Value()));
1599 } else { 1548 } else {
1600 StoreObject(destination.ToStackSlotAddress(), constant); 1549 StoreObject(destination.ToStackSlotAddress(), constant);
1601 } 1550 }
1602 } 1551 }
1603 } 1552 }
1604 1553
1605 move->Eliminate(); 1554 move->Eliminate();
1606 } 1555 }
1607 1556
1608
1609 void ParallelMoveResolver::EmitSwap(int index) { 1557 void ParallelMoveResolver::EmitSwap(int index) {
1610 MoveOperands* move = moves_[index]; 1558 MoveOperands* move = moves_[index];
1611 const Location source = move->src(); 1559 const Location source = move->src();
1612 const Location destination = move->dest(); 1560 const Location destination = move->dest();
1613 1561
1614 if (source.IsRegister() && destination.IsRegister()) { 1562 if (source.IsRegister() && destination.IsRegister()) {
1615 __ xchgq(destination.reg(), source.reg()); 1563 __ xchgq(destination.reg(), source.reg());
1616 } else if (source.IsRegister() && destination.IsStackSlot()) { 1564 } else if (source.IsRegister() && destination.IsStackSlot()) {
1617 Exchange(source.reg(), destination.ToStackSlotAddress()); 1565 Exchange(source.reg(), destination.ToStackSlotAddress());
1618 } else if (source.IsStackSlot() && destination.IsRegister()) { 1566 } else if (source.IsStackSlot() && destination.IsRegister()) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1674 for (int i = 0; i < moves_.length(); ++i) { 1622 for (int i = 0; i < moves_.length(); ++i) {
1675 const MoveOperands& other_move = *moves_[i]; 1623 const MoveOperands& other_move = *moves_[i];
1676 if (other_move.Blocks(source)) { 1624 if (other_move.Blocks(source)) {
1677 moves_[i]->set_src(destination); 1625 moves_[i]->set_src(destination);
1678 } else if (other_move.Blocks(destination)) { 1626 } else if (other_move.Blocks(destination)) {
1679 moves_[i]->set_src(source); 1627 moves_[i]->set_src(source);
1680 } 1628 }
1681 } 1629 }
1682 } 1630 }
1683 1631
1684
1685 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, 1632 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst,
1686 const Address& src) { 1633 const Address& src) {
1687 __ MoveMemoryToMemory(dst, src); 1634 __ MoveMemoryToMemory(dst, src);
1688 } 1635 }
1689 1636
1690
1691 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { 1637 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) {
1692 __ StoreObject(dst, obj); 1638 __ StoreObject(dst, obj);
1693 } 1639 }
1694 1640
1695
1696 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { 1641 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) {
1697 __ Exchange(reg, mem); 1642 __ Exchange(reg, mem);
1698 } 1643 }
1699 1644
1700
1701 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { 1645 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
1702 __ Exchange(mem1, mem2); 1646 __ Exchange(mem1, mem2);
1703 } 1647 }
1704 1648
1705
1706 void ParallelMoveResolver::Exchange(Register reg, 1649 void ParallelMoveResolver::Exchange(Register reg,
1707 Register base_reg, 1650 Register base_reg,
1708 intptr_t stack_offset) { 1651 intptr_t stack_offset) {
1709 UNREACHABLE(); 1652 UNREACHABLE();
1710 } 1653 }
1711 1654
1712
1713 void ParallelMoveResolver::Exchange(Register base_reg1, 1655 void ParallelMoveResolver::Exchange(Register base_reg1,
1714 intptr_t stack_offset1, 1656 intptr_t stack_offset1,
1715 Register base_reg2, 1657 Register base_reg2,
1716 intptr_t stack_offset2) { 1658 intptr_t stack_offset2) {
1717 UNREACHABLE(); 1659 UNREACHABLE();
1718 } 1660 }
1719 1661
1720
1721 void ParallelMoveResolver::SpillScratch(Register reg) { 1662 void ParallelMoveResolver::SpillScratch(Register reg) {
1722 __ pushq(reg); 1663 __ pushq(reg);
1723 } 1664 }
1724 1665
1725
1726 void ParallelMoveResolver::RestoreScratch(Register reg) { 1666 void ParallelMoveResolver::RestoreScratch(Register reg) {
1727 __ popq(reg); 1667 __ popq(reg);
1728 } 1668 }
1729 1669
1730
1731 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { 1670 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) {
1732 __ AddImmediate(RSP, Immediate(-kFpuRegisterSize)); 1671 __ AddImmediate(RSP, Immediate(-kFpuRegisterSize));
1733 __ movups(Address(RSP, 0), reg); 1672 __ movups(Address(RSP, 0), reg);
1734 } 1673 }
1735 1674
1736
1737 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { 1675 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) {
1738 __ movups(reg, Address(RSP, 0)); 1676 __ movups(reg, Address(RSP, 0));
1739 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); 1677 __ AddImmediate(RSP, Immediate(kFpuRegisterSize));
1740 } 1678 }
1741 1679
1742
1743 #undef __ 1680 #undef __
1744 1681
1745 } // namespace dart 1682 } // namespace dart
1746 1683
1747 #endif // defined TARGET_ARCH_X64 1684 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_ia32.cc ('k') | runtime/vm/flow_graph_inliner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698