| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 } | 59 } |
| 60 | 60 |
| 61 | 61 |
| 62 #define __ assembler()-> | 62 #define __ assembler()-> |
| 63 | 63 |
| 64 | 64 |
| 65 // Fall through if bool_register contains null. | 65 // Fall through if bool_register contains null. |
| 66 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, | 66 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| 67 Label* is_true, | 67 Label* is_true, |
| 68 Label* is_false) { | 68 Label* is_false) { |
| 69 __ TraceSimMsg("BoolToJump"); |
| 69 Label fall_through; | 70 Label fall_through; |
| 70 __ BranchEqual(bool_register, reinterpret_cast<intptr_t>(Object::null()), | 71 __ BranchEqual(bool_register, reinterpret_cast<intptr_t>(Object::null()), |
| 71 &fall_through); | 72 &fall_through); |
| 72 __ BranchEqual(bool_register, Bool::True(), is_true); | 73 __ BranchEqual(bool_register, Bool::True(), is_true); |
| 73 __ b(is_false); | 74 __ b(is_false); |
| 74 __ Bind(&fall_through); | 75 __ Bind(&fall_through); |
| 75 } | 76 } |
| 76 | 77 |
| 77 | 78 |
| 78 // A0: instance (must be preserved). | 79 // A0: instance (must be preserved). |
| 79 // A1: instantiator type arguments (if used). | 80 // A1: instantiator type arguments (if used). |
| 80 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 81 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| 81 TypeTestStubKind test_kind, | 82 TypeTestStubKind test_kind, |
| 82 Register instance_reg, | 83 Register instance_reg, |
| 83 Register type_arguments_reg, | 84 Register type_arguments_reg, |
| 84 Register temp_reg, | 85 Register temp_reg, |
| 85 Label* is_instance_lbl, | 86 Label* is_instance_lbl, |
| 86 Label* is_not_instance_lbl) { | 87 Label* is_not_instance_lbl) { |
| 88 __ TraceSimMsg("CallSubtypeTestStub"); |
| 87 ASSERT(instance_reg == A0); | 89 ASSERT(instance_reg == A0); |
| 88 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. | 90 ASSERT(temp_reg == kNoRegister); // Unused on MIPS. |
| 89 const SubtypeTestCache& type_test_cache = | 91 const SubtypeTestCache& type_test_cache = |
| 90 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 92 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 91 __ LoadObject(A2, type_test_cache); | 93 __ LoadObject(A2, type_test_cache); |
| 92 if (test_kind == kTestTypeOneArg) { | 94 if (test_kind == kTestTypeOneArg) { |
| 93 ASSERT(type_arguments_reg == kNoRegister); | 95 ASSERT(type_arguments_reg == kNoRegister); |
| 94 __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null())); | 96 __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null())); |
| 95 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); | 97 __ BranchLink(&StubCode::Subtype1TestCacheLabel()); |
| 96 } else if (test_kind == kTestTypeTwoArgs) { | 98 } else if (test_kind == kTestTypeTwoArgs) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 117 Label* is_not_instance_lbl) { | 119 Label* is_not_instance_lbl) { |
| 118 UNIMPLEMENTED(); | 120 UNIMPLEMENTED(); |
| 119 return NULL; | 121 return NULL; |
| 120 } | 122 } |
| 121 | 123 |
| 122 | 124 |
| 123 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 125 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
| 124 const GrowableArray<intptr_t>& class_ids, | 126 const GrowableArray<intptr_t>& class_ids, |
| 125 Label* is_equal_lbl, | 127 Label* is_equal_lbl, |
| 126 Label* is_not_equal_lbl) { | 128 Label* is_not_equal_lbl) { |
| 129 __ TraceSimMsg("CheckClassIds"); |
| 127 for (intptr_t i = 0; i < class_ids.length(); i++) { | 130 for (intptr_t i = 0; i < class_ids.length(); i++) { |
| 128 __ BranchEqual(class_id_reg, class_ids[i], is_equal_lbl); | 131 __ BranchEqual(class_id_reg, class_ids[i], is_equal_lbl); |
| 129 } | 132 } |
| 130 __ b(is_not_equal_lbl); | 133 __ b(is_not_equal_lbl); |
| 131 } | 134 } |
| 132 | 135 |
| 133 | 136 |
| 134 // Testing against an instantiated type with no arguments, without | 137 // Testing against an instantiated type with no arguments, without |
| 135 // SubtypeTestCache. | 138 // SubtypeTestCache. |
| 136 // A0: instance being type checked (preserved). | 139 // A0: instance being type checked (preserved). |
| 137 // Clobbers: T0, T1, T2 | 140 // Clobbers: T0, T1, T2 |
| 138 // Returns true if there is a fallthrough. | 141 // Returns true if there is a fallthrough. |
| 139 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 142 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 140 intptr_t token_pos, | 143 intptr_t token_pos, |
| 141 const AbstractType& type, | 144 const AbstractType& type, |
| 142 Label* is_instance_lbl, | 145 Label* is_instance_lbl, |
| 143 Label* is_not_instance_lbl) { | 146 Label* is_not_instance_lbl) { |
| 147 __ TraceSimMsg("InstantiatedTypeNoArgumentsTest"); |
| 144 __ Comment("InstantiatedTypeNoArgumentsTest"); | 148 __ Comment("InstantiatedTypeNoArgumentsTest"); |
| 145 ASSERT(type.IsInstantiated()); | 149 ASSERT(type.IsInstantiated()); |
| 146 const Class& type_class = Class::Handle(type.type_class()); | 150 const Class& type_class = Class::Handle(type.type_class()); |
| 147 ASSERT(!type_class.HasTypeArguments()); | 151 ASSERT(!type_class.HasTypeArguments()); |
| 148 | 152 |
| 149 const Register kInstanceReg = A0; | 153 const Register kInstanceReg = A0; |
| 150 __ andi(T0, A0, Immediate(kSmiTagMask)); | 154 __ andi(T0, A0, Immediate(kSmiTagMask)); |
| 151 // If instance is Smi, check directly. | 155 // If instance is Smi, check directly. |
| 152 const Class& smi_class = Class::Handle(Smi::Class()); | 156 const Class& smi_class = Class::Handle(Smi::Class()); |
| 153 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 157 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 // Clobbers A1, A2, T0-T3. | 203 // Clobbers A1, A2, T0-T3. |
| 200 // Immediate class test already done. | 204 // Immediate class test already done. |
| 201 // TODO(srdjan): Implement a quicker subtype check, as type test | 205 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 202 // arrays can grow too high, but they may be useful when optimizing | 206 // arrays can grow too high, but they may be useful when optimizing |
| 203 // code (type-feedback). | 207 // code (type-feedback). |
| 204 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( | 208 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| 205 intptr_t token_pos, | 209 intptr_t token_pos, |
| 206 const Class& type_class, | 210 const Class& type_class, |
| 207 Label* is_instance_lbl, | 211 Label* is_instance_lbl, |
| 208 Label* is_not_instance_lbl) { | 212 Label* is_not_instance_lbl) { |
| 213 __ TraceSimMsg("Subtype1TestCacheLookup"); |
| 209 __ Comment("Subtype1TestCacheLookup"); | 214 __ Comment("Subtype1TestCacheLookup"); |
| 210 const Register kInstanceReg = A0; | 215 const Register kInstanceReg = A0; |
| 211 __ LoadClass(T0, kInstanceReg); | 216 __ LoadClass(T0, kInstanceReg); |
| 212 // T0: instance class. | 217 // T0: instance class. |
| 213 // Check immediate superclass equality. | 218 // Check immediate superclass equality. |
| 214 __ lw(T0, FieldAddress(T0, Class::super_type_offset())); | 219 __ lw(T0, FieldAddress(T0, Class::super_type_offset())); |
| 215 __ lw(T0, FieldAddress(T0, Type::type_class_offset())); | 220 __ lw(T0, FieldAddress(T0, Type::type_class_offset())); |
| 216 __ BranchEqual(T0, type_class, is_instance_lbl); | 221 __ BranchEqual(T0, type_class, is_instance_lbl); |
| 217 | 222 |
| 218 const Register kTypeArgumentsReg = kNoRegister; | 223 const Register kTypeArgumentsReg = kNoRegister; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 243 // - preserved instance in A0 and optional instantiator type arguments in A1. | 248 // - preserved instance in A0 and optional instantiator type arguments in A1. |
| 244 // Clobbers: T0, T1, T2 | 249 // Clobbers: T0, T1, T2 |
| 245 // Note that this inlined code must be followed by the runtime_call code, as it | 250 // Note that this inlined code must be followed by the runtime_call code, as it |
| 246 // may fall through to it. Otherwise, this inline code will jump to the label | 251 // may fall through to it. Otherwise, this inline code will jump to the label |
| 247 // is_instance or to the label is_not_instance. | 252 // is_instance or to the label is_not_instance. |
| 248 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 253 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| 249 intptr_t token_pos, | 254 intptr_t token_pos, |
| 250 const AbstractType& type, | 255 const AbstractType& type, |
| 251 Label* is_instance_lbl, | 256 Label* is_instance_lbl, |
| 252 Label* is_not_instance_lbl) { | 257 Label* is_not_instance_lbl) { |
| 258 __ TraceSimMsg("InlineInstanceof"); |
| 253 __ Comment("InlineInstanceof"); | 259 __ Comment("InlineInstanceof"); |
| 254 if (type.IsVoidType()) { | 260 if (type.IsVoidType()) { |
| 255 // A non-null value is returned from a void function, which will result in a | 261 // A non-null value is returned from a void function, which will result in a |
| 256 // type error. A null value is handled prior to executing this inline code. | 262 // type error. A null value is handled prior to executing this inline code. |
| 257 return SubtypeTestCache::null(); | 263 return SubtypeTestCache::null(); |
| 258 } | 264 } |
| 259 if (TypeCheckAsClassEquality(type)) { | 265 if (TypeCheckAsClassEquality(type)) { |
| 260 const intptr_t type_cid = Class::Handle(type.type_class()).id(); | 266 const intptr_t type_cid = Class::Handle(type.type_class()).id(); |
| 261 const Register kInstanceReg = A0; | 267 const Register kInstanceReg = A0; |
| 262 __ andi(T0, kInstanceReg, Immediate(kSmiTagMask)); | 268 __ andi(T0, kInstanceReg, Immediate(kSmiTagMask)); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 // Returns: | 329 // Returns: |
| 324 // - object in A0 for successful assignable check (or throws TypeError). | 330 // - object in A0 for successful assignable check (or throws TypeError). |
| 325 // Clobbers: T0, T1, T2 | 331 // Clobbers: T0, T1, T2 |
| 326 // Performance notes: positive checks must be quick, negative checks can be slow | 332 // Performance notes: positive checks must be quick, negative checks can be slow |
| 327 // as they throw an exception. | 333 // as they throw an exception. |
| 328 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 334 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
| 329 intptr_t deopt_id, | 335 intptr_t deopt_id, |
| 330 const AbstractType& dst_type, | 336 const AbstractType& dst_type, |
| 331 const String& dst_name, | 337 const String& dst_name, |
| 332 LocationSummary* locs) { | 338 LocationSummary* locs) { |
| 339 __ TraceSimMsg("AssertAssignable"); |
| 333 ASSERT(token_pos >= 0); | 340 ASSERT(token_pos >= 0); |
| 334 ASSERT(!dst_type.IsNull()); | 341 ASSERT(!dst_type.IsNull()); |
| 335 ASSERT(dst_type.IsFinalized()); | 342 ASSERT(dst_type.IsFinalized()); |
| 336 // Assignable check is skipped in FlowGraphBuilder, not here. | 343 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 337 ASSERT(dst_type.IsMalformed() || | 344 ASSERT(dst_type.IsMalformed() || |
| 338 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 345 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 339 // Preserve instantiator and its type arguments. | 346 // Preserve instantiator and its type arguments. |
| 340 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 347 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 341 __ sw(A2, Address(SP, 1 * kWordSize)); | 348 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 342 __ sw(A1, Address(SP, 0 * kWordSize)); | 349 __ sw(A1, Address(SP, 0 * kWordSize)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 | 383 |
| 377 // Generate inline type check, linking to runtime call if not assignable. | 384 // Generate inline type check, linking to runtime call if not assignable. |
| 378 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 385 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 379 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 386 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 380 &is_assignable, &runtime_call); | 387 &is_assignable, &runtime_call); |
| 381 | 388 |
| 382 __ Bind(&runtime_call); | 389 __ Bind(&runtime_call); |
| 383 // Load instantiator and its type arguments. | 390 // Load instantiator and its type arguments. |
| 384 __ lw(A1, Address(SP, 0 * kWordSize)); | 391 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 385 __ lw(A2, Address(SP, 1 * kWordSize)); | 392 __ lw(A2, Address(SP, 1 * kWordSize)); |
| 386 __ addiu(SP, SP, Immediate(2 * kWordSize)); | |
| 387 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 393 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 388 __ Push(A0); // Push the source object. | 394 __ Push(A0); // Push the source object. |
| 389 __ PushObject(dst_type); // Push the type of the destination. | 395 __ PushObject(dst_type); // Push the type of the destination. |
| 390 // Push instantiator and its type arguments. | 396 // Push instantiator and its type arguments. |
| 391 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 397 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 392 __ sw(A2, Address(SP, 1 * kWordSize)); | 398 __ sw(A2, Address(SP, 1 * kWordSize)); |
| 393 __ sw(A1, Address(SP, 0 * kWordSize)); | 399 __ sw(A1, Address(SP, 0 * kWordSize)); |
| 394 __ PushObject(dst_name); // Push the name of the destination. | 400 __ PushObject(dst_name); // Push the name of the destination. |
| 395 __ LoadObject(T0, test_cache); | 401 __ LoadObject(T0, test_cache); |
| 396 __ Push(T0); | 402 __ Push(T0); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 Definition* defn = instr->AsDefinition(); | 441 Definition* defn = instr->AsDefinition(); |
| 436 if ((defn != NULL) && defn->is_used()) { | 442 if ((defn != NULL) && defn->is_used()) { |
| 437 __ Push(defn->locs()->out().reg()); | 443 __ Push(defn->locs()->out().reg()); |
| 438 } | 444 } |
| 439 } | 445 } |
| 440 | 446 |
| 441 | 447 |
| 442 // Input parameters: | 448 // Input parameters: |
| 443 // S4: arguments descriptor array. | 449 // S4: arguments descriptor array. |
| 444 void FlowGraphCompiler::CopyParameters() { | 450 void FlowGraphCompiler::CopyParameters() { |
| 451 __ TraceSimMsg("CopyParameters"); |
| 445 __ Comment("Copy parameters"); | 452 __ Comment("Copy parameters"); |
| 446 const Function& function = parsed_function().function(); | 453 const Function& function = parsed_function().function(); |
| 447 LocalScope* scope = parsed_function().node_sequence()->scope(); | 454 LocalScope* scope = parsed_function().node_sequence()->scope(); |
| 448 const int num_fixed_params = function.num_fixed_parameters(); | 455 const int num_fixed_params = function.num_fixed_parameters(); |
| 449 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); | 456 const int num_opt_pos_params = function.NumOptionalPositionalParameters(); |
| 450 const int num_opt_named_params = function.NumOptionalNamedParameters(); | 457 const int num_opt_named_params = function.NumOptionalNamedParameters(); |
| 451 const int num_params = | 458 const int num_params = |
| 452 num_fixed_params + num_opt_pos_params + num_opt_named_params; | 459 num_fixed_params + num_opt_pos_params + num_opt_named_params; |
| 453 ASSERT(function.NumParameters() == num_params); | 460 ASSERT(function.NumParameters() == num_params); |
| 454 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex); | 461 ASSERT(parsed_function().first_parameter_index() == kFirstLocalSlotIndex); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 475 // Let T1 point to the last passed positional argument, i.e. to | 482 // Let T1 point to the last passed positional argument, i.e. to |
| 476 // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)]. | 483 // fp[kLastParamSlotIndex + num_args - 1 - (num_pos_args - 1)]. |
| 477 __ subu(T1, T1, T2); | 484 __ subu(T1, T1, T2); |
| 478 __ sll(T1, T1, 1); | 485 __ sll(T1, T1, 1); |
| 479 __ addu(T1, FP, T1); | 486 __ addu(T1, FP, T1); |
| 480 __ AddImmediate(T1, kLastParamSlotIndex * kWordSize); | 487 __ AddImmediate(T1, kLastParamSlotIndex * kWordSize); |
| 481 | 488 |
| 482 // Let T0 point to the last copied positional argument, i.e. to | 489 // Let T0 point to the last copied positional argument, i.e. to |
| 483 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. | 490 // fp[kFirstLocalSlotIndex - (num_pos_args - 1)]. |
| 484 __ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize); | 491 __ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize); |
| 485 __ sll(T3, T2, 1); // T2 is a Smi. | 492 __ sll(T2, T2, 1); // T2 is a Smi. |
| 486 __ subu(T0, T0, T3); | |
| 487 | 493 |
| 488 Label loop, loop_condition; | 494 Label loop, loop_condition; |
| 489 __ b(&loop_condition); | 495 __ b(&loop_condition); |
| 490 __ delay_slot()->SmiUntag(T2); | 496 __ delay_slot()->subu(T0, T0, T2); |
| 491 // We do not use the final allocation index of the variable here, i.e. | 497 // We do not use the final allocation index of the variable here, i.e. |
| 492 // scope->VariableAt(i)->index(), because captured variables still need | 498 // scope->VariableAt(i)->index(), because captured variables still need |
| 493 // to be copied to the context that is not yet allocated. | 499 // to be copied to the context that is not yet allocated. |
| 494 __ Bind(&loop); | 500 __ Bind(&loop); |
| 495 __ addu(T4, T1, T2); | 501 __ addu(T4, T1, T2); |
| 496 __ addu(T5, T0, T2); | 502 __ addu(T5, T0, T2); |
| 497 __ lw(T3, Address(T4)); | 503 __ lw(T3, Address(T4)); |
| 498 __ sw(T3, Address(T5)); | 504 __ sw(T3, Address(T5)); |
| 499 __ Bind(&loop_condition); | 505 __ Bind(&loop_condition); |
| 500 __ addiu(T2, T2, Immediate(-kWordSize)); | 506 __ addiu(T2, T2, Immediate(-kWordSize)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 // scope->VariableAt(i)->index(), because captured variables still need | 572 // scope->VariableAt(i)->index(), because captured variables still need |
| 567 // to be copied to the context that is not yet allocated. | 573 // to be copied to the context that is not yet allocated. |
| 568 const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; | 574 const intptr_t computed_param_pos = kFirstLocalSlotIndex - param_pos; |
| 569 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); | 575 __ sw(T3, Address(FP, computed_param_pos * kWordSize)); |
| 570 } | 576 } |
| 571 delete[] opt_param; | 577 delete[] opt_param; |
| 572 delete[] opt_param_position; | 578 delete[] opt_param_position; |
| 573 // Check that T0 now points to the null terminator in the array descriptor. | 579 // Check that T0 now points to the null terminator in the array descriptor. |
| 574 __ lw(T3, Address(T0)); | 580 __ lw(T3, Address(T0)); |
| 575 __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()), | 581 __ BranchEqual(T3, reinterpret_cast<int32_t>(Object::null()), |
| 576 &all_arguments_processed); | 582 &all_arguments_processed); |
| 577 } else { | 583 } else { |
| 578 ASSERT(num_opt_pos_params > 0); | 584 ASSERT(num_opt_pos_params > 0); |
| 579 __ lw(T2, | 585 __ lw(T2, |
| 580 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); | 586 FieldAddress(S4, ArgumentsDescriptor::positional_count_offset())); |
| 581 __ SmiUntag(T2); | 587 __ SmiUntag(T2); |
| 582 for (int i = 0; i < num_opt_pos_params; i++) { | 588 for (int i = 0; i < num_opt_pos_params; i++) { |
| 583 Label next_parameter; | 589 Label next_parameter; |
| 584 // Handle this optional positional parameter only if k or fewer positional | 590 // Handle this optional positional parameter only if k or fewer positional |
| 585 // arguments have been passed, where k is param_pos, the position of this | 591 // arguments have been passed, where k is param_pos, the position of this |
| 586 // optional parameter in the formal parameter list. | 592 // optional parameter in the formal parameter list. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 | 650 |
| 645 __ Bind(&all_arguments_processed); | 651 __ Bind(&all_arguments_processed); |
| 646 // Nullify originally passed arguments only after they have been copied and | 652 // Nullify originally passed arguments only after they have been copied and |
| 647 // checked, otherwise noSuchMethod would not see their original values. | 653 // checked, otherwise noSuchMethod would not see their original values. |
| 648 // This step can be skipped in case we decide that formal parameters are | 654 // This step can be skipped in case we decide that formal parameters are |
| 649 // implicitly final, since garbage collecting the unmodified value is not | 655 // implicitly final, since garbage collecting the unmodified value is not |
| 650 // an issue anymore. | 656 // an issue anymore. |
| 651 | 657 |
| 652 // S4 : arguments descriptor array. | 658 // S4 : arguments descriptor array. |
| 653 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 659 __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 654 __ SmiUntag(T2); | 660 __ sll(T2, T2, 1); // T2 is a Smi. |
| 655 | 661 |
| 656 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | 662 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); |
| 657 Label null_args_loop, null_args_loop_condition; | 663 Label null_args_loop, null_args_loop_condition; |
| 664 |
| 658 __ b(&null_args_loop_condition); | 665 __ b(&null_args_loop_condition); |
| 659 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize)); | 666 __ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize)); |
| 667 |
| 660 __ Bind(&null_args_loop); | 668 __ Bind(&null_args_loop); |
| 661 __ addu(T3, T1, T2); | 669 __ addu(T3, T1, T2); |
| 662 __ sw(T0, Address(T3)); | 670 __ sw(T0, Address(T3)); |
| 671 |
| 663 __ Bind(&null_args_loop_condition); | 672 __ Bind(&null_args_loop_condition); |
| 664 __ addiu(T2, T2, Immediate(-kWordSize)); | 673 __ addiu(T2, T2, Immediate(-kWordSize)); |
| 665 __ bgez(T2, &null_args_loop); | 674 __ bgez(T2, &null_args_loop); |
| 666 } | 675 } |
| 667 | 676 |
| 668 | 677 |
| 669 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 678 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 670 UNIMPLEMENTED(); | 679 // RA: return address. |
| 680 // SP: receiver. |
| 681 // Sequence node has one return node, its input is load field node. |
| 682 __ lw(V0, Address(SP, 0 * kWordSize)); |
| 683 __ lw(V0, Address(V0, offset - kHeapObjectTag)); |
| 684 __ Ret(); |
| 671 } | 685 } |
| 672 | 686 |
| 673 | 687 |
| 674 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 688 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 675 UNIMPLEMENTED(); | 689 // RA: return address. |
| 690 // SP+1: receiver. |
| 691 // SP+0: value. |
| 692 // Sequence node has one store node and one return NULL node. |
| 693 __ lw(T0, Address(SP, 1 * kWordSize)); // Receiver. |
| 694 __ lw(T1, Address(SP, 0 * kWordSize)); // Value. |
| 695 __ StoreIntoObject(T0, FieldAddress(T0, offset), T1); |
| 696 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null())); |
| 697 __ Ret(); |
| 676 } | 698 } |
| 677 | 699 |
| 678 | 700 |
| 679 void FlowGraphCompiler::EmitFrameEntry() { | 701 void FlowGraphCompiler::EmitFrameEntry() { |
| 702 __ TraceSimMsg("FrameEntry"); |
| 680 const Function& function = parsed_function().function(); | 703 const Function& function = parsed_function().function(); |
| 681 if (CanOptimizeFunction() && function.is_optimizable()) { | 704 if (CanOptimizeFunction() && function.is_optimizable()) { |
| 682 const bool can_optimize = !is_optimizing() || may_reoptimize(); | 705 const bool can_optimize = !is_optimizing() || may_reoptimize(); |
| 683 const Register function_reg = T0; | 706 const Register function_reg = T0; |
| 684 if (can_optimize) { | 707 if (can_optimize) { |
| 685 Label next; | 708 Label next; |
| 686 // The pool pointer is not setup before entering the Dart frame. | 709 // The pool pointer is not setup before entering the Dart frame. |
| 687 | 710 |
| 688 __ mov(TMP1, RA); // Save RA. | 711 __ mov(TMP1, RA); // Save RA. |
| 689 __ bal(&next); // Branch and link to next instruction to get PC in RA. | 712 __ bal(&next); // Branch and link to next instruction to get PC in RA. |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 779 LocalVariable* saved_args_desc_var = | 802 LocalVariable* saved_args_desc_var = |
| 780 parsed_function().GetSavedArgumentsDescriptorVar(); | 803 parsed_function().GetSavedArgumentsDescriptorVar(); |
| 781 if (num_copied_params == 0) { | 804 if (num_copied_params == 0) { |
| 782 #ifdef DEBUG | 805 #ifdef DEBUG |
| 783 ASSERT(!parsed_function().function().HasOptionalParameters()); | 806 ASSERT(!parsed_function().function().HasOptionalParameters()); |
| 784 const bool check_arguments = true; | 807 const bool check_arguments = true; |
| 785 #else | 808 #else |
| 786 const bool check_arguments = function.IsClosureFunction(); | 809 const bool check_arguments = function.IsClosureFunction(); |
| 787 #endif | 810 #endif |
| 788 if (check_arguments) { | 811 if (check_arguments) { |
| 812 __ TraceSimMsg("Check argument count"); |
| 789 __ Comment("Check argument count"); | 813 __ Comment("Check argument count"); |
| 790 // Check that exactly num_fixed arguments are passed in. | 814 // Check that exactly num_fixed arguments are passed in. |
| 791 Label correct_num_arguments, wrong_num_arguments; | 815 Label correct_num_arguments, wrong_num_arguments; |
| 792 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 816 __ lw(T0, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
| 793 __ BranchNotEqual(T0, Smi::RawValue(num_fixed_params), | 817 __ BranchNotEqual(T0, Smi::RawValue(num_fixed_params), |
| 794 &wrong_num_arguments); | 818 &wrong_num_arguments); |
| 795 | 819 |
| 796 __ lw(T1, FieldAddress(S4, | 820 __ lw(T1, FieldAddress(S4, |
| 797 ArgumentsDescriptor::positional_count_offset())); | 821 ArgumentsDescriptor::positional_count_offset())); |
| 798 __ beq(T0, T1, &correct_num_arguments); | 822 __ beq(T0, T1, &correct_num_arguments); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 ASSERT(saved_args_desc_var->is_captured() || | 875 ASSERT(saved_args_desc_var->is_captured() || |
| 852 (saved_args_desc_var->index() == slot)); | 876 (saved_args_desc_var->index() == slot)); |
| 853 __ sw(kArgumentsDescriptorReg, Address(FP, slot * kWordSize)); | 877 __ sw(kArgumentsDescriptorReg, Address(FP, slot * kWordSize)); |
| 854 } | 878 } |
| 855 CopyParameters(); | 879 CopyParameters(); |
| 856 } | 880 } |
| 857 | 881 |
| 858 // In unoptimized code, initialize (non-argument) stack allocated slots to | 882 // In unoptimized code, initialize (non-argument) stack allocated slots to |
| 859 // null. This does not cover the saved_args_desc_var slot. | 883 // null. This does not cover the saved_args_desc_var slot. |
| 860 if (!is_optimizing() && (num_locals > 0)) { | 884 if (!is_optimizing() && (num_locals > 0)) { |
| 885 __ TraceSimMsg("Initialize spill slots"); |
| 861 __ Comment("Initialize spill slots"); | 886 __ Comment("Initialize spill slots"); |
| 862 const intptr_t slot_base = parsed_function().first_stack_local_index(); | 887 const intptr_t slot_base = parsed_function().first_stack_local_index(); |
| 863 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); | 888 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); |
| 864 for (intptr_t i = 0; i < num_locals; ++i) { | 889 for (intptr_t i = 0; i < num_locals; ++i) { |
| 865 // Subtract index i (locals lie at lower addresses than FP). | 890 // Subtract index i (locals lie at lower addresses than FP). |
| 866 __ sw(T0, Address(FP, (slot_base - i) * kWordSize)); | 891 __ sw(T0, Address(FP, (slot_base - i) * kWordSize)); |
| 867 } | 892 } |
| 868 } | 893 } |
| 869 | 894 |
| 870 if (FLAG_print_scopes) { | 895 if (FLAG_print_scopes) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 891 Isolate::kNoDeoptId, | 916 Isolate::kNoDeoptId, |
| 892 0); // No token position. | 917 0); // No token position. |
| 893 __ Branch(&StubCode::DeoptimizeLazyLabel()); | 918 __ Branch(&StubCode::DeoptimizeLazyLabel()); |
| 894 } | 919 } |
| 895 | 920 |
| 896 | 921 |
| 897 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 922 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 898 const ExternalLabel* label, | 923 const ExternalLabel* label, |
| 899 PcDescriptors::Kind kind, | 924 PcDescriptors::Kind kind, |
| 900 LocationSummary* locs) { | 925 LocationSummary* locs) { |
| 926 __ TraceSimMsg("Call"); |
| 901 __ BranchLinkPatchable(label); | 927 __ BranchLinkPatchable(label); |
| 902 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); | 928 AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); |
| 903 RecordSafepoint(locs); | 929 RecordSafepoint(locs); |
| 904 } | 930 } |
| 905 | 931 |
| 906 | 932 |
| 907 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 933 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
| 908 intptr_t token_pos, | 934 intptr_t token_pos, |
| 909 const ExternalLabel* label, | 935 const ExternalLabel* label, |
| 910 PcDescriptors::Kind kind, | 936 PcDescriptors::Kind kind, |
| 911 LocationSummary* locs) { | 937 LocationSummary* locs) { |
| 938 __ TraceSimMsg("DartCall"); |
| 912 __ BranchLinkPatchable(label); | 939 __ BranchLinkPatchable(label); |
| 913 AddCurrentDescriptor(kind, deopt_id, token_pos); | 940 AddCurrentDescriptor(kind, deopt_id, token_pos); |
| 914 RecordSafepoint(locs); | 941 RecordSafepoint(locs); |
| 915 // Marks either the continuation point in unoptimized code or the | 942 // Marks either the continuation point in unoptimized code or the |
| 916 // deoptimization point in optimized code, after call. | 943 // deoptimization point in optimized code, after call. |
| 917 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | 944 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); |
| 918 if (is_optimizing()) { | 945 if (is_optimizing()) { |
| 919 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 946 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 920 } else { | 947 } else { |
| 921 // Add deoptimization continuation point after the call and before the | 948 // Add deoptimization continuation point after the call and before the |
| 922 // arguments are removed. | 949 // arguments are removed. |
| 923 AddCurrentDescriptor(PcDescriptors::kDeopt, | 950 AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 924 deopt_id_after, | 951 deopt_id_after, |
| 925 token_pos); | 952 token_pos); |
| 926 } | 953 } |
| 927 } | 954 } |
| 928 | 955 |
| 929 | 956 |
| 930 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, | 957 void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos, |
| 931 intptr_t deopt_id, | 958 intptr_t deopt_id, |
| 932 const RuntimeEntry& entry, | 959 const RuntimeEntry& entry, |
| 933 LocationSummary* locs) { | 960 LocationSummary* locs) { |
| 961 __ TraceSimMsg("CallRuntime"); |
| 934 __ CallRuntime(entry); | 962 __ CallRuntime(entry); |
| 935 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | 963 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); |
| 936 RecordSafepoint(locs); | 964 RecordSafepoint(locs); |
| 937 if (deopt_id != Isolate::kNoDeoptId) { | 965 if (deopt_id != Isolate::kNoDeoptId) { |
| 938 // Marks either the continuation point in unoptimized code or the | 966 // Marks either the continuation point in unoptimized code or the |
| 939 // deoptimization point in optimized code, after call. | 967 // deoptimization point in optimized code, after call. |
| 940 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | 968 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); |
| 941 if (is_optimizing()) { | 969 if (is_optimizing()) { |
| 942 AddDeoptIndexAtCall(deopt_id_after, token_pos); | 970 AddDeoptIndexAtCall(deopt_id_after, token_pos); |
| 943 } else { | 971 } else { |
| 944 // Add deoptimization continuation point after the call and before the | 972 // Add deoptimization continuation point after the call and before the |
| 945 // arguments are removed. | 973 // arguments are removed. |
| 946 AddCurrentDescriptor(PcDescriptors::kDeopt, | 974 AddCurrentDescriptor(PcDescriptors::kDeopt, |
| 947 deopt_id_after, | 975 deopt_id_after, |
| 948 token_pos); | 976 token_pos); |
| 949 } | 977 } |
| 950 } | 978 } |
| 979 __ TraceSimMsg("CallRuntime return"); |
| 951 } | 980 } |
| 952 | 981 |
| 953 | 982 |
| 954 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 983 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 955 ExternalLabel* target_label, | 984 ExternalLabel* target_label, |
| 956 const ICData& ic_data, | 985 const ICData& ic_data, |
| 957 const Array& arguments_descriptor, | 986 const Array& arguments_descriptor, |
| 958 intptr_t argument_count, | 987 intptr_t argument_count, |
| 959 intptr_t deopt_id, | 988 intptr_t deopt_id, |
| 960 intptr_t token_pos, | 989 intptr_t token_pos, |
| 961 LocationSummary* locs) { | 990 LocationSummary* locs) { |
| 962 UNIMPLEMENTED(); | 991 UNIMPLEMENTED(); |
| 963 } | 992 } |
| 964 | 993 |
| 965 | 994 |
| 966 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, | 995 void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label, |
| 967 const ICData& ic_data, | 996 const ICData& ic_data, |
| 968 const Array& arguments_descriptor, | 997 const Array& arguments_descriptor, |
| 969 intptr_t argument_count, | 998 intptr_t argument_count, |
| 970 intptr_t deopt_id, | 999 intptr_t deopt_id, |
| 971 intptr_t token_pos, | 1000 intptr_t token_pos, |
| 972 LocationSummary* locs) { | 1001 LocationSummary* locs) { |
| 1002 __ TraceSimMsg("InstanceCall"); |
| 973 __ LoadObject(S4, arguments_descriptor); | 1003 __ LoadObject(S4, arguments_descriptor); |
| 974 __ LoadObject(S5, ic_data); | 1004 __ LoadObject(S5, ic_data); |
| 975 GenerateDartCall(deopt_id, | 1005 GenerateDartCall(deopt_id, |
| 976 token_pos, | 1006 token_pos, |
| 977 target_label, | 1007 target_label, |
| 978 PcDescriptors::kIcCall, | 1008 PcDescriptors::kIcCall, |
| 979 locs); | 1009 locs); |
| 1010 __ TraceSimMsg("InstanceCall return"); |
| 980 __ Drop(argument_count); | 1011 __ Drop(argument_count); |
| 981 } | 1012 } |
| 982 | 1013 |
| 983 | 1014 |
| 984 void FlowGraphCompiler::EmitMegamorphicInstanceCall( | 1015 void FlowGraphCompiler::EmitMegamorphicInstanceCall( |
| 985 const ICData& ic_data, | 1016 const ICData& ic_data, |
| 986 const Array& arguments_descriptor, | 1017 const Array& arguments_descriptor, |
| 987 intptr_t argument_count, | 1018 intptr_t argument_count, |
| 988 intptr_t deopt_id, | 1019 intptr_t deopt_id, |
| 989 intptr_t token_pos, | 1020 intptr_t token_pos, |
| 990 LocationSummary* locs) { | 1021 LocationSummary* locs) { |
| 991 UNIMPLEMENTED(); | 1022 UNIMPLEMENTED(); |
| 992 } | 1023 } |
| 993 | 1024 |
| 994 | 1025 |
| 995 void FlowGraphCompiler::EmitStaticCall(const Function& function, | 1026 void FlowGraphCompiler::EmitStaticCall(const Function& function, |
| 996 const Array& arguments_descriptor, | 1027 const Array& arguments_descriptor, |
| 997 intptr_t argument_count, | 1028 intptr_t argument_count, |
| 998 intptr_t deopt_id, | 1029 intptr_t deopt_id, |
| 999 intptr_t token_pos, | 1030 intptr_t token_pos, |
| 1000 LocationSummary* locs) { | 1031 LocationSummary* locs) { |
| 1032 __ TraceSimMsg("StaticCall"); |
| 1001 __ LoadObject(S4, arguments_descriptor); | 1033 __ LoadObject(S4, arguments_descriptor); |
| 1002 // Do not use the code from the function, but let the code be patched so that | 1034 // Do not use the code from the function, but let the code be patched so that |
| 1003 // we can record the outgoing edges to other code. | 1035 // we can record the outgoing edges to other code. |
| 1004 GenerateDartCall(deopt_id, | 1036 GenerateDartCall(deopt_id, |
| 1005 token_pos, | 1037 token_pos, |
| 1006 &StubCode::CallStaticFunctionLabel(), | 1038 &StubCode::CallStaticFunctionLabel(), |
| 1007 PcDescriptors::kFuncCall, | 1039 PcDescriptors::kFuncCall, |
| 1008 locs); | 1040 locs); |
| 1009 AddStaticCallTarget(function); | 1041 AddStaticCallTarget(function); |
| 1010 __ Drop(argument_count); | 1042 __ Drop(argument_count); |
| 1011 } | 1043 } |
| 1012 | 1044 |
| 1013 | 1045 |
| 1014 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, | 1046 void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg, |
| 1015 const Object& obj, | 1047 const Object& obj, |
| 1016 bool needs_number_check) { | 1048 bool needs_number_check) { |
| 1017 UNIMPLEMENTED(); | 1049 UNIMPLEMENTED(); |
| 1018 } | 1050 } |
| 1019 | 1051 |
| 1020 | 1052 |
| 1021 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, | 1053 void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left, |
| 1022 Register right, | 1054 Register right, |
| 1023 bool needs_number_check) { | 1055 bool needs_number_check) { |
| 1056 __ TraceSimMsg("EqualityRegRegCompare"); |
| 1024 if (needs_number_check) { | 1057 if (needs_number_check) { |
| 1025 __ Push(left); | 1058 __ Push(left); |
| 1026 __ Push(right); | 1059 __ Push(right); |
| 1027 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); | 1060 __ BranchLink(&StubCode::IdenticalWithNumberCheckLabel()); |
| 1028 // Stub returns result in CMPRES. If it is 0, then left and right are equal. | 1061 // Stub returns result in CMPRES. If it is 0, then left and right are equal. |
| 1029 __ Pop(right); | 1062 __ Pop(right); |
| 1030 __ Pop(left); | 1063 __ Pop(left); |
| 1031 } else { | 1064 } else { |
| 1032 __ subu(CMPRES, left, right); | 1065 __ subu(CMPRES, left, right); |
| 1033 } | 1066 } |
| 1034 } | 1067 } |
| 1035 | 1068 |
| 1036 | 1069 |
| 1037 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, | 1070 void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result, |
| 1038 Label* skip_call) { | 1071 Label* skip_call) { |
| 1039 UNIMPLEMENTED(); | 1072 UNIMPLEMENTED(); |
| 1040 } | 1073 } |
| 1041 | 1074 |
| 1042 | 1075 |
| 1043 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 1076 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 1077 __ TraceSimMsg("SaveLiveRegisters"); |
| 1044 // TODO(vegorov): consider saving only caller save (volatile) registers. | 1078 // TODO(vegorov): consider saving only caller save (volatile) registers. |
| 1045 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); | 1079 const intptr_t fpu_registers = locs->live_registers()->fpu_registers(); |
| 1046 if (fpu_registers > 0) { | 1080 if (fpu_registers > 0) { |
| 1047 UNIMPLEMENTED(); | 1081 UNIMPLEMENTED(); |
| 1048 } | 1082 } |
| 1049 | 1083 |
| 1050 // Store general purpose registers with the lowest register number at the | 1084 // Store general purpose registers with the lowest register number at the |
| 1051 // lowest address. | 1085 // lowest address. |
| 1052 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); | 1086 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); |
| 1053 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); | 1087 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); |
| 1054 const int register_count = Utils::CountOneBits(cpu_registers); | 1088 const int register_count = Utils::CountOneBits(cpu_registers); |
| 1055 int registers_pushed = 0; | 1089 int registers_pushed = 0; |
| 1056 | 1090 |
| 1057 __ addiu(SP, SP, Immediate(-register_count * kWordSize)); | 1091 __ addiu(SP, SP, Immediate(-register_count * kWordSize)); |
| 1058 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 1092 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 1059 Register r = static_cast<Register>(i); | 1093 Register r = static_cast<Register>(i); |
| 1060 if (locs->live_registers()->ContainsRegister(r)) { | 1094 if (locs->live_registers()->ContainsRegister(r)) { |
| 1061 __ sw(r, Address(SP, registers_pushed * kWordSize)); | 1095 __ sw(r, Address(SP, registers_pushed * kWordSize)); |
| 1062 registers_pushed++; | 1096 registers_pushed++; |
| 1063 } | 1097 } |
| 1064 } | 1098 } |
| 1065 } | 1099 } |
| 1066 | 1100 |
| 1067 | 1101 |
| 1068 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { | 1102 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { |
| 1069 // General purpose registers have the lowest register number at the | 1103 // General purpose registers have the lowest register number at the |
| 1070 // lowest address. | 1104 // lowest address. |
| 1105 __ TraceSimMsg("RestoreLiveRegisters"); |
| 1071 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); | 1106 const intptr_t cpu_registers = locs->live_registers()->cpu_registers(); |
| 1072 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); | 1107 ASSERT((cpu_registers & ~kAllCpuRegistersList) == 0); |
| 1073 const int register_count = Utils::CountOneBits(cpu_registers); | 1108 const int register_count = Utils::CountOneBits(cpu_registers); |
| 1074 int registers_popped = 0; | 1109 int registers_popped = 0; |
| 1075 | 1110 |
| 1076 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 1111 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 1077 Register r = static_cast<Register>(i); | 1112 Register r = static_cast<Register>(i); |
| 1078 if (locs->live_registers()->ContainsRegister(r)) { | 1113 if (locs->live_registers()->ContainsRegister(r)) { |
| 1079 __ lw(r, Address(SP, registers_popped * kWordSize)); | 1114 __ lw(r, Address(SP, registers_popped * kWordSize)); |
| 1080 registers_popped++; | 1115 registers_popped++; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1165 UNIMPLEMENTED(); | 1200 UNIMPLEMENTED(); |
| 1166 return FieldAddress(array, index); | 1201 return FieldAddress(array, index); |
| 1167 } | 1202 } |
| 1168 | 1203 |
| 1169 | 1204 |
| 1170 #undef __ | 1205 #undef __ |
| 1171 #define __ compiler_->assembler()-> | 1206 #define __ compiler_->assembler()-> |
| 1172 | 1207 |
| 1173 | 1208 |
| 1174 void ParallelMoveResolver::EmitMove(int index) { | 1209 void ParallelMoveResolver::EmitMove(int index) { |
| 1210 __ TraceSimMsg("ParallelMoveResolver::EmitMove"); |
| 1175 MoveOperands* move = moves_[index]; | 1211 MoveOperands* move = moves_[index]; |
| 1176 const Location source = move->src(); | 1212 const Location source = move->src(); |
| 1177 const Location destination = move->dest(); | 1213 const Location destination = move->dest(); |
| 1178 | 1214 |
| 1179 if (source.IsRegister()) { | 1215 if (source.IsRegister()) { |
| 1180 if (destination.IsRegister()) { | 1216 if (destination.IsRegister()) { |
| 1181 __ mov(destination.reg(), source.reg()); | 1217 __ mov(destination.reg(), source.reg()); |
| 1182 } else { | 1218 } else { |
| 1183 ASSERT(destination.IsStackSlot()); | 1219 ASSERT(destination.IsStackSlot()); |
| 1184 __ sw(source.reg(), destination.ToStackSlotAddress()); | 1220 __ sw(source.reg(), destination.ToStackSlotAddress()); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 ASSERT(destination.IsStackSlot()); | 1257 ASSERT(destination.IsStackSlot()); |
| 1222 StoreObject(destination.ToStackSlotAddress(), source.constant()); | 1258 StoreObject(destination.ToStackSlotAddress(), source.constant()); |
| 1223 } | 1259 } |
| 1224 } | 1260 } |
| 1225 | 1261 |
| 1226 move->Eliminate(); | 1262 move->Eliminate(); |
| 1227 } | 1263 } |
| 1228 | 1264 |
| 1229 | 1265 |
| 1230 void ParallelMoveResolver::EmitSwap(int index) { | 1266 void ParallelMoveResolver::EmitSwap(int index) { |
| 1267 __ TraceSimMsg("ParallelMoveResolver::EmitSwap"); |
| 1231 MoveOperands* move = moves_[index]; | 1268 MoveOperands* move = moves_[index]; |
| 1232 const Location source = move->src(); | 1269 const Location source = move->src(); |
| 1233 const Location destination = move->dest(); | 1270 const Location destination = move->dest(); |
| 1234 | 1271 |
| 1235 if (source.IsRegister() && destination.IsRegister()) { | 1272 if (source.IsRegister() && destination.IsRegister()) { |
| 1236 ASSERT(source.reg() != TMP1); | 1273 ASSERT(source.reg() != TMP1); |
| 1237 ASSERT(destination.reg() != TMP1); | 1274 ASSERT(destination.reg() != TMP1); |
| 1238 __ mov(TMP1, source.reg()); | 1275 __ mov(TMP1, source.reg()); |
| 1239 __ mov(source.reg(), destination.reg()); | 1276 __ mov(source.reg(), destination.reg()); |
| 1240 __ mov(destination.reg(), TMP1); | 1277 __ mov(destination.reg(), TMP1); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 moves_[i]->set_src(destination); | 1333 moves_[i]->set_src(destination); |
| 1297 } else if (other_move.Blocks(destination)) { | 1334 } else if (other_move.Blocks(destination)) { |
| 1298 moves_[i]->set_src(source); | 1335 moves_[i]->set_src(source); |
| 1299 } | 1336 } |
| 1300 } | 1337 } |
| 1301 } | 1338 } |
| 1302 | 1339 |
| 1303 | 1340 |
| 1304 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, | 1341 void ParallelMoveResolver::MoveMemoryToMemory(const Address& dst, |
| 1305 const Address& src) { | 1342 const Address& src) { |
| 1343 __ TraceSimMsg("ParallelMoveResolver::MoveMemoryToMemory"); |
| 1306 __ lw(TMP1, src); | 1344 __ lw(TMP1, src); |
| 1307 __ sw(TMP1, dst); | 1345 __ sw(TMP1, dst); |
| 1308 } | 1346 } |
| 1309 | 1347 |
| 1310 | 1348 |
| 1311 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { | 1349 void ParallelMoveResolver::StoreObject(const Address& dst, const Object& obj) { |
| 1350 __ TraceSimMsg("ParallelMoveResolver::StoreObject"); |
| 1312 __ LoadObject(TMP1, obj); | 1351 __ LoadObject(TMP1, obj); |
| 1313 __ sw(TMP1, dst); | 1352 __ sw(TMP1, dst); |
| 1314 } | 1353 } |
| 1315 | 1354 |
| 1316 | 1355 |
| 1317 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { | 1356 void ParallelMoveResolver::Exchange(Register reg, const Address& mem) { |
| 1357 __ TraceSimMsg("ParallelMoveResolver::Exchange ra"); |
| 1318 ASSERT(reg != TMP1); | 1358 ASSERT(reg != TMP1); |
| 1319 __ mov(TMP1, reg); | 1359 __ mov(TMP1, reg); |
| 1320 __ lw(reg, mem); | 1360 __ lw(reg, mem); |
| 1321 __ sw(TMP1, mem); | 1361 __ sw(TMP1, mem); |
| 1322 } | 1362 } |
| 1323 | 1363 |
| 1324 | 1364 |
| 1325 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { | 1365 void ParallelMoveResolver::Exchange(const Address& mem1, const Address& mem2) { |
| 1366 __ TraceSimMsg("ParallelMoveResolver::Exchange aa"); |
| 1326 ScratchRegisterScope ensure_scratch(this, TMP1); | 1367 ScratchRegisterScope ensure_scratch(this, TMP1); |
| 1327 __ lw(ensure_scratch.reg(), mem1); | 1368 __ lw(ensure_scratch.reg(), mem1); |
| 1328 __ lw(TMP1, mem2); | 1369 __ lw(TMP1, mem2); |
| 1329 __ sw(ensure_scratch.reg(), mem2); | 1370 __ sw(ensure_scratch.reg(), mem2); |
| 1330 __ sw(TMP1, mem1); | 1371 __ sw(TMP1, mem1); |
| 1331 } | 1372 } |
| 1332 | 1373 |
| 1333 | 1374 |
| 1334 void ParallelMoveResolver::SpillScratch(Register reg) { | 1375 void ParallelMoveResolver::SpillScratch(Register reg) { |
| 1376 __ TraceSimMsg("ParallelMoveResolver::SpillScratch"); |
| 1335 __ Push(reg); | 1377 __ Push(reg); |
| 1336 } | 1378 } |
| 1337 | 1379 |
| 1338 | 1380 |
| 1339 void ParallelMoveResolver::RestoreScratch(Register reg) { | 1381 void ParallelMoveResolver::RestoreScratch(Register reg) { |
| 1382 __ TraceSimMsg("ParallelMoveResolver::RestoreScratch"); |
| 1340 __ Pop(reg); | 1383 __ Pop(reg); |
| 1341 } | 1384 } |
| 1342 | 1385 |
| 1343 | 1386 |
| 1344 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { | 1387 void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { |
| 1388 __ TraceSimMsg("ParallelMoveResolver::SpillFpuScratch"); |
| 1345 __ AddImmediate(SP, -kDoubleSize); | 1389 __ AddImmediate(SP, -kDoubleSize); |
| 1346 __ sdc1(reg, Address(SP)); | 1390 __ sdc1(reg, Address(SP)); |
| 1347 } | 1391 } |
| 1348 | 1392 |
| 1349 | 1393 |
| 1350 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1394 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 1395 __ TraceSimMsg("ParallelMoveResolver::RestoreFpuScratch"); |
| 1351 __ ldc1(reg, Address(SP)); | 1396 __ ldc1(reg, Address(SP)); |
| 1352 __ AddImmediate(SP, kDoubleSize); | 1397 __ AddImmediate(SP, kDoubleSize); |
| 1353 } | 1398 } |
| 1354 | 1399 |
| 1355 | 1400 |
| 1356 #undef __ | 1401 #undef __ |
| 1357 | 1402 |
| 1358 | 1403 |
| 1359 } // namespace dart | 1404 } // namespace dart |
| 1360 | 1405 |
| 1361 #endif // defined TARGET_ARCH_MIPS | 1406 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |