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

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

Issue 10832150: Get rid of ast node ids. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/il_printer.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/flow_graph_compiler.h" 8 #include "vm/flow_graph_compiler.h"
9 9
10 #include "lib/error.h" 10 #include "lib/error.h"
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 } 142 }
143 143
144 144
145 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 145 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
146 // type test is conclusive, otherwise fallthrough if a type test could not 146 // type test is conclusive, otherwise fallthrough if a type test could not
147 // be completed. 147 // be completed.
148 // RAX: instance (must survive). 148 // RAX: instance (must survive).
149 // Clobbers R10. 149 // Clobbers R10.
150 RawSubtypeTestCache* 150 RawSubtypeTestCache*
151 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( 151 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
152 intptr_t cid,
153 intptr_t token_pos, 152 intptr_t token_pos,
154 const AbstractType& type, 153 const AbstractType& type,
155 Label* is_instance_lbl, 154 Label* is_instance_lbl,
156 Label* is_not_instance_lbl) { 155 Label* is_not_instance_lbl) {
157 ASSERT(type.IsInstantiated()); 156 ASSERT(type.IsInstantiated());
158 const Class& type_class = Class::ZoneHandle(type.type_class()); 157 const Class& type_class = Class::ZoneHandle(type.type_class());
159 ASSERT(type_class.HasTypeArguments()); 158 ASSERT(type_class.HasTypeArguments());
160 const Register kInstanceReg = RAX; 159 const Register kInstanceReg = RAX;
161 // A Smi object cannot be the instance of a parameterized class. 160 // A Smi object cannot be the instance of a parameterized class.
162 __ testq(kInstanceReg, Immediate(kSmiTagMask)); 161 __ testq(kInstanceReg, Immediate(kSmiTagMask));
163 __ j(ZERO, is_not_instance_lbl); 162 __ j(ZERO, is_not_instance_lbl);
164 const AbstractTypeArguments& type_arguments = 163 const AbstractTypeArguments& type_arguments =
165 AbstractTypeArguments::ZoneHandle(type.arguments()); 164 AbstractTypeArguments::ZoneHandle(type.arguments());
166 const bool is_raw_type = type_arguments.IsNull() || 165 const bool is_raw_type = type_arguments.IsNull() ||
167 type_arguments.IsRaw(type_arguments.Length()); 166 type_arguments.IsRaw(type_arguments.Length());
168 if (is_raw_type) { 167 if (is_raw_type) {
169 const Register kClassIdReg = R10; 168 const Register kClassIdReg = R10;
170 // Dynamic type argument, check only classes. 169 // Dynamic type argument, check only classes.
171 // List is a very common case. 170 // List is a very common case.
172 __ LoadClassId(kClassIdReg, kInstanceReg); 171 __ LoadClassId(kClassIdReg, kInstanceReg);
173 if (!type_class.is_interface()) { 172 if (!type_class.is_interface()) {
174 __ cmpl(kClassIdReg, Immediate(type_class.id())); 173 __ cmpl(kClassIdReg, Immediate(type_class.id()));
175 __ j(EQUAL, is_instance_lbl); 174 __ j(EQUAL, is_instance_lbl);
176 } 175 }
177 if (type.IsListInterface()) { 176 if (type.IsListInterface()) {
178 GenerateListTypeCheck(kClassIdReg, is_instance_lbl); 177 GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
179 } 178 }
180 return GenerateSubtype1TestCacheLookup( 179 return GenerateSubtype1TestCacheLookup(
181 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 180 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
182 } 181 }
183 // If one type argument only, check if type argument is Object or Dynamic. 182 // If one type argument only, check if type argument is Object or Dynamic.
184 if (type_arguments.Length() == 1) { 183 if (type_arguments.Length() == 1) {
185 const AbstractType& tp_argument = AbstractType::ZoneHandle( 184 const AbstractType& tp_argument = AbstractType::ZoneHandle(
186 type_arguments.TypeAt(0)); 185 type_arguments.TypeAt(0));
187 ASSERT(!tp_argument.IsMalformed()); 186 ASSERT(!tp_argument.IsMalformed());
188 if (tp_argument.IsType()) { 187 if (tp_argument.IsType()) {
189 ASSERT(tp_argument.HasResolvedTypeClass()); 188 ASSERT(tp_argument.HasResolvedTypeClass());
190 // Check if type argument is dynamic or Object. 189 // Check if type argument is dynamic or Object.
191 const Type& object_type = Type::Handle(Type::ObjectType()); 190 const Type& object_type = Type::Handle(Type::ObjectType());
192 if (object_type.IsSubtypeOf(tp_argument, NULL)) { 191 if (object_type.IsSubtypeOf(tp_argument, NULL)) {
193 // Instance class test only necessary. 192 // Instance class test only necessary.
194 return GenerateSubtype1TestCacheLookup( 193 return GenerateSubtype1TestCacheLookup(
195 cid, token_pos, type_class, is_instance_lbl, is_not_instance_lbl); 194 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
196 } 195 }
197 } 196 }
198 } 197 }
199 // Regular subtype test cache involving instance's type arguments. 198 // Regular subtype test cache involving instance's type arguments.
200 const Register kTypeArgumentsReg = kNoRegister; 199 const Register kTypeArgumentsReg = kNoRegister;
201 const Register kTempReg = R10; 200 const Register kTempReg = R10;
202 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, 201 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
203 kInstanceReg, 202 kInstanceReg,
204 kTypeArgumentsReg, 203 kTypeArgumentsReg,
205 kTempReg, 204 kTempReg,
(...skipping 13 matching lines...) Expand all
219 __ jmp(is_not_equal_lbl); 218 __ jmp(is_not_equal_lbl);
220 } 219 }
221 220
222 221
223 // Testing against an instantiated type with no arguments, without 222 // Testing against an instantiated type with no arguments, without
224 // SubtypeTestCache. 223 // SubtypeTestCache.
225 // RAX: instance to test against (preserved). 224 // RAX: instance to test against (preserved).
226 // Clobbers R10, R13. 225 // Clobbers R10, R13.
227 // Returns true if there is a fallthrough. 226 // Returns true if there is a fallthrough.
228 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( 227 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
229 intptr_t cid,
230 intptr_t token_pos, 228 intptr_t token_pos,
231 const AbstractType& type, 229 const AbstractType& type,
232 Label* is_instance_lbl, 230 Label* is_instance_lbl,
233 Label* is_not_instance_lbl) { 231 Label* is_not_instance_lbl) {
234 ASSERT(type.IsInstantiated()); 232 ASSERT(type.IsInstantiated());
235 const Class& type_class = Class::Handle(type.type_class()); 233 const Class& type_class = Class::Handle(type.type_class());
236 ASSERT(!type_class.HasTypeArguments()); 234 ASSERT(!type_class.HasTypeArguments());
237 235
238 const Register kInstanceReg = RAX; 236 const Register kInstanceReg = RAX;
239 Label compare_classes; 237 Label compare_classes;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 292
295 293
296 // Uses SubtypeTestCache to store instance class and result. 294 // Uses SubtypeTestCache to store instance class and result.
297 // RAX: instance to test. 295 // RAX: instance to test.
298 // Clobbers R10, R13. 296 // Clobbers R10, R13.
299 // Immediate class test already done. 297 // Immediate class test already done.
300 // TODO(srdjan): Implement a quicker subtype check, as type test 298 // TODO(srdjan): Implement a quicker subtype check, as type test
301 // arrays can grow too high, but they may be useful when optimizing 299 // arrays can grow too high, but they may be useful when optimizing
302 // code (type-feedback). 300 // code (type-feedback).
303 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( 301 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
304 intptr_t cid,
305 intptr_t token_pos, 302 intptr_t token_pos,
306 const Class& type_class, 303 const Class& type_class,
307 Label* is_instance_lbl, 304 Label* is_instance_lbl,
308 Label* is_not_instance_lbl) { 305 Label* is_not_instance_lbl) {
309 const Register kInstanceReg = RAX; 306 const Register kInstanceReg = RAX;
310 __ LoadClass(R10, kInstanceReg); 307 __ LoadClass(R10, kInstanceReg);
311 // R10: instance class. 308 // R10: instance class.
312 // Check immediate superclass equality. 309 // Check immediate superclass equality.
313 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); 310 __ movq(R13, FieldAddress(R10, Class::super_type_offset()));
314 __ movq(R13, FieldAddress(R13, Type::type_class_offset())); 311 __ movq(R13, FieldAddress(R13, Type::type_class_offset()));
315 __ CompareObject(R13, type_class); 312 __ CompareObject(R13, type_class);
316 __ j(EQUAL, is_instance_lbl); 313 __ j(EQUAL, is_instance_lbl);
317 314
318 const Register kTypeArgumentsReg = kNoRegister; 315 const Register kTypeArgumentsReg = kNoRegister;
319 const Register kTempReg = R10; 316 const Register kTempReg = R10;
320 return GenerateCallSubtypeTestStub(kTestTypeOneArg, 317 return GenerateCallSubtypeTestStub(kTestTypeOneArg,
321 kInstanceReg, 318 kInstanceReg,
322 kTypeArgumentsReg, 319 kTypeArgumentsReg,
323 kTempReg, 320 kTempReg,
324 is_instance_lbl, 321 is_instance_lbl,
325 is_not_instance_lbl); 322 is_not_instance_lbl);
326 } 323 }
327 324
328 325
329 // Generates inlined check if 'type' is a type parameter or type itsef 326 // Generates inlined check if 'type' is a type parameter or type itsef
330 // RAX: instance (preserved). 327 // RAX: instance (preserved).
331 // Clobbers RDI, RDX, R10. 328 // Clobbers RDI, RDX, R10.
332 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( 329 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
333 intptr_t cid,
334 intptr_t token_pos, 330 intptr_t token_pos,
335 const AbstractType& type, 331 const AbstractType& type,
336 Label* is_instance_lbl, 332 Label* is_instance_lbl,
337 Label* is_not_instance_lbl) { 333 Label* is_not_instance_lbl) {
338 ASSERT(!type.IsInstantiated()); 334 ASSERT(!type.IsInstantiated());
339 // Skip check if destination is a dynamic type. 335 // Skip check if destination is a dynamic type.
340 const Immediate raw_null = 336 const Immediate raw_null =
341 Immediate(reinterpret_cast<intptr_t>(Object::null())); 337 Immediate(reinterpret_cast<intptr_t>(Object::null()));
342 if (type.IsTypeParameter()) { 338 if (type.IsTypeParameter()) {
343 const TypeParameter& type_param = TypeParameter::Cast(type); 339 const TypeParameter& type_param = TypeParameter::Cast(type);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 // Inputs: 411 // Inputs:
416 // - RAX: instance to test against (preserved). 412 // - RAX: instance to test against (preserved).
417 // - RDX: optional instantiator type arguments (preserved). 413 // - RDX: optional instantiator type arguments (preserved).
418 // Clobbers R10, R13. 414 // Clobbers R10, R13.
419 // Returns: 415 // Returns:
420 // - preserved instance in RAX and optional instantiator type arguments in RDX. 416 // - preserved instance in RAX and optional instantiator type arguments in RDX.
421 // Note that this inlined code must be followed by the runtime_call code, as it 417 // Note that this inlined code must be followed by the runtime_call code, as it
422 // may fall through to it. Otherwise, this inline code will jump to the label 418 // may fall through to it. Otherwise, this inline code will jump to the label
423 // is_instance or to the label is_not_instance. 419 // is_instance or to the label is_not_instance.
424 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( 420 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
425 intptr_t cid,
426 intptr_t token_pos, 421 intptr_t token_pos,
427 const AbstractType& type, 422 const AbstractType& type,
428 Label* is_instance_lbl, 423 Label* is_instance_lbl,
429 Label* is_not_instance_lbl) { 424 Label* is_not_instance_lbl) {
430 if (type.IsVoidType()) { 425 if (type.IsVoidType()) {
431 // A non-null value is returned from a void function, which will result in a 426 // A non-null value is returned from a void function, which will result in a
432 // type error. A null value is handled prior to executing this inline code. 427 // type error. A null value is handled prior to executing this inline code.
433 return SubtypeTestCache::null(); 428 return SubtypeTestCache::null();
434 } 429 }
435 if (type.IsInstantiated()) { 430 if (type.IsInstantiated()) {
436 const Class& type_class = Class::ZoneHandle(type.type_class()); 431 const Class& type_class = Class::ZoneHandle(type.type_class());
437 // A Smi object cannot be the instance of a parameterized class. 432 // A Smi object cannot be the instance of a parameterized class.
438 // A class equality check is only applicable with a dst type of a 433 // A class equality check is only applicable with a dst type of a
439 // non-parameterized class or with a raw dst type of a parameterized class. 434 // non-parameterized class or with a raw dst type of a parameterized class.
440 if (type_class.HasTypeArguments()) { 435 if (type_class.HasTypeArguments()) {
441 return GenerateInstantiatedTypeWithArgumentsTest(cid, 436 return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
442 token_pos,
443 type, 437 type,
444 is_instance_lbl, 438 is_instance_lbl,
445 is_not_instance_lbl); 439 is_not_instance_lbl);
446 // Fall through to runtime call. 440 // Fall through to runtime call.
447 } 441 }
448 const bool has_fall_through = 442 const bool has_fall_through =
449 GenerateInstantiatedTypeNoArgumentsTest(cid, 443 GenerateInstantiatedTypeNoArgumentsTest(token_pos,
450 token_pos,
451 type, 444 type,
452 is_instance_lbl, 445 is_instance_lbl,
453 is_not_instance_lbl); 446 is_not_instance_lbl);
454 if (has_fall_through) { 447 if (has_fall_through) {
455 // If test non-conclusive so far, try the inlined type-test cache. 448 // If test non-conclusive so far, try the inlined type-test cache.
456 // 'type' is known at compile time. 449 // 'type' is known at compile time.
457 return GenerateSubtype1TestCacheLookup( 450 return GenerateSubtype1TestCacheLookup(
458 cid, token_pos, type_class, 451 token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
459 is_instance_lbl, is_not_instance_lbl);
460 } else { 452 } else {
461 return SubtypeTestCache::null(); 453 return SubtypeTestCache::null();
462 } 454 }
463 } 455 }
464 return GenerateUninstantiatedTypeTest(cid, 456 return GenerateUninstantiatedTypeTest(token_pos,
465 token_pos,
466 type, 457 type,
467 is_instance_lbl, 458 is_instance_lbl,
468 is_not_instance_lbl); 459 is_not_instance_lbl);
469 } 460 }
470 461
471 462
472 // If instanceof type test cannot be performed successfully at compile time and 463 // If instanceof type test cannot be performed successfully at compile time and
473 // therefore eliminated, optimize it by adding inlined tests for: 464 // therefore eliminated, optimize it by adding inlined tests for:
474 // - NULL -> return false. 465 // - NULL -> return false.
475 // - Smi -> compile time subtype check (only if dst class is not parameterized). 466 // - Smi -> compile time subtype check (only if dst class is not parameterized).
476 // - Class equality (only if class is not parameterized). 467 // - Class equality (only if class is not parameterized).
477 // Inputs: 468 // Inputs:
478 // - RAX: object. 469 // - RAX: object.
479 // - RDX: instantiator type arguments or raw_null. 470 // - RDX: instantiator type arguments or raw_null.
480 // - RCX: instantiator or raw_null. 471 // - RCX: instantiator or raw_null.
481 // Clobbers RCX and RDX. 472 // Clobbers RCX and RDX.
482 // Returns: 473 // Returns:
483 // - true or false in RAX. 474 // - true or false in RAX.
484 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, 475 void FlowGraphCompiler::GenerateInstanceOf(intptr_t deopt_id,
485 intptr_t token_pos, 476 intptr_t token_pos,
486 intptr_t try_index, 477 intptr_t try_index,
487 const AbstractType& type, 478 const AbstractType& type,
488 bool negate_result) { 479 bool negate_result) {
489 ASSERT(type.IsFinalized() && !type.IsMalformed()); 480 ASSERT(type.IsFinalized() && !type.IsMalformed());
490 481
491 const Immediate raw_null = 482 const Immediate raw_null =
492 Immediate(reinterpret_cast<intptr_t>(Object::null())); 483 Immediate(reinterpret_cast<intptr_t>(Object::null()));
493 Label is_instance, is_not_instance; 484 Label is_instance, is_not_instance;
494 __ pushq(RCX); // Store instantiator on stack. 485 __ pushq(RCX); // Store instantiator on stack.
495 __ pushq(RDX); // Store instantiator type arguments. 486 __ pushq(RDX); // Store instantiator type arguments.
496 // If type is instantiated and non-parameterized, we can inline code 487 // If type is instantiated and non-parameterized, we can inline code
497 // checking whether the tested instance is a Smi. 488 // checking whether the tested instance is a Smi.
498 if (type.IsInstantiated()) { 489 if (type.IsInstantiated()) {
499 // A null object is only an instance of Object and Dynamic, which has 490 // A null object is only an instance of Object and Dynamic, which has
500 // already been checked above (if the type is instantiated). So we can 491 // already been checked above (if the type is instantiated). So we can
501 // return false here if the instance is null (and if the type is 492 // return false here if the instance is null (and if the type is
502 // instantiated). 493 // instantiated).
503 // We can only inline this null check if the type is instantiated at compile 494 // We can only inline this null check if the type is instantiated at compile
504 // time, since an uninstantiated type at compile time could be Object or 495 // time, since an uninstantiated type at compile time could be Object or
505 // Dynamic at run time. 496 // Dynamic at run time.
506 __ cmpq(RAX, raw_null); 497 __ cmpq(RAX, raw_null);
507 __ j(EQUAL, &is_not_instance); 498 __ j(EQUAL, &is_not_instance);
508 } 499 }
509 500
510 // Generate inline instanceof test. 501 // Generate inline instanceof test.
511 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 502 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
512 test_cache = GenerateInlineInstanceof(cid, token_pos, type, 503 test_cache = GenerateInlineInstanceof(token_pos, type,
513 &is_instance, &is_not_instance); 504 &is_instance, &is_not_instance);
514 505
515 // test_cache is null if there is no fall-through. 506 // test_cache is null if there is no fall-through.
516 Label done; 507 Label done;
517 if (!test_cache.IsNull()) { 508 if (!test_cache.IsNull()) {
518 // Generate runtime call. 509 // Generate runtime call.
519 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 510 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
520 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. 511 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
521 __ PushObject(Object::ZoneHandle()); // Make room for the result. 512 __ PushObject(Object::ZoneHandle()); // Make room for the result.
522 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
523 __ pushq(RAX); // Push the instance. 513 __ pushq(RAX); // Push the instance.
524 __ PushObject(type); // Push the type. 514 __ PushObject(type); // Push the type.
525 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. 515 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
526 __ pushq(RDX); // Instantiator type arguments. 516 __ pushq(RDX); // Instantiator type arguments.
527 __ LoadObject(RAX, test_cache); 517 __ LoadObject(RAX, test_cache);
528 __ pushq(RAX); 518 __ pushq(RAX);
529 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); 519 GenerateCallRuntime(deopt_id, token_pos, try_index,
520 kInstanceofRuntimeEntry);
530 // Pop the parameters supplied to the runtime entry. The result of the 521 // Pop the parameters supplied to the runtime entry. The result of the
531 // instanceof runtime call will be left as the result of the operation. 522 // instanceof runtime call will be left as the result of the operation.
532 __ Drop(6); 523 __ Drop(5);
533 if (negate_result) { 524 if (negate_result) {
534 __ popq(RDX); 525 __ popq(RDX);
535 __ LoadObject(RAX, bool_true()); 526 __ LoadObject(RAX, bool_true());
536 __ cmpq(RDX, RAX); 527 __ cmpq(RDX, RAX);
537 __ j(NOT_EQUAL, &done, Assembler::kNearJump); 528 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
538 __ LoadObject(RAX, bool_false()); 529 __ LoadObject(RAX, bool_false());
539 } else { 530 } else {
540 __ popq(RAX); 531 __ popq(RAX);
541 } 532 }
542 __ jmp(&done, Assembler::kNearJump); 533 __ jmp(&done, Assembler::kNearJump);
(...skipping 15 matching lines...) Expand all
558 // - Smi -> compile time subtype check (only if dst class is not parameterized). 549 // - Smi -> compile time subtype check (only if dst class is not parameterized).
559 // - Class equality (only if class is not parameterized). 550 // - Class equality (only if class is not parameterized).
560 // Inputs: 551 // Inputs:
561 // - RAX: object. 552 // - RAX: object.
562 // - RDX: instantiator type arguments or raw_null. 553 // - RDX: instantiator type arguments or raw_null.
563 // - RCX: instantiator or raw_null. 554 // - RCX: instantiator or raw_null.
564 // Returns: 555 // Returns:
565 // - object in RAX for successful assignable check (or throws TypeError). 556 // - object in RAX for successful assignable check (or throws TypeError).
566 // Performance notes: positive checks must be quick, negative checks can be slow 557 // Performance notes: positive checks must be quick, negative checks can be slow
567 // as they throw an exception. 558 // as they throw an exception.
568 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, 559 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t deopt_id,
569 intptr_t token_pos, 560 intptr_t token_pos,
570 intptr_t try_index, 561 intptr_t try_index,
571 const AbstractType& dst_type, 562 const AbstractType& dst_type,
572 const String& dst_name) { 563 const String& dst_name) {
573 ASSERT(token_pos >= 0); 564 ASSERT(token_pos >= 0);
574 ASSERT(!dst_type.IsNull()); 565 ASSERT(!dst_type.IsNull());
575 ASSERT(dst_type.IsFinalized()); 566 ASSERT(dst_type.IsFinalized());
576 // Assignable check is skipped in FlowGraphBuilder, not here. 567 // Assignable check is skipped in FlowGraphBuilder, not here.
577 ASSERT(dst_type.IsMalformed() || 568 ASSERT(dst_type.IsMalformed() ||
578 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); 569 (!dst_type.IsDynamicType() && !dst_type.IsObjectType()));
579 __ pushq(RCX); // Store instantiator. 570 __ pushq(RCX); // Store instantiator.
580 __ pushq(RDX); // Store instantiator type arguments. 571 __ pushq(RDX); // Store instantiator type arguments.
581 // A null object is always assignable and is returned as result. 572 // A null object is always assignable and is returned as result.
582 const Immediate raw_null = 573 const Immediate raw_null =
583 Immediate(reinterpret_cast<intptr_t>(Object::null())); 574 Immediate(reinterpret_cast<intptr_t>(Object::null()));
584 Label is_assignable, runtime_call; 575 Label is_assignable, runtime_call;
585 __ cmpq(RAX, raw_null); 576 __ cmpq(RAX, raw_null);
586 __ j(EQUAL, &is_assignable); 577 __ j(EQUAL, &is_assignable);
587 578
588 // Generate throw new TypeError() if the type is malformed. 579 // Generate throw new TypeError() if the type is malformed.
589 if (dst_type.IsMalformed()) { 580 if (dst_type.IsMalformed()) {
590 const Error& error = Error::Handle(dst_type.malformed_error()); 581 const Error& error = Error::Handle(dst_type.malformed_error());
591 const String& error_message = String::ZoneHandle( 582 const String& error_message = String::ZoneHandle(
592 Symbols::New(error.ToErrorCString())); 583 Symbols::New(error.ToErrorCString()));
593 __ PushObject(Object::ZoneHandle()); // Make room for the result. 584 __ PushObject(Object::ZoneHandle()); // Make room for the result.
594 __ pushq(RAX); // Push the source object. 585 __ pushq(RAX); // Push the source object.
595 __ PushObject(dst_name); // Push the name of the destination. 586 __ PushObject(dst_name); // Push the name of the destination.
596 __ PushObject(error_message); 587 __ PushObject(error_message);
597 GenerateCallRuntime(cid, 588 GenerateCallRuntime(deopt_id,
598 token_pos, 589 token_pos,
599 try_index, 590 try_index,
600 kMalformedTypeErrorRuntimeEntry); 591 kMalformedTypeErrorRuntimeEntry);
601 // We should never return here. 592 // We should never return here.
602 __ int3(); 593 __ int3();
603 594
604 __ Bind(&is_assignable); // For a null object. 595 __ Bind(&is_assignable); // For a null object.
605 return; 596 return;
606 } 597 }
607 598
608 // Generate inline type check, linking to runtime call if not assignable. 599 // Generate inline type check, linking to runtime call if not assignable.
609 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); 600 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
610 test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type, 601 test_cache = GenerateInlineInstanceof(token_pos, dst_type,
611 &is_assignable, &runtime_call); 602 &is_assignable, &runtime_call);
612 603
613 __ Bind(&runtime_call); 604 __ Bind(&runtime_call);
614 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. 605 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
615 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. 606 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
616 __ PushObject(Object::ZoneHandle()); // Make room for the result. 607 __ PushObject(Object::ZoneHandle()); // Make room for the result.
617 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
618 __ pushq(RAX); // Push the source object. 608 __ pushq(RAX); // Push the source object.
619 __ PushObject(dst_type); // Push the type of the destination. 609 __ PushObject(dst_type); // Push the type of the destination.
620 __ pushq(RCX); // Instantiator. 610 __ pushq(RCX); // Instantiator.
621 __ pushq(RDX); // Instantiator type arguments. 611 __ pushq(RDX); // Instantiator type arguments.
622 __ PushObject(dst_name); // Push the name of the destination. 612 __ PushObject(dst_name); // Push the name of the destination.
623 __ LoadObject(RAX, test_cache); 613 __ LoadObject(RAX, test_cache);
624 __ pushq(RAX); 614 __ pushq(RAX);
625 GenerateCallRuntime(cid, 615 GenerateCallRuntime(deopt_id,
626 token_pos, 616 token_pos,
627 try_index, 617 try_index,
628 kTypeCheckRuntimeEntry); 618 kTypeCheckRuntimeEntry);
629 // Pop the parameters supplied to the runtime entry. The result of the 619 // Pop the parameters supplied to the runtime entry. The result of the
630 // type check runtime call is the checked value. 620 // type check runtime call is the checked value.
631 __ Drop(7); 621 __ Drop(6);
632 __ popq(RAX); 622 __ popq(RAX);
633 623
634 __ Bind(&is_assignable); 624 __ Bind(&is_assignable);
635 __ popq(RDX); // Remove pushed instantiator type arguments.. 625 __ popq(RDX); // Remove pushed instantiator type arguments..
636 __ popq(RCX); // Remove pushed instantiator. 626 __ popq(RCX); // Remove pushed instantiator.
637 } 627 }
638 628
639 629
640 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { 630 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
641 LocationSummary* locs = instr->locs(); 631 LocationSummary* locs = instr->locs();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
796 } 786 }
797 787
798 __ Bind(&wrong_num_arguments); 788 __ Bind(&wrong_num_arguments);
799 if (StackSize() != 0) { 789 if (StackSize() != 0) {
800 // We need to unwind the space we reserved for locals and copied parameters. 790 // We need to unwind the space we reserved for locals and copied parameters.
801 // The NoSuchMethodFunction stub does not expect to see that area on the 791 // The NoSuchMethodFunction stub does not expect to see that area on the
802 // stack. 792 // stack.
803 __ addq(RSP, Immediate(StackSize() * kWordSize)); 793 __ addq(RSP, Immediate(StackSize() * kWordSize));
804 } 794 }
805 if (function.IsClosureFunction()) { 795 if (function.IsClosureFunction()) {
806 GenerateCallRuntime(AstNode::kNoId, 796 GenerateCallRuntime(Isolate::kNoDeoptId,
807 0, 797 0,
808 CatchClauseNode::kInvalidTryIndex, 798 CatchClauseNode::kInvalidTryIndex,
809 kClosureArgumentMismatchRuntimeEntry); 799 kClosureArgumentMismatchRuntimeEntry);
810 } else { 800 } else {
811 ASSERT(!IsLeaf()); 801 ASSERT(!IsLeaf());
812 // Invoke noSuchMethod function. 802 // Invoke noSuchMethod function.
813 const int kNumArgsChecked = 1; 803 const int kNumArgsChecked = 1;
814 ICData& ic_data = ICData::ZoneHandle(); 804 ICData& ic_data = ICData::ZoneHandle();
815 ic_data = ICData::New(function, 805 ic_data = ICData::New(function,
816 String::Handle(function.name()), 806 String::Handle(function.name()),
817 AstNode::kNoId, 807 Isolate::kNoDeoptId,
818 kNumArgsChecked); 808 kNumArgsChecked);
819 __ LoadObject(RBX, ic_data); 809 __ LoadObject(RBX, ic_data);
820 // RBP - 8 : PC marker, allows easy identification of RawInstruction obj. 810 // RBP - 8 : PC marker, allows easy identification of RawInstruction obj.
821 // RBP : points to previous frame pointer. 811 // RBP : points to previous frame pointer.
822 // RBP + 8 : points to return address. 812 // RBP + 8 : points to return address.
823 // RBP + 16 : address of last argument (arg n-1). 813 // RBP + 16 : address of last argument (arg n-1).
824 // RSP + 16 + 8*(n-1) : address of first argument (arg 0). 814 // RSP + 16 + 8*(n-1) : address of first argument (arg 0).
825 // RBX : ic-data. 815 // RBX : ic-data.
826 // R10 : arguments descriptor array. 816 // R10 : arguments descriptor array.
827 __ call(&StubCode::CallNoSuchMethodFunctionLabel()); 817 __ call(&StubCode::CallNoSuchMethodFunctionLabel());
828 } 818 }
829 819
830 if (FLAG_trace_functions) { 820 if (FLAG_trace_functions) {
831 __ pushq(RAX); // Preserve result. 821 __ pushq(RAX); // Preserve result.
832 __ PushObject(Function::ZoneHandle(function.raw())); 822 __ PushObject(Function::ZoneHandle(function.raw()));
833 GenerateCallRuntime(AstNode::kNoId, 823 GenerateCallRuntime(Isolate::kNoDeoptId,
834 0, 824 0,
835 CatchClauseNode::kInvalidTryIndex, 825 CatchClauseNode::kInvalidTryIndex,
836 kTraceFunctionExitRuntimeEntry); 826 kTraceFunctionExitRuntimeEntry);
837 __ popq(RAX); // Remove argument. 827 __ popq(RAX); // Remove argument.
838 __ popq(RAX); // Restore result. 828 __ popq(RAX); // Restore result.
839 } 829 }
840 __ LeaveFrame(); 830 __ LeaveFrame();
841 __ ret(); 831 __ ret();
842 832
843 __ Bind(&all_arguments_processed); 833 __ Bind(&all_arguments_processed);
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 const bool check_arguments = function.IsClosureFunction(); 935 const bool check_arguments = function.IsClosureFunction();
946 #endif 936 #endif
947 if (check_arguments) { 937 if (check_arguments) {
948 // Check that num_fixed <= argc <= num_params. 938 // Check that num_fixed <= argc <= num_params.
949 Label argc_in_range; 939 Label argc_in_range;
950 // Total number of args is the first Smi in args descriptor array (R10). 940 // Total number of args is the first Smi in args descriptor array (R10).
951 __ movq(RAX, FieldAddress(R10, Array::data_offset())); 941 __ movq(RAX, FieldAddress(R10, Array::data_offset()));
952 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count))); 942 __ cmpq(RAX, Immediate(Smi::RawValue(parameter_count)));
953 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); 943 __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
954 if (function.IsClosureFunction()) { 944 if (function.IsClosureFunction()) {
955 GenerateCallRuntime(AstNode::kNoId, 945 GenerateCallRuntime(Isolate::kNoDeoptId,
956 function.token_pos(), 946 function.token_pos(),
957 CatchClauseNode::kInvalidTryIndex, 947 CatchClauseNode::kInvalidTryIndex,
958 kClosureArgumentMismatchRuntimeEntry); 948 kClosureArgumentMismatchRuntimeEntry);
959 } else { 949 } else {
960 __ Stop("Wrong number of arguments"); 950 __ Stop("Wrong number of arguments");
961 } 951 }
962 __ Bind(&argc_in_range); 952 __ Bind(&argc_in_range);
963 } 953 }
964 } else { 954 } else {
965 CopyParameters(); 955 CopyParameters();
(...skipping 17 matching lines...) Expand all
983 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX); 973 __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX);
984 } 974 }
985 } 975 }
986 976
987 if (!IsLeaf()) { 977 if (!IsLeaf()) {
988 // Generate stack overflow check. 978 // Generate stack overflow check.
989 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address())); 979 __ movq(RDI, Immediate(Isolate::Current()->stack_limit_address()));
990 __ cmpq(RSP, Address(RDI, 0)); 980 __ cmpq(RSP, Address(RDI, 0));
991 Label no_stack_overflow; 981 Label no_stack_overflow;
992 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); 982 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump);
993 GenerateCallRuntime(AstNode::kNoId, 983 GenerateCallRuntime(Isolate::kNoDeoptId,
994 function.token_pos(), 984 function.token_pos(),
995 CatchClauseNode::kInvalidTryIndex, 985 CatchClauseNode::kInvalidTryIndex,
996 kStackOverflowRuntimeEntry); 986 kStackOverflowRuntimeEntry);
997 __ Bind(&no_stack_overflow); 987 __ Bind(&no_stack_overflow);
998 } 988 }
999 if (FLAG_print_scopes) { 989 if (FLAG_print_scopes) {
1000 // Print the function scope (again) after generating the prologue in order 990 // Print the function scope (again) after generating the prologue in order
1001 // to see annotations such as allocation indices of locals. 991 // to see annotations such as allocation indices of locals.
1002 if (FLAG_print_ast) { 992 if (FLAG_print_ast) {
1003 // Second printing. 993 // Second printing.
1004 OS::Print("Annotated "); 994 OS::Print("Annotated ");
1005 } 995 }
1006 AstPrinter::PrintFunctionScope(parsed_function()); 996 AstPrinter::PrintFunctionScope(parsed_function());
1007 } 997 }
1008 998
1009 VisitBlocks(); 999 VisitBlocks();
1010 1000
1011 __ int3(); 1001 __ int3();
1012 GenerateDeferredCode(); 1002 GenerateDeferredCode();
1013 // Emit function patching code. This will be swapped with the first 13 bytes 1003 // Emit function patching code. This will be swapped with the first 13 bytes
1014 // at entry point. 1004 // at entry point.
1015 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode, 1005 pc_descriptors_list()->AddDescriptor(PcDescriptors::kPatchCode,
1016 assembler()->CodeSize(), 1006 assembler()->CodeSize(),
1017 AstNode::kNoId, 1007 Isolate::kNoDeoptId,
1018 0, 1008 0,
1019 -1); 1009 -1);
1020 __ jmp(&StubCode::FixCallersTargetLabel()); 1010 __ jmp(&StubCode::FixCallersTargetLabel());
1021 } 1011 }
1022 1012
1023 1013
1024 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, 1014 void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
1025 intptr_t try_index, 1015 intptr_t try_index,
1026 const ExternalLabel* label, 1016 const ExternalLabel* label,
1027 PcDescriptors::Kind kind) { 1017 PcDescriptors::Kind kind) {
1028 ASSERT(!IsLeaf()); 1018 ASSERT(!IsLeaf());
1029 ASSERT(frame_register_allocator()->IsSpilled()); 1019 ASSERT(frame_register_allocator()->IsSpilled());
1030 __ call(label); 1020 __ call(label);
1031 AddCurrentDescriptor(kind, AstNode::kNoId, token_pos, try_index); 1021 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos, try_index);
1032 } 1022 }
1033 1023
1034 1024
1035 void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid, 1025 void FlowGraphCompiler::GenerateCallRuntime(intptr_t deopt_id,
1036 intptr_t token_pos, 1026 intptr_t token_pos,
1037 intptr_t try_index, 1027 intptr_t try_index,
1038 const RuntimeEntry& entry) { 1028 const RuntimeEntry& entry) {
1039 ASSERT(!IsLeaf()); 1029 ASSERT(!IsLeaf());
1040 ASSERT(frame_register_allocator()->IsSpilled()); 1030 ASSERT(frame_register_allocator()->IsSpilled());
1041 __ CallRuntime(entry); 1031 __ CallRuntime(entry);
1042 AddCurrentDescriptor(PcDescriptors::kOther, cid, token_pos, try_index); 1032 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos, try_index);
1043 } 1033 }
1044 1034
1045 1035
1046 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, 1036 intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
1047 const ICData& ic_data, 1037 const ICData& ic_data,
1048 const Array& arguments_descriptor, 1038 const Array& arguments_descriptor,
1049 intptr_t argument_count) { 1039 intptr_t argument_count) {
1050 ASSERT(!IsLeaf()); 1040 ASSERT(!IsLeaf());
1051 __ LoadObject(RBX, ic_data); 1041 __ LoadObject(RBX, ic_data);
1052 __ LoadObject(R10, arguments_descriptor); 1042 __ LoadObject(R10, arguments_descriptor);
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { 1216 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) {
1227 __ Exchange(mem1, mem2); 1217 __ Exchange(mem1, mem2);
1228 } 1218 }
1229 1219
1230 1220
1231 #undef __ 1221 #undef __
1232 1222
1233 } // namespace dart 1223 } // namespace dart
1234 1224
1235 #endif // defined TARGET_ARCH_X64 1225 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698