| 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 27 matching lines...) Expand all Loading... |
| 38 } | 38 } |
| 39 | 39 |
| 40 | 40 |
| 41 bool FlowGraphCompiler::SupportsUnboxedMints() { | 41 bool FlowGraphCompiler::SupportsUnboxedMints() { |
| 42 return false; | 42 return false; |
| 43 } | 43 } |
| 44 | 44 |
| 45 | 45 |
| 46 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, | 46 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler, |
| 47 DeoptInfoBuilder* builder) { | 47 DeoptInfoBuilder* builder) { |
| 48 UNIMPLEMENTED(); // TODO(regis): Copy ARM version. | 48 if (deopt_env_ == NULL) return DeoptInfo::null(); |
| 49 return NULL; | 49 |
| 50 intptr_t stack_height = compiler->StackSize(); |
| 51 AllocateIncomingParametersRecursive(deopt_env_, &stack_height); |
| 52 |
| 53 intptr_t slot_ix = 0; |
| 54 Environment* current = deopt_env_; |
| 55 |
| 56 // Emit all kMaterializeObject instructions describing objects to be |
| 57 // materialized on the deoptimization as a prefix to the deoptimization info. |
| 58 EmitMaterializations(deopt_env_, builder); |
| 59 |
| 60 // The real frame starts here. |
| 61 builder->MarkFrameStart(); |
| 62 |
| 63 // Current PP, FP, and PC. |
| 64 builder->AddPp(current->function(), slot_ix++); |
| 65 builder->AddCallerFp(slot_ix++); |
| 66 builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++); |
| 67 |
| 68 // Callee's PC marker is not used anymore. Pass Function::null() to set to 0. |
| 69 builder->AddPcMarker(Function::Handle(), slot_ix++); |
| 70 |
| 71 // Emit all values that are needed for materialization as a part of the |
| 72 // expression stack for the bottom-most frame. This guarantees that GC |
| 73 // will be able to find them during materialization. |
| 74 slot_ix = builder->EmitMaterializationArguments(slot_ix); |
| 75 |
| 76 // For the innermost environment, set outgoing arguments and the locals. |
| 77 for (intptr_t i = current->Length() - 1; |
| 78 i >= current->fixed_parameter_count(); |
| 79 i--) { |
| 80 builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++); |
| 81 } |
| 82 |
| 83 Environment* previous = current; |
| 84 current = current->outer(); |
| 85 while (current != NULL) { |
| 86 // PP, FP, and PC. |
| 87 builder->AddPp(current->function(), slot_ix++); |
| 88 builder->AddCallerFp(slot_ix++); |
| 89 |
| 90 // For any outer environment the deopt id is that of the call instruction |
| 91 // which is recorded in the outer environment. |
| 92 builder->AddReturnAddress(current->function(), |
| 93 Isolate::ToDeoptAfter(current->deopt_id()), |
| 94 slot_ix++); |
| 95 |
| 96 // PC marker. |
| 97 builder->AddPcMarker(previous->function(), slot_ix++); |
| 98 |
| 99 // The values of outgoing arguments can be changed from the inlined call so |
| 100 // we must read them from the previous environment. |
| 101 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 102 builder->AddCopy(previous->ValueAt(i), |
| 103 previous->LocationAt(i), |
| 104 slot_ix++); |
| 105 } |
| 106 |
| 107 // Set the locals, note that outgoing arguments are not in the environment. |
| 108 for (intptr_t i = current->Length() - 1; |
| 109 i >= current->fixed_parameter_count(); |
| 110 i--) { |
| 111 builder->AddCopy(current->ValueAt(i), |
| 112 current->LocationAt(i), |
| 113 slot_ix++); |
| 114 } |
| 115 |
| 116 // Iterate on the outer environment. |
| 117 previous = current; |
| 118 current = current->outer(); |
| 119 } |
| 120 // The previous pointer is now the outermost environment. |
| 121 ASSERT(previous != NULL); |
| 122 |
| 123 // For the outermost environment, set caller PC, caller PP, and caller FP. |
| 124 builder->AddCallerPp(slot_ix++); |
| 125 builder->AddCallerFp(slot_ix++); |
| 126 builder->AddCallerPc(slot_ix++); |
| 127 |
| 128 // PC marker. |
| 129 builder->AddPcMarker(previous->function(), slot_ix++); |
| 130 |
| 131 // For the outermost environment, set the incoming arguments. |
| 132 for (intptr_t i = previous->fixed_parameter_count() - 1; i >= 0; i--) { |
| 133 builder->AddCopy(previous->ValueAt(i), previous->LocationAt(i), slot_ix++); |
| 134 } |
| 135 |
| 136 const DeoptInfo& deopt_info = DeoptInfo::Handle(builder->CreateDeoptInfo()); |
| 137 return deopt_info.raw(); |
| 50 } | 138 } |
| 51 | 139 |
| 52 | 140 |
| 53 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, | 141 void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, |
| 54 intptr_t stub_ix) { | 142 intptr_t stub_ix) { |
| 55 // Calls do not need stubs, they share a deoptimization trampoline. | 143 // Calls do not need stubs, they share a deoptimization trampoline. |
| 56 ASSERT(reason() != kDeoptAtCall); | 144 ASSERT(reason() != kDeoptAtCall); |
| 57 Assembler* assem = compiler->assembler(); | 145 Assembler* assem = compiler->assembler(); |
| 58 #define __ assem-> | 146 #define __ assem-> |
| 59 __ Comment("Deopt stub for id %"Pd"", deopt_id()); | 147 __ Comment("Deopt stub for id %"Pd"", deopt_id()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 71 | 159 |
| 72 #define __ assembler()-> | 160 #define __ assembler()-> |
| 73 | 161 |
| 74 | 162 |
| 75 // Fall through if bool_register contains null. | 163 // Fall through if bool_register contains null. |
| 76 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 164 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 77 Label* is_true, | 165 Label* is_true, |
| 78 Label* is_false) { | 166 Label* is_false) { |
| 79 __ TraceSimMsg("BoolToJump"); | 167 __ TraceSimMsg("BoolToJump"); |
| 80 Label fall_through; | 168 Label fall_through; |
| 81 __ BranchEqual(bool_register, reinterpret_cast<intptr_t>(Object::null()), | 169 __ beq(bool_register, NULLREG, &fall_through); |
| 82 &fall_through); | |
| 83 __ BranchEqual(bool_register, Bool::True(), is_true); | 170 __ BranchEqual(bool_register, Bool::True(), is_true); |
| 84 __ b(is_false); | 171 __ b(is_false); |
| 85 __ Bind(&fall_through); | 172 __ Bind(&fall_through); |
| 86 } | 173 } |
| 87 | 174 |
| 88 | 175 |
| 89 // A0: instance (must be preserved). | 176 // A0: instance (must be preserved). |
| 90 // A1: instantiator type arguments (if used). | 177 // A1: instantiator type arguments (if used). |
| 91 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 178 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 92 TypeTestStubKind test_kind, | 179 TypeTestStubKind test_kind, |
| 93 Register instance_reg, | 180 Register instance_reg, |
| 94 Register type_arguments_reg, | 181 Register type_arguments_reg, |
| 95 Register temp_reg, | 182 Register temp_reg, |
| 96 Label* is_instance_lbl, | 183 Label* is_instance_lbl, |
| 97 Label* is_not_instance_lbl) { | 184 Label* is_not_instance_lbl) { |
| 98 __ TraceSimMsg("CallSubtypeTestStub"); | 185 __ TraceSimMsg("CallSubtypeTestStub"); |
| 99 ASSERT(instance_reg == A0); | 186 ASSERT(instance_reg == A0); |
| 100 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 187 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
| 101 const SubtypeTestCache& type_test_cache = | 188 const SubtypeTestCache& type_test_cache = |
| 102 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 189 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 103 __ LoadObject(A2, type_test_cache); | 190 __ LoadObject(A2, type_test_cache); |
| 104 intptr_t null = reinterpret_cast<intptr_t>(Object::null()); | |
| 105 uint16_t null_lo = Utils::Low16Bits(null); | |
| 106 uint16_t null_hi = Utils::High16Bits(null); | |
| 107 if (test_kind == kTestTypeOneArg) { | 191 if (test_kind == kTestTypeOneArg) { |
| 108 ASSERT(type_arguments_reg == kNoRegister); | 192 ASSERT(type_arguments_reg == kNoRegister); |
| 109 __ lui(A1, Immediate(null_hi)); | |
| 110 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 193 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 111 __ delay_slot()->ori(A1, A1, Immediate(null_lo)); | 194 __ delay_slot()->mov(A1, NULLREG); |
| 112 } else if (test_kind == kTestTypeTwoArgs) { | 195 } else if (test_kind == kTestTypeTwoArgs) { |
| 113 ASSERT(type_arguments_reg == kNoRegister); | 196 ASSERT(type_arguments_reg == kNoRegister); |
| 114 __ lui(A1, Immediate(null_hi)); | |
| 115 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); | 197 __ BranchLink(&StubCode::Subtype2TestCacheLabel()); |
| 116 __ delay_slot()->ori(A1, A1, Immediate(null_lo)); | 198 __ delay_slot()->mov(A1, NULLREG); |
| 117 } else if (test_kind == kTestTypeThreeArgs) { | 199 } else if (test_kind == kTestTypeThreeArgs) { |
| 118 ASSERT(type_arguments_reg == A1); | 200 ASSERT(type_arguments_reg == A1); |
| 119 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); | 201 __ BranchLink(&StubCode::Subtype3TestCacheLabel()); |
| 120 } else { | 202 } else { |
| 121 UNREACHABLE(); | 203 UNREACHABLE(); |
| 122 } | 204 } |
| 123 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. | 205 // Result is in V0: null -> not found, otherwise Bool::True or Bool::False. |
| 124 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); | 206 GenerateBoolToJump(V0, is_instance_lbl, is_not_instance_lbl); |
| 125 return type_test_cache.raw(); | 207 return type_test_cache.raw(); |
| 126 } | 208 } |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 // Bool interface can be implemented only by core class Bool. | 322 // Bool interface can be implemented only by core class Bool. |
| 241 if (type.IsBoolType()) { | 323 if (type.IsBoolType()) { |
| 242 __ BranchEqual(kClassIdReg, kBoolCid, is_instance_lbl); | 324 __ BranchEqual(kClassIdReg, kBoolCid, is_instance_lbl); |
| 243 __ b(is_not_instance_lbl); | 325 __ b(is_not_instance_lbl); |
| 244 return false; | 326 return false; |
| 245 } | 327 } |
| 246 if (type.IsFunctionType()) { | 328 if (type.IsFunctionType()) { |
| 247 // Check if instance is a closure. | 329 // Check if instance is a closure. |
| 248 __ LoadClassById(T1, kClassIdReg); | 330 __ LoadClassById(T1, kClassIdReg); |
| 249 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); | 331 __ lw(T1, FieldAddress(T1, Class::signature_function_offset())); |
| 250 __ BranchNotEqual(T1, reinterpret_cast<int32_t>(Object::null()), | 332 __ bne(T1, NULLREG, is_instance_lbl); |
| 251 is_instance_lbl); | |
| 252 } | 333 } |
| 253 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 334 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 254 // Note that instance is not Smi (checked above). | 335 // Note that instance is not Smi (checked above). |
| 255 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { | 336 if (type.IsSubtypeOf(Type::Handle(Type::Number()), NULL)) { |
| 256 GenerateNumberTypeCheck( | 337 GenerateNumberTypeCheck( |
| 257 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 338 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 258 return false; | 339 return false; |
| 259 } | 340 } |
| 260 if (type.IsStringType()) { | 341 if (type.IsStringType()) { |
| 261 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 342 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 Label* is_not_instance_lbl) { | 389 Label* is_not_instance_lbl) { |
| 309 __ Comment("UninstantiatedTypeTest"); | 390 __ Comment("UninstantiatedTypeTest"); |
| 310 ASSERT(!type.IsInstantiated()); | 391 ASSERT(!type.IsInstantiated()); |
| 311 // Skip check if destination is a dynamic type. | 392 // Skip check if destination is a dynamic type. |
| 312 if (type.IsTypeParameter()) { | 393 if (type.IsTypeParameter()) { |
| 313 const TypeParameter& type_param = TypeParameter::Cast(type); | 394 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 314 // Load instantiator (or null) and instantiator type arguments on stack. | 395 // Load instantiator (or null) and instantiator type arguments on stack. |
| 315 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 396 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
| 316 // A1: instantiator type arguments. | 397 // A1: instantiator type arguments. |
| 317 // Check if type argument is dynamic. | 398 // Check if type argument is dynamic. |
| 318 __ BranchEqual(A1, reinterpret_cast<intptr_t>(Object::null()), | 399 __ beq(A1, NULLREG, is_instance_lbl); |
| 319 is_instance_lbl); | |
| 320 // Can handle only type arguments that are instances of TypeArguments. | 400 // Can handle only type arguments that are instances of TypeArguments. |
| 321 // (runtime checks canonicalize type arguments). | 401 // (runtime checks canonicalize type arguments). |
| 322 Label fall_through; | 402 Label fall_through; |
| 323 __ LoadClassId(T2, A1); | 403 __ LoadClassId(T2, A1); |
| 324 __ BranchNotEqual(T2, kTypeArgumentsCid, &fall_through); | 404 __ BranchNotEqual(T2, kTypeArgumentsCid, &fall_through); |
| 325 __ lw(T2, | 405 __ lw(T2, |
| 326 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); | 406 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); |
| 327 // R2: concrete type of type. | 407 // R2: concrete type of type. |
| 328 // Check if type argument is dynamic. | 408 // Check if type argument is dynamic. |
| 329 __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl); | 409 __ BranchEqual(T2, Type::ZoneHandle(Type::DynamicType()), is_instance_lbl); |
| 330 __ BranchEqual(T2, reinterpret_cast<intptr_t>(Object::null()), | 410 __ beq(T2, NULLREG, is_instance_lbl); |
| 331 is_instance_lbl); | |
| 332 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); | 411 const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
| 333 __ BranchEqual(T2, object_type, is_instance_lbl); | 412 __ BranchEqual(T2, object_type, is_instance_lbl); |
| 334 | 413 |
| 335 // For Smi check quickly against int and num interfaces. | 414 // For Smi check quickly against int and num interfaces. |
| 336 Label not_smi; | 415 Label not_smi; |
| 337 __ andi(CMPRES, A0, Immediate(kSmiTagMask)); | 416 __ andi(CMPRES, A0, Immediate(kSmiTagMask)); |
| 338 __ bne(CMPRES, ZR, ¬_smi); // Value is Smi? | 417 __ bne(CMPRES, ZR, ¬_smi); // Value is Smi? |
| 339 __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl); | 418 __ BranchEqual(T2, Type::ZoneHandle(Type::IntType()), is_instance_lbl); |
| 340 __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl); | 419 __ BranchEqual(T2, Type::ZoneHandle(Type::Number()), is_instance_lbl); |
| 341 | 420 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 ASSERT(dst_type.IsFinalized()); | 559 ASSERT(dst_type.IsFinalized()); |
| 481 // Assignable check is skipped in FlowGraphBuilder, not here. | 560 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 482 ASSERT(dst_type.IsMalformed() || | 561 ASSERT(dst_type.IsMalformed() || |
| 483 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 562 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 484 // Preserve instantiator and its type arguments. | 563 // Preserve instantiator and its type arguments. |
| 485 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 564 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 486 __ sw(A2, Address(SP, 1 * kWordSize)); | 565 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 487 | 566 |
| 488 // A null object is always assignable and is returned as result. | 567 // A null object is always assignable and is returned as result. |
| 489 Label is_assignable, runtime_call; | 568 Label is_assignable, runtime_call; |
| 490 __ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable); | 569 __ beq(A0, NULLREG, &is_assignable); |
| 491 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); | 570 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
| 492 | 571 |
| 493 if (!FLAG_eliminate_type_checks) { | 572 if (!FLAG_eliminate_type_checks) { |
| 494 // If type checks are not eliminated during the graph building then | 573 // If type checks are not eliminated during the graph building then |
| 495 // a transition sentinel can be seen here. | 574 // a transition sentinel can be seen here. |
| 496 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); | 575 __ BranchEqual(A0, Object::transition_sentinel(), &is_assignable); |
| 497 } | 576 } |
| 498 | 577 |
| 499 // Generate throw new TypeError() if the type is malformed. | 578 // Generate throw new TypeError() if the type is malformed. |
| 500 if (dst_type.IsMalformed()) { | 579 if (dst_type.IsMalformed()) { |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 // We do not use the final allocation index of the variable here, i.e. | 798 // We do not use the final allocation index of the variable here, i.e. |
| 720 // scope->VariableAt(i)->index(), because captured variables still need | 799 // scope->VariableAt(i)->index(), because captured variables still need |
| 721 // to be copied to the context that is not yet allocated. | 800 // to be copied to the context that is not yet allocated. |
| 722 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; | 801 const intptr_t computed_param_pos = kFirstLocalSlotFromFp - param_pos; |
| 723 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 802 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 724 } | 803 } |
| 725 delete[] opt_param; | 804 delete[] opt_param; |
| 726 delete[] opt_param_position; | 805 delete[] opt_param_position; |
| 727 // Check that T0 now points to the null terminator in the array descriptor. | 806 // Check that T0 now points to the null terminator in the array descriptor. |
| 728 __ lw(T3, Address(T0)); | 807 __ lw(T3, Address(T0)); |
| 729 __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()), | 808 __ beq(T3, NULLREG, &all_arguments_processed); |
| 730 &all_arguments_processed); | |
| 731 } else { | 809 } else { |
| 732 ASSERT(num_opt_pos_params > 0); | 810 ASSERT(num_opt_pos_params > 0); |
| 733 __ lw(T2, | 811 __ lw(T2, |
| 734 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 812 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 735 __ SmiUntag(T2); | 813 __ SmiUntag(T2); |
| 736 for (int i = 0; i < num_opt_pos_params; i++) { | 814 for (int i = 0; i < num_opt_pos_params; i++) { |
| 737 Label next_parameter; | 815 Label next_parameter; |
| 738 // Handle this optional positional parameter only if k or fewer positional | 816 // Handle this optional positional parameter only if k or fewer positional |
| 739 // arguments have been passed, where k is param_pos, the position of this | 817 // arguments have been passed, where k is param_pos, the position of this |
| 740 // optional parameter in the formal parameter list. | 818 // optional parameter in the formal parameter list. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 797 // The noSuchMethod call may return. | 875 // The noSuchMethod call may return. |
| 798 __ LeaveDartFrameAndReturn(); | 876 __ LeaveDartFrameAndReturn(); |
| 799 | 877 |
| 800 __ Bind(&all_arguments_processed); | 878 __ Bind(&all_arguments_processed); |
| 801 // Nullify originally passed arguments only after they have been copied and | 879 // Nullify originally passed arguments only after they have been copied and |
| 802 // checked, otherwise noSuchMethod would not see their original values. | 880 // checked, otherwise noSuchMethod would not see their original values. |
| 803 // This step can be skipped in case we decide that formal parameters are | 881 // This step can be skipped in case we decide that formal parameters are |
| 804 // implicitly final, since garbage collecting the unmodified value is not | 882 // implicitly final, since garbage collecting the unmodified value is not |
| 805 // an issue anymore. | 883 // an issue anymore. |
| 806 | 884 |
| 807 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | |
| 808 | |
| 809 // S4 : arguments descriptor array. | 885 // S4 : arguments descriptor array. |
| 810 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 886 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 811 __ sll(T2, T2, 1); // T2 is a Smi. | 887 __ sll(T2, T2, 1); // T2 is a Smi. |
| 812 | 888 |
| 813 Label null_args_loop, null_args_loop_exit; | 889 Label null_args_loop, null_args_loop_exit; |
| 814 __ blez(T2, &null_args_loop_exit); | 890 __ blez(T2, &null_args_loop_exit); |
| 815 __ delay_slot()->addiu(T1, FP, | 891 __ delay_slot()->addiu(T1, FP, |
| 816 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); | 892 Immediate((kParamEndSlotFromFp + 1) * kWordSize)); |
| 817 __ Bind(&null_args_loop); | 893 __ Bind(&null_args_loop); |
| 818 __ addiu(T2, T2, Immediate(-kWordSize)); | 894 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 819 __ addu(T3, T1, T2); | 895 __ addu(T3, T1, T2); |
| 820 __ bgtz(T2, &null_args_loop); | 896 __ bgtz(T2, &null_args_loop); |
| 821 __ delay_slot()->sw(T0, Address(T3)); | 897 __ delay_slot()->sw(NULLREG, Address(T3)); |
| 822 __ Bind(&null_args_loop_exit); | 898 __ Bind(&null_args_loop_exit); |
| 823 } | 899 } |
| 824 | 900 |
| 825 | 901 |
| 826 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 902 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 827 // RA: return address. | 903 // RA: return address. |
| 828 // SP: receiver. | 904 // SP: receiver. |
| 829 // Sequence node has one return node, its input is load field node. | 905 // Sequence node has one return node, its input is load field node. |
| 830 __ lw(V0, Address(SP, 0 * kWordSize)); | 906 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 831 __ lw(V0, Address(V0, offset - kHeapObjectTag)); | 907 __ lw(V0, Address(V0, offset - kHeapObjectTag)); |
| 832 __ Ret(); | 908 __ Ret(); |
| 833 } | 909 } |
| 834 | 910 |
| 835 | 911 |
| 836 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 912 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 837 // RA: return address. | 913 // RA: return address. |
| 838 // SP+1: receiver. | 914 // SP+1: receiver. |
| 839 // SP+0: value. | 915 // SP+0: value. |
| 840 // Sequence node has one store node and one return NULL node. | 916 // Sequence node has one store node and one return NULL node. |
| 841 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. | 917 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 842 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. | 918 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 843 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); | 919 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 844 intptr_t null = reinterpret_cast<intptr_t>(Object::null()); | |
| 845 uint16_t null_lo = Utils::Low16Bits(null); | |
| 846 uint16_t null_hi = Utils::High16Bits(null); | |
| 847 __ lui(V0, Immediate(null_hi)); | |
| 848 __ Ret(); | 920 __ Ret(); |
| 849 __ delay_slot()->ori(V0, V0, Immediate(null_lo)); | 921 __ delay_slot()->mov(V0, NULLREG); |
| 850 } | 922 } |
| 851 | 923 |
| 852 | 924 |
| 853 void FlowGraphCompiler::EmitFrameEntry() { | 925 void FlowGraphCompiler::EmitFrameEntry() { |
| 854 __ TraceSimMsg("FrameEntry"); | 926 __ TraceSimMsg("FrameEntry"); |
| 855 const Function& function = parsed_function().function(); | 927 const Function& function = parsed_function().function(); |
| 856 if (CanOptimizeFunction() && function.is_optimizable()) { | 928 if (CanOptimizeFunction() && function.is_optimizable()) { |
| 857 const bool can_optimize = !is_optimizing() || may_reoptimize(); | 929 const bool can_optimize = !is_optimizing() || may_reoptimize(); |
| 858 const Register function_reg = T0; | 930 const Register function_reg = T0; |
| 859 if (can_optimize) { | 931 if (can_optimize) { |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 } | 1104 } |
| 1033 CopyParameters(); | 1105 CopyParameters(); |
| 1034 } | 1106 } |
| 1035 | 1107 |
| 1036 // In unoptimized code, initialize (non-argument) stack allocated slots to | 1108 // In unoptimized code, initialize (non-argument) stack allocated slots to |
| 1037 // null. This does not cover the saved_args_desc_var slot. | 1109 // null. This does not cover the saved_args_desc_var slot. |
| 1038 if (!is_optimizing() && (num_locals > 0)) { | 1110 if (!is_optimizing() && (num_locals > 0)) { |
| 1039 __ TraceSimMsg("Initialize spill slots"); | 1111 __ TraceSimMsg("Initialize spill slots"); |
| 1040 __ Comment("Initialize spill slots"); | 1112 __ Comment("Initialize spill slots"); |
| 1041 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 1113 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
| 1042 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | |
| 1043 for (intptr_t i = 0; i < num_locals; ++i) { | 1114 for (intptr_t i = 0; i < num_locals; ++i) { |
| 1044 // Subtract index i (locals lie at lower addresses than FP). | 1115 // Subtract index i (locals lie at lower addresses than FP). |
| 1045 __ sw(T0, Address(FP, (slot_base - i) * kWordSize)); | 1116 __ sw(NULLREG, Address(FP, (slot_base - i) * kWordSize)); |
| 1046 } | 1117 } |
| 1047 } | 1118 } |
| 1048 | 1119 |
| 1049 if (FLAG_print_scopes) { | 1120 if (FLAG_print_scopes) { |
| 1050 // Print the function scope (again) after generating the prologue in order | 1121 // Print the function scope (again) after generating the prologue in order |
| 1051 // to see annotations such as allocation indices of locals. | 1122 // to see annotations such as allocation indices of locals. |
| 1052 if (FLAG_print_ast) { | 1123 if (FLAG_print_ast) { |
| 1053 // Second printing. | 1124 // Second printing. |
| 1054 OS::Print("Annotated "); | 1125 OS::Print("Annotated "); |
| 1055 } | 1126 } |
| 1056 AstPrinter::PrintFunctionScope(parsed_function()); | 1127 AstPrinter::PrintFunctionScope(parsed_function()); |
| 1057 } | 1128 } |
| 1058 | 1129 |
| 1059 VisitBlocks(); | 1130 VisitBlocks(); |
| 1060 | 1131 |
| 1061 __ break_(0); | 1132 __ break_(0); |
| 1062 GenerateDeferredCode(); | 1133 GenerateDeferredCode(); |
| 1063 // Emit function patching code. This will be swapped with the first 5 bytes | 1134 // Emit function patching code. This will be swapped with the first 5 bytes |
| 1064 // at entry point. | 1135 // at entry point. |
| 1065 AddCurrentDescriptor(PcDescriptors::kPatchCode, | 1136 AddCurrentDescriptor(PcDescriptors::kPatchCode, |
| 1066 Isolate::kNoDeoptId, | 1137 Isolate::kNoDeoptId, |
| 1067 0); // No token position. | 1138 0); // No token position. |
| 1068 __ Branch(&StubCode::FixCallersTargetLabel()); | 1139 __ BranchPatchable(&StubCode::FixCallersTargetLabel()); |
| 1069 AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, | 1140 AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, |
| 1070 Isolate::kNoDeoptId, | 1141 Isolate::kNoDeoptId, |
| 1071 0); // No token position. | 1142 0); // No token position. |
| 1072 __ Branch(&StubCode::DeoptimizeLazyLabel()); | 1143 __ Branch(&StubCode::DeoptimizeLazyLabel()); |
| 1073 } | 1144 } |
| 1074 | 1145 |
| 1075 | 1146 |
| 1076 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 1147 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 1077 const ExternalLabel* label, | 1148 const ExternalLabel* label, |
| 1078 PcDescriptors::Kind kind, | 1149 PcDescriptors::Kind kind, |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1222 __ LoadObject(TMP1, obj); | 1293 __ LoadObject(TMP1, obj); |
| 1223 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1294 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1224 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1295 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1225 Isolate::kNoDeoptId, | 1296 Isolate::kNoDeoptId, |
| 1226 token_pos); | 1297 token_pos); |
| 1227 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); | 1298 __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize)); |
| 1228 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. | 1299 __ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'. |
| 1229 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. | 1300 __ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant. |
| 1230 return; | 1301 return; |
| 1231 } | 1302 } |
| 1232 __ CompareObject(CMPRES, reg, obj); | 1303 __ CompareObject(CMPRES, TMP1, reg, obj); |
| 1233 } | 1304 } |
| 1234 | 1305 |
| 1235 | 1306 |
| 1236 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1307 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1237 Register right, | 1308 Register right, |
| 1238 bool needs_number_check, | 1309 bool needs_number_check, |
| 1239 intptr_t token_pos) { | 1310 intptr_t token_pos) { |
| 1240 __ TraceSimMsg("EqualityRegRegCompare"); | 1311 __ TraceSimMsg("EqualityRegRegCompare"); |
| 1241 if (needs_number_check) { | 1312 if (needs_number_check) { |
| 1242 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 1313 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 1243 __ sw(left, Address(SP, 1 * kWordSize)); | 1314 __ sw(left, Address(SP, 1 * kWordSize)); |
| 1244 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1315 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1245 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, | 1316 AddCurrentDescriptor(PcDescriptors::kRuntimeCall, |
| 1246 Isolate::kNoDeoptId, | 1317 Isolate::kNoDeoptId, |
| 1247 token_pos); | 1318 token_pos); |
| 1248 __ delay_slot()->sw(right, Address(SP, 0 * kWordSize)); | 1319 __ delay_slot()->sw(right, Address(SP, 0 * kWordSize)); |
| 1249 __ TraceSimMsg("EqualityRegRegCompare return"); | 1320 __ TraceSimMsg("EqualityRegRegCompare return"); |
| 1250 // Stub returns result in CMPRES. If it is 0, then left and right are equal. | 1321 // Stub returns result in CMPRES. If it is 0, then left and right are equal. |
| 1251 __ lw(right, Address(SP, 0 * kWordSize)); | 1322 __ lw(right, Address(SP, 0 * kWordSize)); |
| 1252 __ lw(left, Address(SP, 1 * kWordSize)); | 1323 __ lw(left, Address(SP, 1 * kWordSize)); |
| 1253 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1324 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1254 } else { | 1325 } else { |
| 1255 __ subu(CMPRES, left, right); | 1326 __ slt(CMPRES, left, right); |
| 1327 __ slt(TMP1, right, left); |
| 1256 } | 1328 } |
| 1257 } | 1329 } |
| 1258 | 1330 |
| 1259 | 1331 |
| 1260 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, | 1332 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, |
| 1261 Label* skip_call) { | 1333 Label* skip_call) { |
| 1262 UNIMPLEMENTED(); | 1334 UNIMPLEMENTED(); |
| 1263 } | 1335 } |
| 1264 | 1336 |
| 1265 | 1337 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1461 __ movd(FpuTMP, source.fpu_reg()); | 1533 __ movd(FpuTMP, source.fpu_reg()); |
| 1462 __ movd(source.fpu_reg(), destination.fpu_reg()); | 1534 __ movd(source.fpu_reg(), destination.fpu_reg()); |
| 1463 __ movd(destination.fpu_reg(), FpuTMP); | 1535 __ movd(destination.fpu_reg(), FpuTMP); |
| 1464 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { | 1536 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { |
| 1465 ASSERT(destination.IsDoubleStackSlot() || | 1537 ASSERT(destination.IsDoubleStackSlot() || |
| 1466 destination.IsQuadStackSlot() || | 1538 destination.IsQuadStackSlot() || |
| 1467 source.IsDoubleStackSlot() || | 1539 source.IsDoubleStackSlot() || |
| 1468 source.IsQuadStackSlot()); | 1540 source.IsQuadStackSlot()); |
| 1469 bool double_width = destination.IsDoubleStackSlot() || | 1541 bool double_width = destination.IsDoubleStackSlot() || |
| 1470 source.IsDoubleStackSlot(); | 1542 source.IsDoubleStackSlot(); |
| 1471 FRegister reg = source.IsFpuRegister() ? source.fpu_reg() | 1543 DRegister reg = source.IsFpuRegister() ? source.fpu_reg() |
| 1472 : destination.fpu_reg(); | 1544 : destination.fpu_reg(); |
| 1473 const Address& slot_address = source.IsFpuRegister() | 1545 const Address& slot_address = source.IsFpuRegister() |
| 1474 ? destination.ToStackSlotAddress() | 1546 ? destination.ToStackSlotAddress() |
| 1475 : source.ToStackSlotAddress(); | 1547 : source.ToStackSlotAddress(); |
| 1476 | 1548 |
| 1477 if (double_width) { | 1549 if (double_width) { |
| 1478 __ ldc1(FpuTMP, slot_address); | 1550 __ ldc1(FpuTMP, slot_address); |
| 1479 __ sdc1(reg, slot_address); | 1551 __ sdc1(reg, slot_address); |
| 1480 __ movd(reg, FpuTMP); | 1552 __ movd(reg, FpuTMP); |
| 1481 } else { | 1553 } else { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1573 __ AddImmediate(SP, kDoubleSize); | 1645 __ AddImmediate(SP, kDoubleSize); |
| 1574 } | 1646 } |
| 1575 | 1647 |
| 1576 | 1648 |
| 1577 #undef __ | 1649 #undef __ |
| 1578 | 1650 |
| 1579 | 1651 |
| 1580 } // namespace dart | 1652 } // namespace dart |
| 1581 | 1653 |
| 1582 #endif // defined TARGET_ARCH_MIPS | 1654 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |