| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 // .... | 334 // .... |
| 335 __ CallRuntime(kInstanceFunctionLookupRuntimeEntry); | 335 __ CallRuntime(kInstanceFunctionLookupRuntimeEntry); |
| 336 // Remove arguments. | 336 // Remove arguments. |
| 337 __ lw(V0, Address(SP, 4 * kWordSize)); | 337 __ lw(V0, Address(SP, 4 * kWordSize)); |
| 338 __ addiu(SP, SP, Immediate(5 * kWordSize)); // Get result into V0. | 338 __ addiu(SP, SP, Immediate(5 * kWordSize)); // Get result into V0. |
| 339 __ LeaveStubFrame(); | 339 __ LeaveStubFrame(); |
| 340 __ Ret(); | 340 __ Ret(); |
| 341 } | 341 } |
| 342 | 342 |
| 343 | 343 |
| 344 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
| 345 intptr_t deopt_reason, |
| 346 uword saved_registers_address); |
| 347 |
| 348 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); |
| 349 |
| 350 |
| 351 // Used by eager and lazy deoptimization. Preserve result in V0 if necessary. |
| 352 // This stub translates optimized frame into unoptimized frame. The optimized |
| 353 // frame can contain values in registers and on stack, the unoptimized |
| 354 // frame contains all values on stack. |
| 355 // Deoptimization occurs in following steps: |
| 356 // - Push all registers that can contain values. |
| 357 // - Call C routine to copy the stack and saved registers into temporary buffer. |
| 358 // - Adjust caller's frame to correct unoptimized frame size. |
| 359 // - Fill the unoptimized frame. |
| 360 // - Materialize objects that require allocation (e.g. Double instances). |
| 361 // GC can occur only after frame is fully rewritten. |
| 362 // Stack after EnterFrame(...) below: |
| 363 // +------------------+ |
| 364 // | Saved FP | <- TOS |
| 365 // +------------------+ |
| 366 // | return-address | (deoptimization point) |
| 367 // +------------------+ |
| 368 // | optimized frame | |
| 369 // | ... | |
| 370 // |
| 371 // Parts of the code cannot GC, part of the code can GC. |
| 372 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 373 bool preserve_result) { |
| 374 const intptr_t kPushedRegistersSize = |
| 375 kNumberOfCpuRegisters * kWordSize + |
| 376 2 * kWordSize + // FP and RA. |
| 377 kNumberOfFRegisters * kWordSize; |
| 378 |
| 379 __ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize)); |
| 380 __ sw(RA, Address(SP, kPushedRegistersSize - 1 * kWordSize)); |
| 381 __ sw(FP, Address(SP, kPushedRegistersSize - 2 * kWordSize)); |
| 382 __ addiu(FP, SP, Immediate(kPushedRegistersSize - 2 * kWordSize)); |
| 383 |
| 384 |
| 385 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 386 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 387 const intptr_t saved_v0_offset_from_fp = -(kNumberOfCpuRegisters - V0); |
| 388 // Result in V0 is preserved as part of pushing all registers below. |
| 389 |
| 390 // Push registers in their enumeration order: lowest register number at |
| 391 // lowest address. |
| 392 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| 393 const int slot = 2 + kNumberOfCpuRegisters - i; |
| 394 Register reg = static_cast<Register>(i); |
| 395 __ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 396 } |
| 397 for (int i = 0; i < kNumberOfFRegisters; i++) { |
| 398 // These go below the CPU registers. |
| 399 const int slot = 2 + kNumberOfCpuRegisters + kNumberOfFRegisters - i; |
| 400 FRegister reg = static_cast<FRegister>(i); |
| 401 __ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 402 } |
| 403 |
| 404 __ mov(A0, SP); // Pass address of saved registers block. |
| 405 __ ReserveAlignedFrameSpace(0); |
| 406 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry); |
| 407 // Result (V0) is stack-size (FP - SP) in bytes, incl. the return address. |
| 408 |
| 409 if (preserve_result) { |
| 410 // Restore result into T1 temporarily. |
| 411 __ lw(T1, Address(FP, saved_v0_offset_from_fp * kWordSize)); |
| 412 } |
| 413 |
| 414 __ mov(SP, FP); |
| 415 __ lw(FP, Address(SP, 0 * kWordSize)); |
| 416 __ lw(RA, Address(SP, 1 * kWordSize)); |
| 417 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 418 |
| 419 __ subu(SP, FP, V0); |
| 420 |
| 421 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 422 __ sw(RA, Address(SP, 1 * kWordSize)); |
| 423 __ sw(FP, Address(SP, 0 * kWordSize)); |
| 424 __ mov(FP, SP); |
| 425 |
| 426 __ mov(A0, SP); // Get last FP address. |
| 427 if (preserve_result) { |
| 428 __ Push(T1); // Preserve result. |
| 429 } |
| 430 __ ReserveAlignedFrameSpace(0); |
| 431 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); // Pass last FP in A0. |
| 432 // Result (V0) is our FP. |
| 433 if (preserve_result) { |
| 434 // Restore result into T1. |
| 435 __ lw(T1, Address(FP, -1 * kWordSize)); |
| 436 } |
| 437 // Code above cannot cause GC. |
| 438 __ mov(SP, FP); |
| 439 __ lw(FP, Address(SP, 0 * kWordSize)); |
| 440 __ lw(RA, Address(SP, 1 * kWordSize)); |
| 441 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 442 __ mov(FP, V0); |
| 443 |
| 444 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 445 // Materialize any objects that were deferred by FillFrame because they |
| 446 // require allocation. |
| 447 __ EnterStubFrame(); |
| 448 if (preserve_result) { |
| 449 __ Push(T1); // Preserve result, it will be GC-d here. |
| 450 } |
| 451 __ CallRuntime(kDeoptimizeMaterializeDoublesRuntimeEntry); |
| 452 if (preserve_result) { |
| 453 __ Pop(V0); // Restore result. |
| 454 } |
| 455 __ LeaveStubFrame(); |
| 456 __ Ret(); |
| 457 } |
| 458 |
| 459 |
| 344 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 460 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 345 __ Unimplemented("DeoptimizeLazy stub"); | 461 __ Unimplemented("DeoptimizeLazy stub"); |
| 346 } | 462 } |
| 347 | 463 |
| 348 | 464 |
| 349 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 465 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 350 __ Unimplemented("Deoptimize stub"); | 466 GenerateDeoptimizationSequence(assembler, false); // Don't preserve V0. |
| 351 } | 467 } |
| 352 | 468 |
| 353 | 469 |
| 354 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 470 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 355 __ Unimplemented("MegamorphicMiss stub"); | 471 __ Unimplemented("MegamorphicMiss stub"); |
| 356 } | 472 } |
| 357 | 473 |
| 358 | 474 |
| 359 // Called for inline allocation of arrays. | 475 // Called for inline allocation of arrays. |
| 360 // Input parameters: | 476 // Input parameters: |
| (...skipping 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1254 __ LeaveStubFrame(true); | 1370 __ LeaveStubFrame(true); |
| 1255 __ Ret(); | 1371 __ Ret(); |
| 1256 } | 1372 } |
| 1257 | 1373 |
| 1258 | 1374 |
| 1259 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 1375 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
| 1260 __ Unimplemented("CallNoSuchMethodFunction stub"); | 1376 __ Unimplemented("CallNoSuchMethodFunction stub"); |
| 1261 } | 1377 } |
| 1262 | 1378 |
| 1263 | 1379 |
| 1380 // T0: function object. |
| 1381 // S5: inline cache data object. |
| 1382 // S4: arguments descriptor array. |
| 1264 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 1383 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1265 __ Unimplemented("OptimizedUsageCounterIncrement stub"); | 1384 __ TraceSimMsg("OptimizedUsageCounterIncrement"); |
| 1385 Register ic_reg = S5; |
| 1386 Register func_reg = T0; |
| 1387 if (FLAG_trace_optimized_ic_calls) { |
| 1388 __ EnterStubFrame(); |
| 1389 __ addiu(SP, SP, Immediate(-5 * kWordSize)); |
| 1390 __ sw(T0, Address(SP, 4 * kWordSize)); |
| 1391 __ sw(S5, Address(SP, 3 * kWordSize)); |
| 1392 __ sw(S4, Address(SP, 2 * kWordSize)); // Preserve. |
| 1393 __ sw(ic_reg, Address(SP, 1 * kWordSize)); // Argument. |
| 1394 __ sw(func_reg, Address(SP, 0 * kWordSize)); // Argument. |
| 1395 __ CallRuntime(kTraceICCallRuntimeEntry); |
| 1396 __ lw(S4, Address(SP, 2 * kWordSize)); // Restore. |
| 1397 __ lw(S5, Address(SP, 3 * kWordSize)); |
| 1398 __ lw(T0, Address(SP, 4 * kWordSize)); |
| 1399 __ addiu(SP, SP, Immediate(5 * kWordSize)); // Discard argument; |
| 1400 __ LeaveStubFrame(); |
| 1401 } |
| 1402 __ lw(T7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1403 Label is_hot; |
| 1404 if (FlowGraphCompiler::CanOptimize()) { |
| 1405 ASSERT(FLAG_optimization_counter_threshold > 1); |
| 1406 __ BranchGreaterEqual(T7, FLAG_optimization_counter_threshold, &is_hot); |
| 1407 // As long as VM has no OSR do not optimize in the middle of the function |
| 1408 // but only at exit so that we have collected all type feedback before |
| 1409 // optimizing. |
| 1410 } |
| 1411 __ addiu(T7, T7, Immediate(1)); |
| 1412 __ sw(T7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1413 __ Bind(&is_hot); |
| 1266 } | 1414 } |
| 1267 | 1415 |
| 1268 | 1416 |
| 1269 // Loads function into 'temp_reg'. | 1417 // Loads function into 'temp_reg'. |
| 1270 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1418 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1271 Register temp_reg) { | 1419 Register temp_reg) { |
| 1272 __ TraceSimMsg("UsageCounterIncrement"); | 1420 __ TraceSimMsg("UsageCounterIncrement"); |
| 1273 Register ic_reg = S5; | 1421 Register ic_reg = S5; |
| 1274 Register func_reg = temp_reg; | 1422 Register func_reg = temp_reg; |
| 1275 ASSERT(temp_reg == T0); | 1423 ASSERT(temp_reg == T0); |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1968 __ Bind(&done); | 2116 __ Bind(&done); |
| 1969 __ lw(T0, Address(SP, 0 * kWordSize)); | 2117 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 1970 __ lw(T1, Address(SP, 1 * kWordSize)); | 2118 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 1971 __ Ret(); | 2119 __ Ret(); |
| 1972 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); | 2120 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1973 } | 2121 } |
| 1974 | 2122 |
| 1975 } // namespace dart | 2123 } // namespace dart |
| 1976 | 2124 |
| 1977 #endif // defined TARGET_ARCH_MIPS | 2125 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |