| 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 "lib/error.h" |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 // - NULL -> return false. | 440 // - NULL -> return false. |
| 441 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 441 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 442 // - Class equality (only if class is not parameterized). | 442 // - Class equality (only if class is not parameterized). |
| 443 // Inputs: | 443 // Inputs: |
| 444 // - EAX: object. | 444 // - EAX: object. |
| 445 // - EDX: instantiator type arguments or raw_null. | 445 // - EDX: instantiator type arguments or raw_null. |
| 446 // - ECX: instantiator or raw_null. | 446 // - ECX: instantiator or raw_null. |
| 447 // Clobbers ECX and EDX. | 447 // Clobbers ECX and EDX. |
| 448 // Returns: | 448 // Returns: |
| 449 // - true or false in EAX. | 449 // - true or false in EAX. |
| 450 void FlowGraphCompiler::GenerateInstanceOf(intptr_t deopt_id, | 450 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
| 451 intptr_t token_pos, | |
| 452 const AbstractType& type, | 451 const AbstractType& type, |
| 453 bool negate_result, | 452 bool negate_result, |
| 454 LocationSummary* locs) { | 453 LocationSummary* locs) { |
| 455 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 454 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 456 | 455 |
| 457 const Immediate raw_null = | 456 const Immediate raw_null = |
| 458 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 457 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 459 Label is_instance, is_not_instance; | 458 Label is_instance, is_not_instance; |
| 460 __ pushl(ECX); // Store instantiator on stack. | 459 __ pushl(ECX); // Store instantiator on stack. |
| 461 __ pushl(EDX); // Store instantiator type arguments. | 460 __ pushl(EDX); // Store instantiator type arguments. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 484 // Generate runtime call. | 483 // Generate runtime call. |
| 485 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 484 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 486 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 485 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 487 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 486 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 488 __ pushl(EAX); // Push the instance. | 487 __ pushl(EAX); // Push the instance. |
| 489 __ PushObject(type); // Push the type. | 488 __ PushObject(type); // Push the type. |
| 490 __ pushl(ECX); // Instantiator. | 489 __ pushl(ECX); // Instantiator. |
| 491 __ pushl(EDX); // Instantiator type arguments. | 490 __ pushl(EDX); // Instantiator type arguments. |
| 492 __ LoadObject(EAX, test_cache); | 491 __ LoadObject(EAX, test_cache); |
| 493 __ pushl(EAX); | 492 __ pushl(EAX); |
| 494 GenerateCallRuntime(deopt_id, token_pos, kInstanceofRuntimeEntry, locs); | 493 GenerateCallRuntime(token_pos, kInstanceofRuntimeEntry, locs); |
| 495 // Pop the parameters supplied to the runtime entry. The result of the | 494 // Pop the parameters supplied to the runtime entry. The result of the |
| 496 // instanceof runtime call will be left as the result of the operation. | 495 // instanceof runtime call will be left as the result of the operation. |
| 497 __ Drop(5); | 496 __ Drop(5); |
| 498 if (negate_result) { | 497 if (negate_result) { |
| 499 __ popl(EDX); | 498 __ popl(EDX); |
| 500 __ LoadObject(EAX, bool_true()); | 499 __ LoadObject(EAX, bool_true()); |
| 501 __ cmpl(EDX, EAX); | 500 __ cmpl(EDX, EAX); |
| 502 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 501 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 503 __ LoadObject(EAX, bool_false()); | 502 __ LoadObject(EAX, bool_false()); |
| 504 } else { | 503 } else { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 523 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 522 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 524 // - Class equality (only if class is not parameterized). | 523 // - Class equality (only if class is not parameterized). |
| 525 // Inputs: | 524 // Inputs: |
| 526 // - EAX: object. | 525 // - EAX: object. |
| 527 // - EDX: instantiator type arguments or raw_null. | 526 // - EDX: instantiator type arguments or raw_null. |
| 528 // - ECX: instantiator or raw_null. | 527 // - ECX: instantiator or raw_null. |
| 529 // Returns: | 528 // Returns: |
| 530 // - object in EAX for successful assignable check (or throws TypeError). | 529 // - object in EAX for successful assignable check (or throws TypeError). |
| 531 // Performance notes: positive checks must be quick, negative checks can be slow | 530 // Performance notes: positive checks must be quick, negative checks can be slow |
| 532 // as they throw an exception. | 531 // as they throw an exception. |
| 533 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t deopt_id, | 532 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
| 534 intptr_t token_pos, | |
| 535 const AbstractType& dst_type, | 533 const AbstractType& dst_type, |
| 536 const String& dst_name, | 534 const String& dst_name, |
| 537 LocationSummary* locs) { | 535 LocationSummary* locs) { |
| 538 ASSERT(token_pos >= 0); | 536 ASSERT(token_pos >= 0); |
| 539 ASSERT(!dst_type.IsNull()); | 537 ASSERT(!dst_type.IsNull()); |
| 540 ASSERT(dst_type.IsFinalized()); | 538 ASSERT(dst_type.IsFinalized()); |
| 541 // Assignable check is skipped in FlowGraphBuilder, not here. | 539 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 542 ASSERT(dst_type.IsMalformed() || | 540 ASSERT(dst_type.IsMalformed() || |
| 543 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 541 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 544 __ pushl(ECX); // Store instantiator. | 542 __ pushl(ECX); // Store instantiator. |
| 545 __ pushl(EDX); // Store instantiator type arguments. | 543 __ pushl(EDX); // Store instantiator type arguments. |
| 546 // A null object is always assignable and is returned as result. | 544 // A null object is always assignable and is returned as result. |
| 547 const Immediate raw_null = | 545 const Immediate raw_null = |
| 548 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 546 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 549 Label is_assignable, runtime_call; | 547 Label is_assignable, runtime_call; |
| 550 __ cmpl(EAX, raw_null); | 548 __ cmpl(EAX, raw_null); |
| 551 __ j(EQUAL, &is_assignable); | 549 __ j(EQUAL, &is_assignable); |
| 552 | 550 |
| 553 // Generate throw new TypeError() if the type is malformed. | 551 // Generate throw new TypeError() if the type is malformed. |
| 554 if (dst_type.IsMalformed()) { | 552 if (dst_type.IsMalformed()) { |
| 555 const Error& error = Error::Handle(dst_type.malformed_error()); | 553 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 556 const String& error_message = String::ZoneHandle( | 554 const String& error_message = String::ZoneHandle( |
| 557 Symbols::New(error.ToErrorCString())); | 555 Symbols::New(error.ToErrorCString())); |
| 558 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 556 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 559 __ pushl(EAX); // Push the source object. | 557 __ pushl(EAX); // Push the source object. |
| 560 __ PushObject(dst_name); // Push the name of the destination. | 558 __ PushObject(dst_name); // Push the name of the destination. |
| 561 __ PushObject(error_message); | 559 __ PushObject(error_message); |
| 562 GenerateCallRuntime(deopt_id, | 560 GenerateCallRuntime(token_pos, |
| 563 token_pos, | |
| 564 kMalformedTypeErrorRuntimeEntry, | 561 kMalformedTypeErrorRuntimeEntry, |
| 565 locs); | 562 locs); |
| 566 // We should never return here. | 563 // We should never return here. |
| 567 __ int3(); | 564 __ int3(); |
| 568 | 565 |
| 569 __ Bind(&is_assignable); // For a null object. | 566 __ Bind(&is_assignable); // For a null object. |
| 570 __ popl(EDX); // Remove pushed instantiator type arguments. | 567 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 571 __ popl(ECX); // Remove pushed instantiator. | 568 __ popl(ECX); // Remove pushed instantiator. |
| 572 return; | 569 return; |
| 573 } | 570 } |
| 574 | 571 |
| 575 // Generate inline type check, linking to runtime call if not assignable. | 572 // Generate inline type check, linking to runtime call if not assignable. |
| 576 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 573 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 577 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 574 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 578 &is_assignable, &runtime_call); | 575 &is_assignable, &runtime_call); |
| 579 | 576 |
| 580 __ Bind(&runtime_call); | 577 __ Bind(&runtime_call); |
| 581 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. | 578 __ movl(EDX, Address(ESP, 0)); // Get instantiator type arguments. |
| 582 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. | 579 __ movl(ECX, Address(ESP, kWordSize)); // Get instantiator. |
| 583 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 580 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 584 __ pushl(EAX); // Push the source object. | 581 __ pushl(EAX); // Push the source object. |
| 585 __ PushObject(dst_type); // Push the type of the destination. | 582 __ PushObject(dst_type); // Push the type of the destination. |
| 586 __ pushl(ECX); // Instantiator. | 583 __ pushl(ECX); // Instantiator. |
| 587 __ pushl(EDX); // Instantiator type arguments. | 584 __ pushl(EDX); // Instantiator type arguments. |
| 588 __ PushObject(dst_name); // Push the name of the destination. | 585 __ PushObject(dst_name); // Push the name of the destination. |
| 589 __ LoadObject(EAX, test_cache); | 586 __ LoadObject(EAX, test_cache); |
| 590 __ pushl(EAX); | 587 __ pushl(EAX); |
| 591 GenerateCallRuntime(deopt_id, token_pos, kTypeCheckRuntimeEntry, locs); | 588 GenerateCallRuntime(token_pos, kTypeCheckRuntimeEntry, locs); |
| 592 // Pop the parameters supplied to the runtime entry. The result of the | 589 // Pop the parameters supplied to the runtime entry. The result of the |
| 593 // type check runtime call is the checked value. | 590 // type check runtime call is the checked value. |
| 594 __ Drop(6); | 591 __ Drop(6); |
| 595 __ popl(EAX); | 592 __ popl(EAX); |
| 596 | 593 |
| 597 __ Bind(&is_assignable); | 594 __ Bind(&is_assignable); |
| 598 __ popl(EDX); // Remove pushed instantiator type arguments. | 595 __ popl(EDX); // Remove pushed instantiator type arguments. |
| 599 __ popl(ECX); // Remove pushed instantiator. | 596 __ popl(ECX); // Remove pushed instantiator. |
| 600 } | 597 } |
| 601 | 598 |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 933 #endif | 930 #endif |
| 934 if (check_arguments) { | 931 if (check_arguments) { |
| 935 __ Comment("Check argument count"); | 932 __ Comment("Check argument count"); |
| 936 // Check that num_fixed <= argc <= num_params. | 933 // Check that num_fixed <= argc <= num_params. |
| 937 Label argc_in_range; | 934 Label argc_in_range; |
| 938 // Total number of args is the first Smi in args descriptor array (EDX). | 935 // Total number of args is the first Smi in args descriptor array (EDX). |
| 939 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); | 936 __ movl(EAX, FieldAddress(EDX, Array::data_offset())); |
| 940 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); | 937 __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count))); |
| 941 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 938 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 942 if (function.IsClosureFunction()) { | 939 if (function.IsClosureFunction()) { |
| 943 GenerateCallRuntime(Isolate::kNoDeoptId, | 940 GenerateCallRuntime(function.token_pos(), |
| 944 function.token_pos(), | |
| 945 kClosureArgumentMismatchRuntimeEntry, | 941 kClosureArgumentMismatchRuntimeEntry, |
| 946 prologue_locs); | 942 prologue_locs); |
| 947 } else { | 943 } else { |
| 948 __ Stop("Wrong number of arguments"); | 944 __ Stop("Wrong number of arguments"); |
| 949 } | 945 } |
| 950 __ Bind(&argc_in_range); | 946 __ Bind(&argc_in_range); |
| 951 } | 947 } |
| 952 // The arguments descriptor is never saved in the absence of optional | 948 // The arguments descriptor is never saved in the absence of optional |
| 953 // parameters, since any argument definition test would always yield true. | 949 // parameters, since any argument definition test would always yield true. |
| 954 ASSERT(saved_args_desc_var == NULL); | 950 ASSERT(saved_args_desc_var == NULL); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1031 } else { | 1027 } else { |
| 1032 // Add deoptimization continuation point after the call and before the | 1028 // Add deoptimization continuation point after the call and before the |
| 1033 // arguments are removed. | 1029 // arguments are removed. |
| 1034 AddCurrentDescriptor(PcDescriptors::kDeoptAfter, | 1030 AddCurrentDescriptor(PcDescriptors::kDeoptAfter, |
| 1035 deopt_id, | 1031 deopt_id, |
| 1036 token_pos); | 1032 token_pos); |
| 1037 } | 1033 } |
| 1038 } | 1034 } |
| 1039 | 1035 |
| 1040 | 1036 |
| 1041 void FlowGraphCompiler::GenerateCallRuntime(intptr_t deopt_id, | 1037 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, |
| 1042 intptr_t token_pos, | |
| 1043 const RuntimeEntry& entry, | 1038 const RuntimeEntry& entry, |
| 1044 LocationSummary* locs) { | 1039 LocationSummary* locs) { |
| 1045 ASSERT(!IsLeaf()); | 1040 ASSERT(!IsLeaf()); |
| 1046 __ CallRuntime(entry); | 1041 __ CallRuntime(entry); |
| 1047 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | 1042 AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| 1048 RecordSafepoint(locs); | 1043 RecordSafepoint(locs); |
| 1049 } | 1044 } |
| 1050 | 1045 |
| 1051 | 1046 |
| 1052 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 1047 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 1053 const ICData& ic_data, | 1048 const ICData& ic_data, |
| 1054 const Array& arguments_descriptor, | 1049 const Array& arguments_descriptor, |
| 1055 intptr_t argument_count, | 1050 intptr_t argument_count, |
| 1056 intptr_t deopt_id, | 1051 intptr_t deopt_id, |
| 1057 intptr_t token_pos, | 1052 intptr_t token_pos, |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 __ popl(ECX); | 1314 __ popl(ECX); |
| 1320 __ popl(EAX); | 1315 __ popl(EAX); |
| 1321 } | 1316 } |
| 1322 | 1317 |
| 1323 | 1318 |
| 1324 #undef __ | 1319 #undef __ |
| 1325 | 1320 |
| 1326 } // namespace dart | 1321 } // namespace dart |
| 1327 | 1322 |
| 1328 #endif // defined TARGET_ARCH_IA32 | 1323 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |