| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 | 159 |
| 160 #define __ assembler()-> | 160 #define __ assembler()-> |
| 161 | 161 |
| 162 | 162 |
| 163 // Fall through if bool_register contains null. | 163 // Fall through if bool_register contains null. |
| 164 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 164 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 165 Label* is_true, | 165 Label* is_true, |
| 166 Label* is_false) { | 166 Label* is_false) { |
| 167 __ TraceSimMsg("BoolToJump"); | 167 __ TraceSimMsg("BoolToJump"); |
| 168 Label fall_through; | 168 Label fall_through; |
| 169 __ beq(bool_register, NULLREG, &fall_through); | 169 __ BranchEqual(bool_register, reinterpret_cast<int32_t>(Object::null()), |
| 170 &fall_through); |
| 170 __ BranchEqual(bool_register, Bool::True(), is_true); | 171 __ BranchEqual(bool_register, Bool::True(), is_true); |
| 171 __ b(is_false); | 172 __ b(is_false); |
| 172 __ Bind(&fall_through); | 173 __ Bind(&fall_through); |
| 173 } | 174 } |
| 174 | 175 |
| 175 | 176 |
| 176 // A0: instance (must be preserved). | 177 // A0: instance (must be preserved). |
| 177 // A1: instantiator type arguments (if used). | 178 // A1: instantiator type arguments (if used). |
| 178 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 179 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 179 TypeTestStubKind test_kind, | 180 TypeTestStubKind test_kind, |
| 180 Register instance_reg, | 181 Register instance_reg, |
| 181 Register type_arguments_reg, | 182 Register type_arguments_reg, |
| 182 Register temp_reg, | 183 Register temp_reg, |
| 183 Label* is_instance_lbl, | 184 Label* is_instance_lbl, |
| 184 Label* is_not_instance_lbl) { | 185 Label* is_not_instance_lbl) { |
| 185 __ TraceSimMsg("CallSubtypeTestStub"); | 186 __ TraceSimMsg("CallSubtypeTestStub"); |
| 186 ASSERT(instance_reg == A0); | 187 ASSERT(instance_reg == A0); |
| 187 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 188 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
| 188 const SubtypeTestCache& type_test_cache = | 189 const SubtypeTestCache& type_test_cache = |
| 189 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 190 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 190 __ LoadObject(A2, type_test_cache); | 191 __ LoadObject(A2, type_test_cache); |
| 191 if (test_kind == kTestTypeOneArg) { | 192 if (test_kind == kTestTypeOneArg) { |
| 192 ASSERT(type_arguments_reg == kNoRegister); | 193 ASSERT(type_arguments_reg == kNoRegister); |
| 194 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); |
| 193 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 195 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 194 __ delay_slot()->mov(A1, NULLREG); | |
| 195 } else if (test_kind == kTestTypeTwoArgs) { | 196 } else if (test_kind == kTestTypeTwoArgs) { |
| 196 ASSERT(type_arguments_reg == kNoRegister); | 197 ASSERT(type_arguments_reg == kNoRegister); |
| 198 __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null())); |
| 197 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 199 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 198 __ delay_slot()->mov(A1, NULLREG); | |
| 199 } else if (test_kind == kTestTypeThreeArgs) { | 200 } else if (test_kind == kTestTypeThreeArgs) { |
| 200 ASSERT(type_arguments_reg == A1); | 201 ASSERT(type_arguments_reg == A1); |
| 201 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); | 202 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); |
| 202 } else { | 203 } else { |
| 203 UNREACHABLE(); | 204 UNREACHABLE(); |
| 204 } | 205 } |
| 205 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. | 206 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. |
| 206 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); | 207 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); |
| 207 return type_test_cache.raw(); | 208 return type_test_cache.raw(); |
| 208 } | 209 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 // Bool interface can be implemented only by core class Bool. | 323 // Bool interface can be implemented only by core class Bool. |
| 323 if (type.IsBoolType()) { | 324 if (type.IsBoolType()) { |
| 324 __ BranchEqual(kClassIdReg, kBoolCid, is_instance_lbl); | 325 __ BranchEqual(kClassIdReg, kBoolCid, is_instance_lbl); |
| 325 __ b(is_not_instance_lbl); | 326 __ b(is_not_instance_lbl); |
| 326 return false; | 327 return false; |
| 327 } | 328 } |
| 328 if (type.IsFunctionType()) { | 329 if (type.IsFunctionType()) { |
| 329 // Check if instance is a closure. | 330 // Check if instance is a closure. |
| 330 __ LoadClassById(T1, kClassIdReg); | 331 __ LoadClassById(T1, kClassIdReg); |
| 331 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); | 332 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); |
| 332 __ bne(T1, NULLREG, is_instance_lbl); | 333 __ BranchNotEqual(T1, reinterpret_cast<int32_t>(Object::null()), |
| 334 is_instance_lbl); |
| 333 } | 335 } |
| 334 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 336 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 335 // Note that instance is not Smi (checked above). | 337 // Note that instance is not Smi (checked above). |
| 336 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 338 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 337 GenerateNumberTypeCheck( | 339 GenerateNumberTypeCheck( |
| 338 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 340 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 339 return false; | 341 return false; |
| 340 } | 342 } |
| 341 if (type.IsStringType()) { | 343 if (type.IsStringType()) { |
| 342 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 344 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 __ TraceSimMsg("UninstantiatedTypeTest"); | 392 __ TraceSimMsg("UninstantiatedTypeTest"); |
| 391 __ Comment("UninstantiatedTypeTest"); | 393 __ Comment("UninstantiatedTypeTest"); |
| 392 ASSERT(!type.IsInstantiated()); | 394 ASSERT(!type.IsInstantiated()); |
| 393 // Skip check if destination is a dynamic type. | 395 // Skip check if destination is a dynamic type. |
| 394 if (type.IsTypeParameter()) { | 396 if (type.IsTypeParameter()) { |
| 395 const TypeParameter& type_param = TypeParameter::Cast(type); | 397 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 396 // Load instantiator (or null) and instantiator type arguments on stack. | 398 // Load instantiator (or null) and instantiator type arguments on stack. |
| 397 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 399 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
| 398 // A1: instantiator type arguments. | 400 // A1: instantiator type arguments. |
| 399 // Check if type argument is dynamic. | 401 // Check if type argument is dynamic. |
| 400 __ beq(A1, NULLREG, is_instance_lbl); | 402 __ LoadImmediate(T7, reinterpret_cast<int32_t>(Object::null())); |
| 403 __ beq(A1, T7, is_instance_lbl); |
| 401 // Can handle only type arguments that are instances of TypeArguments. | 404 // Can handle only type arguments that are instances of TypeArguments. |
| 402 // (runtime checks canonicalize type arguments). | 405 // (runtime checks canonicalize type arguments). |
| 403 Label fall_through; | 406 Label fall_through; |
| 404 __ LoadClassId(T2, A1); | 407 __ LoadClassId(T2, A1); |
| 405 __ BranchNotEqual(T2, kTypeArgumentsCid, &fall_through); | 408 __ BranchNotEqual(T2, kTypeArgumentsCid, &fall_through); |
| 406 __ lw(T2, | 409 __ lw(T2, |
| 407 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); | 410 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); |
| 408 // R2: concrete type of type. | 411 // R2: concrete type of type. |
| 409 // Check if type argument is dynamic. | 412 // Check if type argument is dynamic. |
| 410 __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl); | 413 __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl); |
| 411 __ beq(T2, NULLREG, is_instance_lbl); | 414 __ beq(T2, T7, is_instance_lbl); |
| 412 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 415 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
| 413 __ BranchEqual(T2, object_type, is_instance_lbl); | 416 __ BranchEqual(T2, object_type, is_instance_lbl); |
| 414 | 417 |
| 415 // For Smi check quickly against int and num interfaces. | 418 // For Smi check quickly against int and num interfaces. |
| 416 Label not_smi; | 419 Label not_smi; |
| 417 __ andi(CMPRES, A0, Immediate(kSmiTagMask)); | 420 __ andi(CMPRES, A0, Immediate(kSmiTagMask)); |
| 418 __ bne(CMPRES, ZR, ¬_smi); // Value is Smi? | 421 __ bne(CMPRES, ZR, ¬_smi); // Value is Smi? |
| 419 __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl); | 422 __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl); |
| 420 __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl); | 423 __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl); |
| 421 | 424 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 __ TraceSimMsg("InlineInstanceof"); | 479 __ TraceSimMsg("InlineInstanceof"); |
| 477 __ Comment("InlineInstanceof"); | 480 __ Comment("InlineInstanceof"); |
| 478 if (type.IsVoidType()) { | 481 if (type.IsVoidType()) { |
| 479 // A non-null value is returned from a void function, which will result in a | 482 // A non-null value is returned from a void function, which will result in a |
| 480 // type error. A null value is handled prior to executing this inline code. | 483 // type error. A null value is handled prior to executing this inline code. |
| 481 return SubtypeTestCache::null(); | 484 return SubtypeTestCache::null(); |
| 482 } | 485 } |
| 483 if (TypeCheckAsClassEquality(type)) { | 486 if (TypeCheckAsClassEquality(type)) { |
| 484 const intptr_t type_cid = Class::Handle(type.type_class()).id(); | 487 const intptr_t type_cid = Class::Handle(type.type_class()).id(); |
| 485 const Register kInstanceReg = A0; | 488 const Register kInstanceReg = A0; |
| 486 __ andi(T0, kInstanceReg, Immediate(kSmiTagMask)); | 489 __ andi(CMPRES, kInstanceReg, Immediate(kSmiTagMask)); |
| 487 if (type_cid == kSmiCid) { | 490 if (type_cid == kSmiCid) { |
| 488 __ beq(T0, ZR, is_instance_lbl); | 491 __ beq(CMPRES, ZR, is_instance_lbl); |
| 489 } else { | 492 } else { |
| 490 __ beq(T0, ZR, is_not_instance_lbl); | 493 __ beq(CMPRES, ZR, is_not_instance_lbl); |
| 491 __ LoadClassId(T0, kInstanceReg); | 494 __ LoadClassId(T0, kInstanceReg); |
| 492 __ BranchEqual(T0, type_cid, is_instance_lbl); | 495 __ BranchEqual(T0, type_cid, is_instance_lbl); |
| 493 } | 496 } |
| 494 __ b(is_not_instance_lbl); | 497 __ b(is_not_instance_lbl); |
| 495 return SubtypeTestCache::null(); | 498 return SubtypeTestCache::null(); |
| 496 } | 499 } |
| 497 if (type.IsInstantiated()) { | 500 if (type.IsInstantiated()) { |
| 498 const Class& type_class = Class::ZoneHandle(type.type_class()); | 501 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 499 // A Smi object cannot be the instance of a parameterized class. | 502 // A Smi object cannot be the instance of a parameterized class. |
| 500 // A class equality check is only applicable with a dst type of a | 503 // A class equality check is only applicable with a dst type of a |
| (...skipping 19 matching lines...) Expand all Loading... |
| 520 return SubtypeTestCache::null(); | 523 return SubtypeTestCache::null(); |
| 521 } | 524 } |
| 522 } | 525 } |
| 523 return GenerateUninstantiatedTypeTest(token_pos, | 526 return GenerateUninstantiatedTypeTest(token_pos, |
| 524 type, | 527 type, |
| 525 is_instance_lbl, | 528 is_instance_lbl, |
| 526 is_not_instance_lbl); | 529 is_not_instance_lbl); |
| 527 } | 530 } |
| 528 | 531 |
| 529 | 532 |
| 533 // If instanceof type test cannot be performed successfully at compile time and |
| 534 // therefore eliminated, optimize it by adding inlined tests for: |
| 535 // - NULL -> return false. |
| 536 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 537 // - Class equality (only if class is not parameterized). |
| 538 // Inputs: |
| 539 // - A0: object. |
| 540 // - A1: instantiator type arguments or raw_null. |
| 541 // - A2: instantiator or raw_null. |
| 542 // Returns: |
| 543 // - true or false in V0. |
| 530 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 544 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
| 531 intptr_t deopt_id, | 545 intptr_t deopt_id, |
| 532 const AbstractType& type, | 546 const AbstractType& type, |
| 533 bool negate_result, | 547 bool negate_result, |
| 534 LocationSummary* locs) { | 548 LocationSummary* locs) { |
| 535 UNIMPLEMENTED(); | 549 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 550 |
| 551 // Preserve instantiator (A2) and its type arguments (A1). |
| 552 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 553 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 554 __ sw(A1, Address(SP, 0 * kWordSize)); |
| 555 |
| 556 Label is_instance, is_not_instance; |
| 557 // If type is instantiated and non-parameterized, we can inline code |
| 558 // checking whether the tested instance is a Smi. |
| 559 if (type.IsInstantiated()) { |
| 560 // A null object is only an instance of Object and dynamic, which has |
| 561 // already been checked above (if the type is instantiated). So we can |
| 562 // return false here if the instance is null (and if the type is |
| 563 // instantiated). |
| 564 // We can only inline this null check if the type is instantiated at compile |
| 565 // time, since an uninstantiated type at compile time could be Object or |
| 566 // dynamic at run time. |
| 567 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), |
| 568 &is_not_instance); |
| 569 } |
| 570 |
| 571 // Generate inline instanceof test. |
| 572 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 573 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 574 &is_instance, &is_not_instance); |
| 575 |
| 576 // test_cache is null if there is no fall-through. |
| 577 Label done; |
| 578 if (!test_cache.IsNull()) { |
| 579 // Generate runtime call. |
| 580 // Load instantiator (A2) and its type arguments (A1). |
| 581 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 582 __ lw(A2, Address(SP, 1 * kWordSize)); |
| 583 |
| 584 __ addiu(SP, SP, Immediate(-6 * kWordSize)); |
| 585 __ LoadObject(TMP, Object::ZoneHandle()); |
| 586 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. |
| 587 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the instance. |
| 588 __ LoadObject(TMP, type); |
| 589 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type. |
| 590 __ sw(A2, Address(SP, 2 * kWordSize)); // Push instantiator. |
| 591 __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. |
| 592 __ LoadObject(A0, test_cache); |
| 593 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 594 GenerateCallRuntime(token_pos, deopt_id, kInstanceofRuntimeEntry, locs); |
| 595 // Pop the parameters supplied to the runtime entry. The result of the |
| 596 // instanceof runtime call will be left as the result of the operation. |
| 597 __ lw(T0, Address(SP, 5 * kWordSize)); |
| 598 __ addiu(SP, SP, Immediate(6 * kWordSize)); |
| 599 if (negate_result) { |
| 600 __ LoadObject(V0, Bool::True()); |
| 601 __ bne(T0, V0, &done); |
| 602 __ LoadObject(V0, Bool::False()); |
| 603 } else { |
| 604 __ mov(V0, T0); |
| 605 } |
| 606 __ b(&done); |
| 607 } |
| 608 __ Bind(&is_not_instance); |
| 609 __ LoadObject(V0, negate_result ? Bool::True() : Bool::False()); |
| 610 __ b(&done); |
| 611 |
| 612 __ Bind(&is_instance); |
| 613 __ LoadObject(V0, negate_result ? Bool::False() : Bool::True()); |
| 614 __ Bind(&done); |
| 615 // Remove instantiator (A2) and its type arguments (A1). |
| 616 __ Drop(2); |
| 536 } | 617 } |
| 537 | 618 |
| 538 | 619 |
| 539 // Optimize assignable type check by adding inlined tests for: | 620 // Optimize assignable type check by adding inlined tests for: |
| 540 // - NULL -> return NULL. | 621 // - NULL -> return NULL. |
| 541 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 622 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 542 // - Class equality (only if class is not parameterized). | 623 // - Class equality (only if class is not parameterized). |
| 543 // Inputs: | 624 // Inputs: |
| 544 // - A0: instance being type checked. | 625 // - A0: instance being type checked. |
| 545 // - A1: instantiator type arguments or raw_null. | 626 // - A1: instantiator type arguments or raw_null. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 560 ASSERT(dst_type.IsFinalized()); | 641 ASSERT(dst_type.IsFinalized()); |
| 561 // Assignable check is skipped in FlowGraphBuilder, not here. | 642 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 562 ASSERT(dst_type.IsMalformed() || | 643 ASSERT(dst_type.IsMalformed() || |
| 563 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 644 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 564 // Preserve instantiator and its type arguments. | 645 // Preserve instantiator and its type arguments. |
| 565 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 646 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 566 __ sw(A2, Address(SP, 1 * kWordSize)); | 647 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 567 | 648 |
| 568 // A null object is always assignable and is returned as result. | 649 // A null object is always assignable and is returned as result. |
| 569 Label is_assignable, runtime_call; | 650 Label is_assignable, runtime_call; |
| 570 __ beq(A0, NULLREG, &is_assignable); | 651 |
| 652 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable); |
| 571 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); | 653 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
| 572 | 654 |
| 573 if (!FLAG_eliminate_type_checks) { | 655 if (!FLAG_eliminate_type_checks) { |
| 574 // If type checks are not eliminated during the graph building then | 656 // If type checks are not eliminated during the graph building then |
| 575 // a transition sentinel can be seen here. | 657 // a transition sentinel can be seen here. |
| 576 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); | 658 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); |
| 577 } | 659 } |
| 578 | 660 |
| 579 // Generate throw new TypeError() if the type is malformed. | 661 // Generate throw new TypeError() if the type is malformed. |
| 580 if (dst_type.IsMalformed()) { | 662 if (dst_type.IsMalformed()) { |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 // We do not use the final allocation index of the variable here, i.e. | 879 // We do not use the final allocation index of the variable here, i.e. |
| 798 // scope->VariableAt(i)->index(), because captured variables still need | 880 // scope->VariableAt(i)->index(), because captured variables still need |
| 799 // to be copied to the context that is not yet allocated. | 881 // to be copied to the context that is not yet allocated. |
| 800 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 882 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 801 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 883 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 802 } | 884 } |
| 803 delete[] opt_param; | 885 delete[] opt_param; |
| 804 delete[] opt_param_position; | 886 delete[] opt_param_position; |
| 805 // Check that T0 now points to the null terminator in the array descriptor. | 887 // Check that T0 now points to the null terminator in the array descriptor. |
| 806 __ lw(T3, Address(T0)); | 888 __ lw(T3, Address(T0)); |
| 807 __ beq(T3, NULLREG, &all_arguments_processed); | 889 __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()), |
| 890 &all_arguments_processed); |
| 808 } else { | 891 } else { |
| 809 ASSERT(num_opt_pos_params > 0); | 892 ASSERT(num_opt_pos_params > 0); |
| 810 __ Comment("There are optional positional parameters"); | 893 __ Comment("There are optional positional parameters"); |
| 811 __ lw(T2, | 894 __ lw(T2, |
| 812 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 895 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 813 __ SmiUntag(T2); | 896 __ SmiUntag(T2); |
| 814 for (int i = 0; i < num_opt_pos_params; i++) { | 897 for (int i = 0; i < num_opt_pos_params; i++) { |
| 815 Label next_parameter; | 898 Label next_parameter; |
| 816 // Handle this optional positional parameter only if k or fewer positional | 899 // Handle this optional positional parameter only if k or fewer positional |
| 817 // arguments have been passed, where k is param_pos, the position of this | 900 // arguments have been passed, where k is param_pos, the position of this |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 887 __ sll(T2, T2, 1); // T2 is a Smi. | 970 __ sll(T2, T2, 1); // T2 is a Smi. |
| 888 | 971 |
| 889 __ Comment("Null arguments loop"); | 972 __ Comment("Null arguments loop"); |
| 890 Label null_args_loop, null_args_loop_exit; | 973 Label null_args_loop, null_args_loop_exit; |
| 891 __ blez(T2, &null_args_loop_exit); | 974 __ blez(T2, &null_args_loop_exit); |
| 892 __ delay_slot()->addiu(T1, FP, | 975 __ delay_slot()->addiu(T1, FP, |
| 893 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); | 976 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); |
| 894 __ Bind(&null_args_loop); | 977 __ Bind(&null_args_loop); |
| 895 __ addiu(T2, T2, Immediate(-kWordSize)); | 978 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 896 __ addu(T3, T1, T2); | 979 __ addu(T3, T1, T2); |
| 980 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); |
| 897 __ bgtz(T2, &null_args_loop); | 981 __ bgtz(T2, &null_args_loop); |
| 898 __ delay_slot()->sw(NULLREG, Address(T3)); | 982 __ delay_slot()->sw(TMP, Address(T3)); |
| 899 __ Bind(&null_args_loop_exit); | 983 __ Bind(&null_args_loop_exit); |
| 900 } | 984 } |
| 901 | 985 |
| 902 | 986 |
| 903 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 987 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 904 // RA: return address. | 988 // RA: return address. |
| 905 // SP: receiver. | 989 // SP: receiver. |
| 906 // Sequence node has one return node, its input is load field node. | 990 // Sequence node has one return node, its input is load field node. |
| 907 __ lw(V0, Address(SP, 0 * kWordSize)); | 991 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 908 __ lw(V0, Address(V0, offset - kHeapObjectTag)); | 992 __ lw(V0, Address(V0, offset - kHeapObjectTag)); |
| 909 __ Ret(); | 993 __ Ret(); |
| 910 } | 994 } |
| 911 | 995 |
| 912 | 996 |
| 913 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 997 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 914 // RA: return address. | 998 // RA: return address. |
| 915 // SP+1: receiver. | 999 // SP+1: receiver. |
| 916 // SP+0: value. | 1000 // SP+0: value. |
| 917 // Sequence node has one store node and one return NULL node. | 1001 // Sequence node has one store node and one return NULL node. |
| 918 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 1002 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 919 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 1003 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 920 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); | 1004 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 1005 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); |
| 921 __ Ret(); | 1006 __ Ret(); |
| 922 __ delay_slot()->mov(V0, NULLREG); | 1007 __ delay_slot()->mov(V0, TMP); |
| 923 } | 1008 } |
| 924 | 1009 |
| 925 | 1010 |
| 926 void FlowGraphCompiler::EmitFrameEntry() { | 1011 void FlowGraphCompiler::EmitFrameEntry() { |
| 927 const Function& function = parsed_function().function(); | 1012 const Function& function = parsed_function().function(); |
| 928 if (CanOptimizeFunction() && function.is_optimizable()) { | 1013 if (CanOptimizeFunction() && function.is_optimizable()) { |
| 929 const bool can_optimize = !is_optimizing() || may_reoptimize(); | 1014 const bool can_optimize = !is_optimizing() || may_reoptimize(); |
| 930 const Register function_reg = T0; | 1015 const Register function_reg = T0; |
| 931 if (can_optimize) { | 1016 if (can_optimize) { |
| 932 Label next; | 1017 Label next; |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1106 } | 1191 } |
| 1107 | 1192 |
| 1108 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1193 // In unoptimized code, initialize (non-argument) stack allocated slots to |
| 1109 // null. This does not cover the saved_args_desc_var slot. | 1194 // null. This does not cover the saved_args_desc_var slot. |
| 1110 if (!is_optimizing() && (num_locals > 0)) { | 1195 if (!is_optimizing() && (num_locals > 0)) { |
| 1111 __ TraceSimMsg("Initialize spill slots"); | 1196 __ TraceSimMsg("Initialize spill slots"); |
| 1112 __ Comment("Initialize spill slots"); | 1197 __ Comment("Initialize spill slots"); |
| 1113 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1198 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
| 1114 for (intptr_t i = 0; i < num_locals; ++i) { | 1199 for (intptr_t i = 0; i < num_locals; ++i) { |
| 1115 // Subtract index i (locals lie at lower addresses than FP). | 1200 // Subtract index i (locals lie at lower addresses than FP). |
| 1116 __ sw(NULLREG, Address(FP, (slot_base - i) * kWordSize)); | 1201 __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null())); |
| 1202 __ sw(TMP, Address(FP, (slot_base - i) * kWordSize)); |
| 1117 } | 1203 } |
| 1118 } | 1204 } |
| 1119 | 1205 |
| 1120 if (FLAG_print_scopes) { | 1206 if (FLAG_print_scopes) { |
| 1121 // Print the function scope (again) after generating the prologue in order | 1207 // Print the function scope (again) after generating the prologue in order |
| 1122 // to see annotations such as allocation indices of locals. | 1208 // to see annotations such as allocation indices of locals. |
| 1123 if (FLAG_print_ast) { | 1209 if (FLAG_print_ast) { |
| 1124 // Second printing. | 1210 // Second printing. |
| 1125 OS::Print("Annotated "); | 1211 OS::Print("Annotated "); |
| 1126 } | 1212 } |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1341 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, | 1427 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, |
| 1342 const Object& obj, | 1428 const Object& obj, |
| 1343 bool needs_number_check, | 1429 bool needs_number_check, |
| 1344 intptr_t token_pos) { | 1430 intptr_t token_pos) { |
| 1345 __ TraceSimMsg("EqualityRegConstCompare"); | 1431 __ TraceSimMsg("EqualityRegConstCompare"); |
| 1346 if (needs_number_check && | 1432 if (needs_number_check && |
| 1347 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { | 1433 (obj.IsMint() || obj.IsDouble() || obj.IsBigint())) { |
| 1348 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1434 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1349 __ sw(reg, Address(SP, 1 * kWordSize)); | 1435 __ sw(reg, Address(SP, 1 * kWordSize)); |
| 1350 __ LoadObject(TMP1, obj); | 1436 __ LoadObject(TMP1, obj); |
| 1437 __ sw(TMP1, Address(SP, 0 * kWordSize)); |
| 1351 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1438 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1352 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1439 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1353 Isolate::kNoDeoptId, | 1440 Isolate::kNoDeoptId, |
| 1354 token_pos); | 1441 token_pos); |
| 1355 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); | |
| 1356 __ TraceSimMsg("EqualityRegConstCompare return"); | 1442 __ TraceSimMsg("EqualityRegConstCompare return"); |
| 1357 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. | 1443 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. |
| 1358 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. | 1444 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. |
| 1359 return; | 1445 return; |
| 1360 } | 1446 } |
| 1361 __ CompareObject(CMPRES, TMP1, reg, obj); | 1447 __ CompareObject(CMPRES, TMP1, reg, obj); |
| 1362 } | 1448 } |
| 1363 | 1449 |
| 1364 | 1450 |
| 1365 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1451 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1366 Register right, | 1452 Register right, |
| 1367 bool needs_number_check, | 1453 bool needs_number_check, |
| 1368 intptr_t token_pos) { | 1454 intptr_t token_pos) { |
| 1369 __ TraceSimMsg("EqualityRegRegCompare"); | 1455 __ TraceSimMsg("EqualityRegRegCompare"); |
| 1456 __ Comment("EqualityRegRegCompare"); |
| 1370 if (needs_number_check) { | 1457 if (needs_number_check) { |
| 1371 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1458 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1372 __ sw(left, Address(SP, 1 * kWordSize)); | 1459 __ sw(left, Address(SP, 1 * kWordSize)); |
| 1460 __ sw(right, Address(SP, 0 * kWordSize)); |
| 1373 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1461 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1374 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1462 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1375 Isolate::kNoDeoptId, | 1463 Isolate::kNoDeoptId, |
| 1376 token_pos); | 1464 token_pos); |
| 1377 __ delay_slot()->sw(right, Address(SP, 0 * kWordSize)); | |
| 1378 __ TraceSimMsg("EqualityRegRegCompare return"); | 1465 __ TraceSimMsg("EqualityRegRegCompare return"); |
| 1379 // Stub returns result in CMPRES. If it is 0, then left and right are equal. | 1466 // Stub returns result in CMPRES. If it is 0, then left and right are equal. |
| 1380 __ lw(right, Address(SP, 0 * kWordSize)); | 1467 __ lw(right, Address(SP, 0 * kWordSize)); |
| 1381 __ lw(left, Address(SP, 1 * kWordSize)); | 1468 __ lw(left, Address(SP, 1 * kWordSize)); |
| 1382 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1469 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1383 } else { | 1470 } else { |
| 1384 __ slt(CMPRES, left, right); | 1471 __ slt(CMPRES, left, right); |
| 1385 __ slt(TMP1, right, left); | 1472 __ slt(TMP1, right, left); |
| 1386 } | 1473 } |
| 1387 } | 1474 } |
| 1388 | 1475 |
| 1389 | 1476 |
| 1390 // Implement equality spec: if any of the arguments is null do identity check. | 1477 // Implement equality spec: if any of the arguments is null do identity check. |
| 1391 // Fallthrough calls super equality. | 1478 // Fallthrough calls super equality. |
| 1392 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, | 1479 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, |
| 1393 Label* skip_call) { | 1480 Label* skip_call) { |
| 1394 Label check_identity, is_false, fall_through; | 1481 Label check_identity, is_false, fall_through; |
| 1395 __ TraceSimMsg("SuperEqualityCallPrologue"); | 1482 __ TraceSimMsg("SuperEqualityCallPrologue"); |
| 1396 __ lw(result, Address(SP, 0 * kWordSize)); // Load right operand. | 1483 __ lw(result, Address(SP, 0 * kWordSize)); // Load right operand. |
| 1397 __ lw(TMP1, Address(SP, 1 * kWordSize)); // Load left operand. | 1484 __ lw(TMP1, Address(SP, 1 * kWordSize)); // Load left operand. |
| 1398 __ beq(result, NULLREG, &check_identity); // Is right null? | 1485 __ LoadImmediate(CMPRES, reinterpret_cast<int32_t>(Object::null())); |
| 1399 __ bne(TMP1, NULLREG, &fall_through); // If right is non-null, check left. | 1486 __ beq(result, CMPRES, &check_identity); // Is right null? |
| 1487 __ bne(TMP1, CMPRES, &fall_through); // If right is non-null, check left. |
| 1400 | 1488 |
| 1401 __ Bind(&check_identity); | 1489 __ Bind(&check_identity); |
| 1402 __ bne(result, TMP1, &is_false); | 1490 __ bne(result, TMP1, &is_false); |
| 1403 __ LoadObject(result, Bool::True()); | 1491 __ LoadObject(result, Bool::True()); |
| 1404 __ Drop(2); | 1492 __ Drop(2); |
| 1405 __ b(skip_call); | 1493 __ b(skip_call); |
| 1406 __ Bind(&is_false); | 1494 __ Bind(&is_false); |
| 1407 __ LoadObject(result, Bool::False()); | 1495 __ LoadObject(result, Bool::False()); |
| 1408 __ Drop(2); | 1496 __ Drop(2); |
| 1409 __ b(skip_call); | 1497 __ b(skip_call); |
| 1410 __ Bind(&fall_through); | 1498 __ Bind(&fall_through); |
| 1411 } | 1499 } |
| 1412 | 1500 |
| 1413 | 1501 |
| 1414 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1502 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 1415 __ TraceSimMsg("SaveLiveRegisters"); | 1503 __ TraceSimMsg("SaveLiveRegisters"); |
| 1416 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1504 // TODO(vegorov): consider saving only caller save (volatile) registers. |
| 1417 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1505 const intptr_t fpu_regs_count= locs->live_registers()->fpu_regs_count(); |
| 1418 if (fpu_registers > 0) { | 1506 if (fpu_regs_count > 0) { |
| 1419 UNIMPLEMENTED(); | 1507 __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize)); |
| 1508 // Store fpu registers with the lowest register number at the lowest |
| 1509 // address. |
| 1510 intptr_t offset = 0; |
| 1511 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { |
| 1512 DRegister fpu_reg = static_cast<DRegister>(reg_idx); |
| 1513 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { |
| 1514 __ StoreDToOffset(fpu_reg, SP, offset); |
| 1515 offset += kFpuRegisterSize; |
| 1516 } |
| 1517 } |
| 1518 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); |
| 1420 } | 1519 } |
| 1421 | 1520 |
| 1422 // Store general purpose registers with the lowest register number at the | 1521 // Store general purpose registers with the lowest register number at the |
| 1423 // lowest address. | 1522 // lowest address. |
| 1424 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); | 1523 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); |
| 1425 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); | 1524 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); |
| 1426 const int register_count = Utils::CountOneBits(cpu_registers); | 1525 const int register_count = Utils::CountOneBits(cpu_registers); |
| 1427 int registers_pushed = 0; | 1526 int registers_pushed = 0; |
| 1428 | 1527 |
| 1429 __ addiu(SP, SP, Immediate(-register_count * kWordSize)); | 1528 __ addiu(SP, SP, Immediate(-register_count * kWordSize)); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1448 | 1547 |
| 1449 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 1548 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 1450 Register r = static_cast<Register>(i); | 1549 Register r = static_cast<Register>(i); |
| 1451 if (locs->live_registers()->ContainsRegister(r)) { | 1550 if (locs->live_registers()->ContainsRegister(r)) { |
| 1452 __ lw(r, Address(SP, registers_popped * kWordSize)); | 1551 __ lw(r, Address(SP, registers_popped * kWordSize)); |
| 1453 registers_popped++; | 1552 registers_popped++; |
| 1454 } | 1553 } |
| 1455 } | 1554 } |
| 1456 __ addiu(SP, SP, Immediate(register_count * kWordSize)); | 1555 __ addiu(SP, SP, Immediate(register_count * kWordSize)); |
| 1457 | 1556 |
| 1458 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1557 const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count(); |
| 1459 if (fpu_registers > 0) { | 1558 if (fpu_regs_count > 0) { |
| 1460 UNIMPLEMENTED(); | 1559 // Fpu registers have the lowest register number at the lowest address. |
| 1560 intptr_t offset = 0; |
| 1561 for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) { |
| 1562 DRegister fpu_reg = static_cast<DRegister>(reg_idx); |
| 1563 if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) { |
| 1564 __ LoadDFromOffset(fpu_reg, SP, offset); |
| 1565 offset += kFpuRegisterSize; |
| 1566 } |
| 1567 } |
| 1568 ASSERT(offset == (fpu_regs_count * kFpuRegisterSize)); |
| 1569 __ AddImmediate(SP, offset); |
| 1461 } | 1570 } |
| 1462 } | 1571 } |
| 1463 | 1572 |
| 1464 | 1573 |
| 1465 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 1574 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 1466 Register class_id_reg, | 1575 Register class_id_reg, |
| 1467 intptr_t argument_count, | 1576 intptr_t argument_count, |
| 1468 const Array& argument_names, | 1577 const Array& argument_names, |
| 1469 Label* deopt, | 1578 Label* deopt, |
| 1470 intptr_t deopt_id, | 1579 intptr_t deopt_id, |
| 1471 intptr_t token_index, | 1580 intptr_t token_index, |
| 1472 LocationSummary* locs) { | 1581 LocationSummary* locs) { |
| 1473 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); | 1582 ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0)); |
| 1474 Label match_found; | 1583 Label match_found; |
| 1475 const intptr_t len = ic_data.NumberOfChecks(); | 1584 const intptr_t len = ic_data.NumberOfChecks(); |
| 1476 GrowableArray<CidTarget> sorted(len); | 1585 GrowableArray<CidTarget> sorted(len); |
| 1477 SortICDataByCount(ic_data, &sorted); | 1586 SortICDataByCount(ic_data, &sorted); |
| 1478 ASSERT(class_id_reg != S4); | 1587 ASSERT(class_id_reg != S4); |
| 1479 ASSERT(len > 0); // Why bother otherwise. | 1588 ASSERT(len > 0); // Why bother otherwise. |
| 1480 const Array& arguments_descriptor = | 1589 const Array& arguments_descriptor = |
| 1481 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, | 1590 Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| 1482 argument_names)); | 1591 argument_names)); |
| 1483 __ TraceSimMsg("EmitTestAndCall"); | 1592 __ TraceSimMsg("EmitTestAndCall"); |
| 1593 __ Comment("EmitTestAndCall"); |
| 1484 __ LoadObject(S4, arguments_descriptor); | 1594 __ LoadObject(S4, arguments_descriptor); |
| 1485 for (intptr_t i = 0; i < len; i++) { | 1595 for (intptr_t i = 0; i < len; i++) { |
| 1486 const bool is_last_check = (i == (len - 1)); | 1596 const bool is_last_check = (i == (len - 1)); |
| 1487 Label next_test; | 1597 Label next_test; |
| 1488 if (is_last_check) { | 1598 if (is_last_check) { |
| 1489 __ BranchNotEqual(class_id_reg, sorted[i].cid, deopt); | 1599 __ BranchNotEqual(class_id_reg, sorted[i].cid, deopt); |
| 1490 } else { | 1600 } else { |
| 1491 __ BranchNotEqual(class_id_reg, sorted[i].cid, &next_test); | 1601 __ BranchNotEqual(class_id_reg, sorted[i].cid, &next_test); |
| 1492 } | 1602 } |
| 1493 // Do not use the code from the function, but let the code be patched so | 1603 // Do not use the code from the function, but let the code be patched so |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1506 __ Bind(&next_test); | 1616 __ Bind(&next_test); |
| 1507 } | 1617 } |
| 1508 __ Bind(&match_found); | 1618 __ Bind(&match_found); |
| 1509 } | 1619 } |
| 1510 | 1620 |
| 1511 | 1621 |
| 1512 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, | 1622 void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition, |
| 1513 FpuRegister left, | 1623 FpuRegister left, |
| 1514 FpuRegister right, | 1624 FpuRegister right, |
| 1515 BranchInstr* branch) { | 1625 BranchInstr* branch) { |
| 1516 UNIMPLEMENTED(); | 1626 ASSERT(branch != NULL); |
| 1627 __ Comment("DoubleCompareBranch"); |
| 1628 assembler()->cund(left, right); |
| 1629 BlockEntryInstr* nan_result = (true_condition == NE) ? |
| 1630 branch->true_successor() : branch->false_successor(); |
| 1631 assembler()->bc1t(GetJumpLabel(nan_result)); |
| 1632 |
| 1633 switch (true_condition) { |
| 1634 case EQ: assembler()->ceqd(left, right); break; |
| 1635 case LT: assembler()->coltd(left, right); break; |
| 1636 case LE: assembler()->coled(left, right); break; |
| 1637 case GT: assembler()->coltd(right, left); break; |
| 1638 case GE: assembler()->coled(right, left); break; |
| 1639 default: { |
| 1640 // Should only passing the above conditions to this function. |
| 1641 UNREACHABLE(); |
| 1642 break; |
| 1643 } |
| 1644 } |
| 1645 |
| 1646 assembler()->LoadImmediate(TMP, 1); |
| 1647 assembler()->movf(CMPRES, TMP); |
| 1648 assembler()->movt(CMPRES, ZR); |
| 1649 assembler()->mov(TMP, ZR); |
| 1650 |
| 1651 // EmitBranchOnCondition expects ordering to be described by CMPRES, TMP1. |
| 1652 branch->EmitBranchOnCondition(this, EQ); |
| 1517 } | 1653 } |
| 1518 | 1654 |
| 1519 | 1655 |
| 1520 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, | 1656 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, |
| 1521 FpuRegister left, | 1657 FpuRegister left, |
| 1522 FpuRegister right, | 1658 FpuRegister right, |
| 1523 Register result) { | 1659 Register result) { |
| 1524 UNIMPLEMENTED(); | 1660 Label done; |
| 1661 __ Comment("DoubleCompareBool"); |
| 1662 assembler()->LoadObject(result, Bool::False()); |
| 1663 assembler()->cund(left, right); |
| 1664 assembler()->bc1t(&done); |
| 1665 |
| 1666 switch (true_condition) { |
| 1667 case EQ: assembler()->ceqd(left, right); break; |
| 1668 case LT: assembler()->coltd(left, right); break; |
| 1669 case LE: assembler()->coled(left, right); break; |
| 1670 case GT: assembler()->coltd(right, left); break; |
| 1671 case GE: assembler()->coled(right, left); break; |
| 1672 default: { |
| 1673 // Should only passing the above conditions to this function. |
| 1674 UNREACHABLE(); |
| 1675 break; |
| 1676 } |
| 1677 } |
| 1678 |
| 1679 assembler()->bc1f(&done); // False is already in result. |
| 1680 assembler()->LoadObject(result, Bool::True()); |
| 1681 assembler()->Bind(&done); |
| 1525 } | 1682 } |
| 1526 | 1683 |
| 1527 | 1684 |
| 1528 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid, | 1685 FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid, |
| 1529 intptr_t index_scale, | 1686 intptr_t index_scale, |
| 1530 Register array, | 1687 Register array, |
| 1531 intptr_t index) { | 1688 intptr_t index) { |
| 1532 UNREACHABLE(); | 1689 UNREACHABLE(); |
| 1533 return FieldAddress(array, index); | 1690 return FieldAddress(array, index); |
| 1534 } | 1691 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1584 } else { | 1741 } else { |
| 1585 ASSERT(destination.IsStackSlot()); | 1742 ASSERT(destination.IsStackSlot()); |
| 1586 MoveMemoryToMemory(destination.ToStackSlotAddress(), | 1743 MoveMemoryToMemory(destination.ToStackSlotAddress(), |
| 1587 source.ToStackSlotAddress()); | 1744 source.ToStackSlotAddress()); |
| 1588 } | 1745 } |
| 1589 } else if (source.IsFpuRegister()) { | 1746 } else if (source.IsFpuRegister()) { |
| 1590 if (destination.IsFpuRegister()) { | 1747 if (destination.IsFpuRegister()) { |
| 1591 __ movd(destination.fpu_reg(), source.fpu_reg()); | 1748 __ movd(destination.fpu_reg(), source.fpu_reg()); |
| 1592 } else { | 1749 } else { |
| 1593 if (destination.IsDoubleStackSlot()) { | 1750 if (destination.IsDoubleStackSlot()) { |
| 1594 __ sdc1(source.fpu_reg(), destination.ToStackSlotAddress()); | 1751 const Address& addr = destination.ToStackSlotAddress(); |
| 1752 int32_t offset = addr.get_offset(); |
| 1753 __ StoreDToOffset(source.fpu_reg(), FP, offset); |
| 1595 } else { | 1754 } else { |
| 1596 ASSERT(destination.IsQuadStackSlot()); | 1755 ASSERT(destination.IsQuadStackSlot()); |
| 1597 UNIMPLEMENTED(); | 1756 UNIMPLEMENTED(); |
| 1598 } | 1757 } |
| 1599 } | 1758 } |
| 1600 } else if (source.IsDoubleStackSlot()) { | 1759 } else if (source.IsDoubleStackSlot()) { |
| 1601 if (destination.IsFpuRegister()) { | 1760 if (destination.IsFpuRegister()) { |
| 1602 __ ldc1(destination.fpu_reg(), source.ToStackSlotAddress()); | 1761 const Address &addr = source.ToStackSlotAddress(); |
| 1762 const Register base = addr.get_base(); |
| 1763 const int32_t offset = addr.get_offset(); |
| 1764 __ LoadDFromOffset(destination.fpu_reg(), base, offset); |
| 1603 } else { | 1765 } else { |
| 1604 ASSERT(destination.IsDoubleStackSlot()); | 1766 ASSERT(destination.IsDoubleStackSlot()); |
| 1605 __ ldc1(FpuTMP, source.ToStackSlotAddress()); | 1767 const Address& saddr = source.ToStackSlotAddress(); |
| 1606 __ sdc1(FpuTMP, destination.ToStackSlotAddress()); | 1768 const Address& daddr = destination.ToStackSlotAddress(); |
| 1769 int32_t soffset = saddr.get_offset(); |
| 1770 int32_t doffset = daddr.get_offset(); |
| 1771 __ LoadDFromOffset(FpuTMP, FP, soffset); |
| 1772 __ StoreDToOffset(FpuTMP, FP, doffset); |
| 1607 } | 1773 } |
| 1608 } else if (source.IsQuadStackSlot()) { | 1774 } else if (source.IsQuadStackSlot()) { |
| 1609 UNIMPLEMENTED(); | 1775 UNIMPLEMENTED(); |
| 1610 } else { | 1776 } else { |
| 1611 ASSERT(source.IsConstant()); | 1777 ASSERT(source.IsConstant()); |
| 1612 if (destination.IsRegister()) { | 1778 if (destination.IsRegister()) { |
| 1613 const Object& constant = source.constant(); | 1779 const Object& constant = source.constant(); |
| 1614 __ LoadObject(destination.reg(), constant); | 1780 __ LoadObject(destination.reg(), constant); |
| 1615 } else { | 1781 } else { |
| 1616 ASSERT(destination.IsStackSlot()); | 1782 ASSERT(destination.IsStackSlot()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1651 source.IsQuadStackSlot()); | 1817 source.IsQuadStackSlot()); |
| 1652 bool double_width = destination.IsDoubleStackSlot() || | 1818 bool double_width = destination.IsDoubleStackSlot() || |
| 1653 source.IsDoubleStackSlot(); | 1819 source.IsDoubleStackSlot(); |
| 1654 DRegister reg = source.IsFpuRegister() ? source.fpu_reg() | 1820 DRegister reg = source.IsFpuRegister() ? source.fpu_reg() |
| 1655 : destination.fpu_reg(); | 1821 : destination.fpu_reg(); |
| 1656 const Address& slot_address = source.IsFpuRegister() | 1822 const Address& slot_address = source.IsFpuRegister() |
| 1657 ? destination.ToStackSlotAddress() | 1823 ? destination.ToStackSlotAddress() |
| 1658 : source.ToStackSlotAddress(); | 1824 : source.ToStackSlotAddress(); |
| 1659 | 1825 |
| 1660 if (double_width) { | 1826 if (double_width) { |
| 1661 __ ldc1(FpuTMP, slot_address); | 1827 const Register base = slot_address.get_base(); |
| 1662 __ sdc1(reg, slot_address); | 1828 const int32_t offset = slot_address.get_offset(); |
| 1829 __ LoadDFromOffset(FpuTMP, base, offset); |
| 1830 __ StoreDToOffset(reg, base, offset); |
| 1663 __ movd(reg, FpuTMP); | 1831 __ movd(reg, FpuTMP); |
| 1664 } else { | 1832 } else { |
| 1665 UNIMPLEMENTED(); | 1833 UNIMPLEMENTED(); |
| 1666 } | 1834 } |
| 1667 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { | 1835 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { |
| 1668 const Address& source_slot_address = source.ToStackSlotAddress(); | 1836 const Address& source_slot_address = source.ToStackSlotAddress(); |
| 1669 const Address& destination_slot_address = destination.ToStackSlotAddress(); | 1837 const Address& destination_slot_address = destination.ToStackSlotAddress(); |
| 1838 const Register sbase = source_slot_address.get_base(); |
| 1839 const int32_t soffset = source_slot_address.get_offset(); |
| 1840 const Register dbase = destination_slot_address.get_base(); |
| 1841 const int32_t doffset = destination_slot_address.get_offset(); |
| 1670 | 1842 |
| 1671 ScratchFpuRegisterScope ensure_scratch(this, FpuTMP); | 1843 ScratchFpuRegisterScope ensure_scratch(this, FpuTMP); |
| 1672 __ ldc1(FpuTMP, source_slot_address); | 1844 __ LoadDFromOffset(FpuTMP, sbase, soffset); |
| 1673 __ ldc1(ensure_scratch.reg(), destination_slot_address); | 1845 __ LoadDFromOffset(ensure_scratch.reg(), dbase, doffset); |
| 1674 __ sdc1(FpuTMP, destination_slot_address); | 1846 __ StoreDToOffset(FpuTMP, dbase, doffset); |
| 1675 __ sdc1(ensure_scratch.reg(), source_slot_address); | 1847 __ StoreDToOffset(ensure_scratch.reg(), sbase, soffset); |
| 1676 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { | 1848 } else if (source.IsQuadStackSlot() && destination.IsQuadStackSlot()) { |
| 1677 UNIMPLEMENTED(); | 1849 UNIMPLEMENTED(); |
| 1678 } else { | 1850 } else { |
| 1679 UNREACHABLE(); | 1851 UNREACHABLE(); |
| 1680 } | 1852 } |
| 1681 | 1853 |
| 1682 // The swap of source and destination has executed a move from source to | 1854 // The swap of source and destination has executed a move from source to |
| 1683 // destination. | 1855 // destination. |
| 1684 move->Eliminate(); | 1856 move->Eliminate(); |
| 1685 | 1857 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1739 | 1911 |
| 1740 void ParallelMoveResolver::RestoreScratch(Register reg) { | 1912 void ParallelMoveResolver::RestoreScratch(Register reg) { |
| 1741 __ TraceSimMsg("ParallelMoveResolver::RestoreScratch"); | 1913 __ TraceSimMsg("ParallelMoveResolver::RestoreScratch"); |
| 1742 __ Pop(reg); | 1914 __ Pop(reg); |
| 1743 } | 1915 } |
| 1744 | 1916 |
| 1745 | 1917 |
| 1746 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { | 1918 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { |
| 1747 __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch"); | 1919 __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch"); |
| 1748 __ AddImmediate(SP, -kDoubleSize); | 1920 __ AddImmediate(SP, -kDoubleSize); |
| 1749 __ sdc1(reg, Address(SP)); | 1921 __ StoreDToOffset(reg, SP, 0); |
| 1750 } | 1922 } |
| 1751 | 1923 |
| 1752 | 1924 |
| 1753 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1925 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1754 __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch"); | 1926 __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch"); |
| 1755 __ ldc1(reg, Address(SP)); | 1927 __ LoadDFromOffset(reg, SP, 0); |
| 1756 __ AddImmediate(SP, kDoubleSize); | 1928 __ AddImmediate(SP, kDoubleSize); |
| 1757 } | 1929 } |
| 1758 | 1930 |
| 1759 | 1931 |
| 1760 #undef __ | 1932 #undef __ |
| 1761 | 1933 |
| 1762 | 1934 |
| 1763 } // namespace dart | 1935 } // namespace dart |
| 1764 | 1936 |
| 1765 #endif // defined TARGET_ARCH_MIPS | 1937 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |