| OLD | NEW |
| 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 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 "vm/ast_printer.h" | 11 #include "vm/ast_printer.h" |
| 11 #include "vm/compiler_stats.h" | 12 #include "vm/compiler_stats.h" |
| 12 #include "vm/il_printer.h" | 13 #include "vm/il_printer.h" |
| 13 #include "vm/locations.h" | 14 #include "vm/locations.h" |
| 14 #include "vm/stub_code.h" | 15 #include "vm/stub_code.h" |
| 15 | 16 |
| 16 namespace dart { | 17 namespace dart { |
| 17 | 18 |
| 18 DECLARE_FLAG(bool, code_comments); | 19 DECLARE_FLAG(bool, code_comments); |
| 19 DECLARE_FLAG(bool, compiler_stats); | 20 DECLARE_FLAG(bool, compiler_stats); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 | 402 |
| 402 void FlowGraphCompiler::GenerateCall(intptr_t token_index, | 403 void FlowGraphCompiler::GenerateCall(intptr_t token_index, |
| 403 intptr_t try_index, | 404 intptr_t try_index, |
| 404 const ExternalLabel* label, | 405 const ExternalLabel* label, |
| 405 PcDescriptors::Kind kind) { | 406 PcDescriptors::Kind kind) { |
| 406 __ call(label); | 407 __ call(label); |
| 407 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); | 408 AddCurrentDescriptor(kind, AstNode::kNoId, token_index, try_index); |
| 408 } | 409 } |
| 409 | 410 |
| 410 | 411 |
| 412 // If instanceof type test cannot be performed successfully at compile time and |
| 413 // therefore eliminated, optimize it by adding inlined tests for: |
| 414 // - NULL -> return false. |
| 415 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 416 // - Class equality (only if class is not parameterized). |
| 417 // Inputs: |
| 418 // - EAX: object. |
| 419 // - EDX: instantiator type arguments or raw_null. |
| 420 // - ECX: instantiator or raw_null. |
| 421 // Returns: |
| 422 // - true or false in EAX. |
| 423 void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid, |
| 424 intptr_t token_index, |
| 425 intptr_t try_index, |
| 426 const AbstractType& type, |
| 427 bool negate_result) { |
| 428 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 429 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 430 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 431 |
| 432 const Immediate raw_null = |
| 433 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 434 Label is_instance, is_not_instance; |
| 435 __ pushl(ECX); // Store instantiator on stack. |
| 436 __ pushl(EDX); // Store instantiator type arguments. |
| 437 // If type is instantiated and non-parameterized, we can inline code |
| 438 // checking whether the tested instance is a Smi. |
| 439 if (type.IsInstantiated()) { |
| 440 // A null object is only an instance of Object and Dynamic, which has |
| 441 // already been checked above (if the type is instantiated). So we can |
| 442 // return false here if the instance is null (and if the type is |
| 443 // instantiated). |
| 444 // We can only inline this null check if the type is instantiated at compile |
| 445 // time, since an uninstantiated type at compile time could be Object or |
| 446 // Dynamic at run time. |
| 447 __ cmpl(EAX, raw_null); |
| 448 __ j(EQUAL, &is_not_instance); |
| 449 } |
| 450 // TODO(srdjan): Enable inlined checks. |
| 451 // Generate inline instanceof test. |
| 452 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 453 // test_cache = GenerateInlineInstanceof(cid, token_index, type, |
| 454 // &is_instance, &is_not_instance); |
| 455 |
| 456 // Generate runtime call. |
| 457 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 458 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 459 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 460 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 461 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
| 462 __ pushl(EAX); // Push the instance. |
| 463 __ PushObject(type); // Push the type. |
| 464 __ pushl(ECX); // TODO(srdjan): Pass instantiator instead of null. |
| 465 __ pushl(EDX); // Instantiator type arguments. |
| 466 __ LoadObject(EAX, test_cache); |
| 467 __ pushl(EAX); |
| 468 GenerateCallRuntime(cid, token_index, try_index, kInstanceofRuntimeEntry); |
| 469 // Pop the two parameters supplied to the runtime entry. The result of the |
| 470 // instanceof runtime call will be left as the result of the operation. |
| 471 __ Drop(7); |
| 472 Label done; |
| 473 if (negate_result) { |
| 474 __ popl(EDX); |
| 475 __ LoadObject(EAX, bool_true); |
| 476 __ cmpl(EDX, EAX); |
| 477 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 478 __ LoadObject(EAX, bool_false); |
| 479 } else { |
| 480 __ popl(EAX); |
| 481 } |
| 482 __ jmp(&done, Assembler::kNearJump); |
| 483 |
| 484 __ Bind(&is_not_instance); |
| 485 __ LoadObject(EAX, negate_result ? bool_true : bool_false); |
| 486 __ jmp(&done, Assembler::kNearJump); |
| 487 |
| 488 __ Bind(&is_instance); |
| 489 __ LoadObject(EAX, negate_result ? bool_false : bool_true); |
| 490 __ Bind(&done); |
| 491 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 492 __ popl(ECX); // Remove pushed instantiator. |
| 493 } |
| 494 |
| 495 |
| 496 // Optimize assignable type check by adding inlined tests for: |
| 497 // - NULL -> return NULL. |
| 498 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 499 // - Class equality (only if class is not parameterized). |
| 500 // Inputs: |
| 501 // - EAX: object. |
| 502 // - EDX: instantiator type arguments or raw_null. |
| 503 // - ECX: instantiator or raw_null. |
| 504 // Returns: |
| 505 // - object in EAX for successful assignable check (or throws TypeError). |
| 506 // Performance notes: positive checks must be quick, negative checks can be slow |
| 507 // as they throw an exception. |
| 508 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t cid, |
| 509 intptr_t token_index, |
| 510 intptr_t try_index, |
| 511 const AbstractType& dst_type, |
| 512 const String& dst_name) { |
| 513 ASSERT(FLAG_enable_type_checks); |
| 514 ASSERT(token_index >= 0); |
| 515 ASSERT(!dst_type.IsNull()); |
| 516 ASSERT(dst_type.IsFinalized()); |
| 517 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 518 ASSERT(dst_type.IsMalformed() || |
| 519 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 520 ASSERT(!dst_type.IsVoidType()); |
| 521 __ pushl(ECX); // Store instantiator. |
| 522 __ pushl(EDX); // Store instantiator type arguments. |
| 523 // A null object is always assignable and is returned as result. |
| 524 const Immediate raw_null = |
| 525 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 526 Label is_assignable, runtime_call; |
| 527 __ cmpl(EAX, raw_null); |
| 528 __ j(EQUAL, &is_assignable); |
| 529 |
| 530 // Generate throw new TypeError() if the type is malformed. |
| 531 if (dst_type.IsMalformed()) { |
| 532 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 533 const String& error_message = String::ZoneHandle( |
| 534 String::NewSymbol(error.ToErrorCString())); |
| 535 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 536 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 537 __ pushl(EAX); // Push the source object. |
| 538 __ PushObject(dst_name); // Push the name of the destination. |
| 539 __ PushObject(error_message); |
| 540 GenerateCallRuntime(cid, |
| 541 token_index, |
| 542 try_index, |
| 543 kMalformedTypeErrorRuntimeEntry); |
| 544 // We should never return here. |
| 545 __ int3(); |
| 546 |
| 547 __ Bind(&is_assignable); // For a null object. |
| 548 return; |
| 549 } |
| 550 |
| 551 // TODO(srdjan): Enable subtype test cache. |
| 552 // Generate inline type check, linking to runtime call if not assignable. |
| 553 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 554 // test_cache = GenerateInlineInstanceof(cid, token_index, dst_type, |
| 555 // &is_assignable, &runtime_call); |
| 556 |
| 557 __ Bind(&runtime_call); |
| 558 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 559 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 560 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 561 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 562 __ pushl(Immediate(Smi::RawValue(cid))); // Computation id. |
| 563 __ pushl(EAX); // Push the source object. |
| 564 __ PushObject(dst_type); // Push the type of the destination. |
| 565 __ pushl(ECX); // Instantiator. |
| 566 __ pushl(EDX); // Instantiator type arguments. |
| 567 __ PushObject(dst_name); // Push the name of the destination. |
| 568 __ LoadObject(EAX, test_cache); |
| 569 __ pushl(EAX); |
| 570 GenerateCallRuntime(cid, |
| 571 token_index, |
| 572 try_index, |
| 573 kTypeCheckRuntimeEntry); |
| 574 // Pop the parameters supplied to the runtime entry. The result of the |
| 575 // type check runtime call is the checked value. |
| 576 __ Drop(8); |
| 577 __ popl(EAX); |
| 578 |
| 579 __ Bind(&is_assignable); |
| 580 __ popl(EDX); // Remove pushed instantiator type arguments.. |
| 581 __ popl(ECX); // Remove pushed instantiator. |
| 582 } |
| 583 |
| 584 |
| 411 void FlowGraphCompiler::EmitComment(Instruction* instr) { | 585 void FlowGraphCompiler::EmitComment(Instruction* instr) { |
| 412 char buffer[80]; | 586 char buffer[80]; |
| 413 BufferFormatter f(buffer, sizeof(buffer)); | 587 BufferFormatter f(buffer, sizeof(buffer)); |
| 414 instr->PrintTo(&f); | 588 instr->PrintTo(&f); |
| 415 __ Comment("@%d: %s", instr->cid(), buffer); | 589 __ Comment("@%d: %s", instr->cid(), buffer); |
| 416 } | 590 } |
| 417 | 591 |
| 418 | 592 |
| 419 void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) { | 593 void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) { |
| 420 char buffer[80]; | 594 char buffer[80]; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 468 } | 642 } |
| 469 } | 643 } |
| 470 } | 644 } |
| 471 } | 645 } |
| 472 | 646 |
| 473 #undef __ | 647 #undef __ |
| 474 | 648 |
| 475 } // namespace dart | 649 } // namespace dart |
| 476 | 650 |
| 477 #endif // defined TARGET_ARCH_IA32 | 651 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |