| 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 22 matching lines...) Expand all Loading... |
| 33 // SP + 4*S4 - 4 : address of first argument in argument array. | 33 // SP + 4*S4 - 4 : address of first argument in argument array. |
| 34 // SP + 4*S4 : address of return value. | 34 // SP + 4*S4 : address of return value. |
| 35 // S5 : address of the runtime function to call. | 35 // S5 : address of the runtime function to call. |
| 36 // S4 : number of arguments to the call. | 36 // S4 : number of arguments to the call. |
| 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 37 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 38 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 38 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 39 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 39 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 40 const intptr_t argv_offset = NativeArguments::argv_offset(); | 40 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 41 const intptr_t retval_offset = NativeArguments::retval_offset(); | 41 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 42 | 42 |
| 43 __ SetPrologueOffset(); |
| 43 __ TraceSimMsg("CallToRuntimeStub"); | 44 __ TraceSimMsg("CallToRuntimeStub"); |
| 44 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 45 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 45 __ sw(RA, Address(SP, 1 * kWordSize)); | 46 __ sw(RA, Address(SP, 1 * kWordSize)); |
| 46 __ sw(FP, Address(SP, 0 * kWordSize)); | 47 __ sw(FP, Address(SP, 0 * kWordSize)); |
| 47 __ mov(FP, SP); | 48 __ mov(FP, SP); |
| 48 | 49 |
| 49 // Load current Isolate pointer from Context structure into R0. | 50 // Load current Isolate pointer from Context structure into A0. |
| 50 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); | 51 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); |
| 51 | 52 |
| 52 // Save exit frame information to enable stack walking as we are about | 53 // Save exit frame information to enable stack walking as we are about |
| 53 // to transition to Dart VM C++ code. | 54 // to transition to Dart VM C++ code. |
| 54 __ sw(SP, Address(A0, Isolate::top_exit_frame_info_offset())); | 55 __ sw(SP, Address(A0, Isolate::top_exit_frame_info_offset())); |
| 55 | 56 |
| 56 // Save current Context pointer into Isolate structure. | 57 // Save current Context pointer into Isolate structure. |
| 57 __ sw(CTX, Address(A0, Isolate::top_context_offset())); | 58 __ sw(CTX, Address(A0, Isolate::top_context_offset())); |
| 58 | 59 |
| 59 // Cache Isolate pointer into CTX while executing runtime code. | 60 // Cache Isolate pointer into CTX while executing runtime code. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 // SP : address of return value. | 136 // SP : address of return value. |
| 136 // T5 : address of the native function to call. | 137 // T5 : address of the native function to call. |
| 137 // A2 : address of first argument in argument array. | 138 // A2 : address of first argument in argument array. |
| 138 // A1 : argc_tag including number of arguments and function kind. | 139 // A1 : argc_tag including number of arguments and function kind. |
| 139 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 140 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
| 140 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 141 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| 141 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 142 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 142 const intptr_t argv_offset = NativeArguments::argv_offset(); | 143 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 143 const intptr_t retval_offset = NativeArguments::retval_offset(); | 144 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 144 | 145 |
| 146 __ SetPrologueOffset(); |
| 145 __ TraceSimMsg("CallNativeCFunctionStub"); | 147 __ TraceSimMsg("CallNativeCFunctionStub"); |
| 146 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 148 __ addiu(SP, SP, Immediate(-2 * kWordSize)); |
| 147 __ sw(RA, Address(SP, 1 * kWordSize)); | 149 __ sw(RA, Address(SP, 1 * kWordSize)); |
| 148 __ sw(FP, Address(SP, 0 * kWordSize)); | 150 __ sw(FP, Address(SP, 0 * kWordSize)); |
| 149 __ mov(FP, SP); | 151 __ mov(FP, SP); |
| 150 | 152 |
| 151 // Load current Isolate pointer from Context structure into A0. | 153 // Load current Isolate pointer from Context structure into A0. |
| 152 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); | 154 __ lw(A0, FieldAddress(CTX, Context::isolate_offset())); |
| 153 | 155 |
| 154 // Save exit frame information to enable stack walking as we are about | 156 // Save exit frame information to enable stack walking as we are about |
| 155 // to transition to native code. | 157 // to transition to native code. |
| 156 __ sw(SP, Address(A0, Isolate::top_exit_frame_info_offset())); | 158 __ sw(SP, Address(A0, Isolate::top_exit_frame_info_offset())); |
| 157 | 159 |
| 158 // Save current Context pointer into Isolate structure. | 160 // Save current Context pointer into Isolate structure. |
| 159 __ sw(CTX, Address(A0, Isolate::top_context_offset())); | 161 __ sw(CTX, Address(A0, Isolate::top_context_offset())); |
| 160 | 162 |
| 161 // Cache Isolate pointer into CTX while executing native code. | 163 // Cache Isolate pointer into CTX while executing native code. |
| 162 __ mov(CTX, A0); | 164 __ mov(CTX, A0); |
| 163 | 165 |
| 164 // Initialize NativeArguments structure and call native function. | 166 // Initialize NativeArguments structure and call native function. |
| 165 // Registers A0, A1, A2, and A3 are used. | 167 // Registers A0, A1, A2, and A3 are used. |
| 166 | 168 |
| 167 ASSERT(isolate_offset == 0 * kWordSize); | 169 ASSERT(isolate_offset == 0 * kWordSize); |
| 168 // Set isolate in NativeArgs: A0 already contains CTX. | 170 // Set isolate in NativeArgs: A0 already contains CTX. |
| 169 | 171 |
| 170 // There are no native calls to closures, so we do not need to set the tag | 172 // There are no native calls to closures, so we do not need to set the tag |
| 171 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 173 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 172 ASSERT(argc_tag_offset == 1 * kWordSize); | 174 ASSERT(argc_tag_offset == 1 * kWordSize); |
| 173 // Set argc in NativeArguments: T1 already contains argc. | 175 // Set argc in NativeArguments: A1 already contains argc. |
| 174 | 176 |
| 175 ASSERT(argv_offset == 2 * kWordSize); | 177 ASSERT(argv_offset == 2 * kWordSize); |
| 176 // Set argv in NativeArguments: T2 already contains argv. | 178 // Set argv in NativeArguments: A2 already contains argv. |
| 177 | 179 |
| 178 ASSERT(retval_offset == 3 * kWordSize); | 180 ASSERT(retval_offset == 3 * kWordSize); |
| 179 __ addiu(A3, FP, Immediate(2 * kWordSize)); // Set retval in NativeArgs. | 181 __ addiu(A3, FP, Immediate(2 * kWordSize)); // Set retval in NativeArgs. |
| 180 | 182 |
| 181 // TODO(regis): Should we pass the structure by value as in runtime calls? | 183 // TODO(regis): Should we pass the structure by value as in runtime calls? |
| 182 // It would require changing Dart API for native functions. | 184 // It would require changing Dart API for native functions. |
| 183 // For now, space is reserved on the stack and we pass a pointer to it. | 185 // For now, space is reserved on the stack and we pass a pointer to it. |
| 184 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 186 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 185 __ sw(A3, Address(SP, 3 * kWordSize)); | 187 __ sw(A3, Address(SP, 3 * kWordSize)); |
| 186 __ sw(A2, Address(SP, 2 * kWordSize)); | 188 __ sw(A2, Address(SP, 2 * kWordSize)); |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 } | 347 } |
| 346 | 348 |
| 347 | 349 |
| 348 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, | 350 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
| 349 intptr_t deopt_reason, | 351 intptr_t deopt_reason, |
| 350 uword saved_registers_address); | 352 uword saved_registers_address); |
| 351 | 353 |
| 352 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); | 354 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); |
| 353 | 355 |
| 354 | 356 |
| 355 | |
| 356 | |
| 357 // Used by eager and lazy deoptimization. Preserve result in V0 if necessary. | 357 // Used by eager and lazy deoptimization. Preserve result in V0 if necessary. |
| 358 // This stub translates optimized frame into unoptimized frame. The optimized | 358 // This stub translates optimized frame into unoptimized frame. The optimized |
| 359 // frame can contain values in registers and on stack, the unoptimized | 359 // frame can contain values in registers and on stack, the unoptimized |
| 360 // frame contains all values on stack. | 360 // frame contains all values on stack. |
| 361 // Deoptimization occurs in following steps: | 361 // Deoptimization occurs in following steps: |
| 362 // - Push all registers that can contain values. | 362 // - Push all registers that can contain values. |
| 363 // - Call C routine to copy the stack and saved registers into temporary buffer. | 363 // - Call C routine to copy the stack and saved registers into temporary buffer. |
| 364 // - Adjust caller's frame to correct unoptimized frame size. | 364 // - Adjust caller's frame to correct unoptimized frame size. |
| 365 // - Fill the unoptimized frame. | 365 // - Fill the unoptimized frame. |
| 366 // - Materialize objects that require allocation (e.g. Double instances). | 366 // - Materialize objects that require allocation (e.g. Double instances). |
| 367 // GC can occur only after frame is fully rewritten. | 367 // GC can occur only after frame is fully rewritten. |
| 368 // Stack after EnterFrame(...) below: | 368 // Stack after EnterFrame(...) below: |
| 369 // +------------------+ | 369 // +------------------+ |
| 370 // | Saved PP | <- TOS | 370 // | Saved PP | <- TOS |
| 371 // +------------------+ | 371 // +------------------+ |
| 372 // | Saved FP | <- FP of stub | 372 // | Saved FP | <- FP of stub |
| 373 // +------------------+ | 373 // +------------------+ |
| 374 // | Saved LR | (deoptimization point) | 374 // | Saved LR | (deoptimization point) |
| 375 // +------------------+ | 375 // +------------------+ |
| 376 // | PC marker | | 376 // | PC marker | |
| 377 // +------------------+ | 377 // +------------------+ |
| 378 // | ... | <- SP of optimized frame | 378 // | ... | <- SP of optimized frame |
| 379 // | 379 // |
| 380 // Parts of the code cannot GC, part of the code can GC. | 380 // Parts of the code cannot GC, part of the code can GC. |
| 381 static void GenerateDeoptimizationSequence(Assembler* assembler, | 381 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 382 bool preserve_result) { | 382 bool preserve_result) { |
| 383 __ TraceSimMsg("GenerateDeoptimizationSequence"); | |
| 384 const intptr_t kPushedRegistersSize = | 383 const intptr_t kPushedRegistersSize = |
| 385 kNumberOfCpuRegisters * kWordSize + | 384 kNumberOfCpuRegisters * kWordSize + |
| 386 4 * kWordSize + // PP, FP, RA, PC marker. | 385 4 * kWordSize + // PP, FP, RA, PC marker. |
| 387 kNumberOfFRegisters * kWordSize; | 386 kNumberOfFRegisters * kWordSize; |
| 388 | 387 |
| 388 __ SetPrologueOffset(); |
| 389 __ TraceSimMsg("GenerateDeoptimizationSequence"); |
| 389 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 390 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 390 // is no need to set the correct PC marker or load PP, since they get patched. | 391 // is no need to set the correct PC marker or load PP, since they get patched. |
| 391 __ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize)); | 392 __ addiu(SP, SP, Immediate(-kPushedRegistersSize * kWordSize)); |
| 392 __ sw(ZR, Address(SP, kPushedRegistersSize - 1 * kWordSize)); | 393 __ sw(ZR, Address(SP, kPushedRegistersSize - 1 * kWordSize)); |
| 393 __ sw(RA, Address(SP, kPushedRegistersSize - 2 * kWordSize)); | 394 __ sw(RA, Address(SP, kPushedRegistersSize - 2 * kWordSize)); |
| 394 __ sw(FP, Address(SP, kPushedRegistersSize - 3 * kWordSize)); | 395 __ sw(FP, Address(SP, kPushedRegistersSize - 3 * kWordSize)); |
| 395 __ sw(PP, Address(SP, kPushedRegistersSize - 4 * kWordSize)); | 396 __ sw(PP, Address(SP, kPushedRegistersSize - 4 * kWordSize)); |
| 396 __ addiu(FP, SP, Immediate(kPushedRegistersSize - 3 * kWordSize)); | 397 __ addiu(FP, SP, Immediate(kPushedRegistersSize - 3 * kWordSize)); |
| 397 | 398 |
| 398 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry | 399 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| (...skipping 13 matching lines...) Expand all Loading... |
| 412 __ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); | 413 __ sw(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 413 } | 414 } |
| 414 for (int i = 0; i < kNumberOfFRegisters; i++) { | 415 for (int i = 0; i < kNumberOfFRegisters; i++) { |
| 415 // These go below the CPU registers. | 416 // These go below the CPU registers. |
| 416 const int slot = 4 + kNumberOfCpuRegisters + kNumberOfFRegisters - i; | 417 const int slot = 4 + kNumberOfCpuRegisters + kNumberOfFRegisters - i; |
| 417 FRegister reg = static_cast<FRegister>(i); | 418 FRegister reg = static_cast<FRegister>(i); |
| 418 __ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); | 419 __ swc1(reg, Address(SP, kPushedRegistersSize - slot * kWordSize)); |
| 419 } | 420 } |
| 420 | 421 |
| 421 __ mov(A0, SP); // Pass address of saved registers block. | 422 __ mov(A0, SP); // Pass address of saved registers block. |
| 422 __ ReserveAlignedFrameSpace(0); | 423 __ ReserveAlignedFrameSpace(1 * kWordSize); |
| 423 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry); | 424 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry); |
| 424 // Result (V0) is stack-size (FP - SP) in bytes, incl. the return address. | 425 // Result (V0) is stack-size (FP - SP) in bytes, incl. the return address. |
| 425 | 426 |
| 426 if (preserve_result) { | 427 if (preserve_result) { |
| 427 // Restore result into T1 temporarily. | 428 // Restore result into T1 temporarily. |
| 428 __ lw(T1, Address(FP, saved_result_slot_from_fp * kWordSize)); | 429 __ lw(T1, Address(FP, saved_result_slot_from_fp * kWordSize)); |
| 429 } | 430 } |
| 430 | 431 |
| 431 __ addiu(SP, FP, Immediate(-kWordSize)); | 432 __ addiu(SP, FP, Immediate(-kWordSize)); |
| 432 __ lw(RA, Address(SP, 2 * kWordSize)); | 433 __ lw(RA, Address(SP, 2 * kWordSize)); |
| 433 __ lw(FP, Address(SP, 1 * kWordSize)); | 434 __ lw(FP, Address(SP, 1 * kWordSize)); |
| 434 __ lw(PP, Address(SP, 0 * kWordSize)); | 435 __ lw(PP, Address(SP, 0 * kWordSize)); |
| 435 __ subu(SP, FP, V0); | 436 __ subu(SP, FP, V0); |
| 436 | 437 |
| 437 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 438 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 438 // is no need to set the correct PC marker or load PP, since they get patched. | 439 // is no need to set the correct PC marker or load PP, since they get patched. |
| 439 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 440 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 440 __ sw(ZR, Address(SP, 3 * kWordSize)); | 441 __ sw(ZR, Address(SP, 3 * kWordSize)); |
| 441 __ sw(RA, Address(SP, 2 * kWordSize)); | 442 __ sw(RA, Address(SP, 2 * kWordSize)); |
| 442 __ sw(FP, Address(SP, 1 * kWordSize)); | 443 __ sw(FP, Address(SP, 1 * kWordSize)); |
| 443 __ sw(PP, Address(SP, 0 * kWordSize)); | 444 __ sw(PP, Address(SP, 0 * kWordSize)); |
| 444 __ addiu(FP, SP, Immediate(kWordSize)); | 445 __ addiu(FP, SP, Immediate(kWordSize)); |
| 445 | 446 |
| 446 __ mov(A0, FP); // Get last FP address. | 447 __ mov(A0, FP); // Get last FP address. |
| 447 if (preserve_result) { | 448 if (preserve_result) { |
| 448 __ Push(T1); // Preserve result as first local. | 449 __ Push(T1); // Preserve result as first local. |
| 449 } | 450 } |
| 450 __ ReserveAlignedFrameSpace(0); | 451 __ ReserveAlignedFrameSpace(1 * kWordSize); |
| 451 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); // Pass last FP in A0. | 452 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry); // Pass last FP in A0. |
| 452 if (preserve_result) { | 453 if (preserve_result) { |
| 453 // Restore result into T1. | 454 // Restore result into T1. |
| 454 __ lw(T1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | 455 __ lw(T1, Address(FP, kFirstLocalSlotFromFp * kWordSize)); |
| 455 } | 456 } |
| 456 // Code above cannot cause GC. | 457 // Code above cannot cause GC. |
| 457 __ addiu(SP, FP, Immediate(-kWordSize)); | 458 __ addiu(SP, FP, Immediate(-kWordSize)); |
| 458 __ lw(RA, Address(SP, 2 * kWordSize)); | 459 __ lw(RA, Address(SP, 2 * kWordSize)); |
| 459 __ lw(FP, Address(SP, 1 * kWordSize)); | 460 __ lw(FP, Address(SP, 1 * kWordSize)); |
| 460 __ lw(PP, Address(SP, 0 * kWordSize)); | 461 __ lw(PP, Address(SP, 0 * kWordSize)); |
| (...skipping 1176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1637 | 1638 |
| 1638 __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue)); | 1639 __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue)); |
| 1639 __ sw(T1, Address(T0, count_offset)); | 1640 __ sw(T1, Address(T0, count_offset)); |
| 1640 | 1641 |
| 1641 __ Bind(&call_target_function); | 1642 __ Bind(&call_target_function); |
| 1642 // T3: Target function. | 1643 // T3: Target function. |
| 1643 __ lw(T3, FieldAddress(T3, Function::code_offset())); | 1644 __ lw(T3, FieldAddress(T3, Function::code_offset())); |
| 1644 __ lw(T3, FieldAddress(T3, Code::instructions_offset())); | 1645 __ lw(T3, FieldAddress(T3, Code::instructions_offset())); |
| 1645 __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag); | 1646 __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag); |
| 1646 __ jr(T3); | 1647 __ jr(T3); |
| 1647 __ delay_slot()->addiu(T3, T3, | |
| 1648 Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | |
| 1649 | 1648 |
| 1650 // Instance in T3, return its class-id in T3 as Smi. | 1649 // Instance in T3, return its class-id in T3 as Smi. |
| 1651 __ Bind(&get_class_id_as_smi); | 1650 __ Bind(&get_class_id_as_smi); |
| 1652 Label not_smi; | 1651 Label not_smi; |
| 1653 // Test if Smi -> load Smi class for comparison. | 1652 // Test if Smi -> load Smi class for comparison. |
| 1654 __ andi(TMP1, T3, Immediate(kSmiTagMask)); | 1653 __ andi(TMP1, T3, Immediate(kSmiTagMask)); |
| 1655 __ bne(TMP1, ZR, ¬_smi); | 1654 __ bne(TMP1, ZR, ¬_smi); |
| 1656 __ jr(RA); | 1655 __ jr(RA); |
| 1657 __ delay_slot()->addiu(T3, ZR, Immediate(Smi::RawValue(kSmiCid))); | 1656 __ delay_slot()->addiu(T3, ZR, Immediate(Smi::RawValue(kSmiCid))); |
| 1658 | 1657 |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1940 | 1939 |
| 1941 // Implements equality operator when one of the arguments is null | 1940 // Implements equality operator when one of the arguments is null |
| 1942 // (identity check) and updates ICData if necessary. | 1941 // (identity check) and updates ICData if necessary. |
| 1943 // RA: return address. | 1942 // RA: return address. |
| 1944 // A1: left argument. | 1943 // A1: left argument. |
| 1945 // A0: right argument. | 1944 // A0: right argument. |
| 1946 // T0: ICData. | 1945 // T0: ICData. |
| 1947 // V0: result. | 1946 // V0: result. |
| 1948 // TODO(srdjan): Move to VM stubs once Boolean objects become VM objects. | 1947 // TODO(srdjan): Move to VM stubs once Boolean objects become VM objects. |
| 1949 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { | 1948 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { |
| 1949 __ TraceSimMsg("EqualityWithNullArgStub"); |
| 1950 __ EnterStubFrame(); | 1950 __ EnterStubFrame(); |
| 1951 static const intptr_t kNumArgsTested = 2; | 1951 static const intptr_t kNumArgsTested = 2; |
| 1952 #if defined(DEBUG) | 1952 #if defined(DEBUG) |
| 1953 { Label ok; | 1953 { Label ok; |
| 1954 __ lw(TMP1, FieldAddress(T0, ICData::num_args_tested_offset())); | 1954 __ lw(TMP1, FieldAddress(T0, ICData::num_args_tested_offset())); |
| 1955 __ BranchEqual(TMP1, kNumArgsTested, &ok); | 1955 __ BranchEqual(TMP1, kNumArgsTested, &ok); |
| 1956 __ Stop("Incorrect ICData for equality"); | 1956 __ Stop("Incorrect ICData for equality"); |
| 1957 __ Bind(&ok); | 1957 __ Bind(&ok); |
| 1958 } | 1958 } |
| 1959 #endif // DEBUG | 1959 #endif // DEBUG |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2162 __ mov(TMP1, ZR); | 2162 __ mov(TMP1, ZR); |
| 2163 __ lw(T0, Address(SP, 0 * kWordSize)); | 2163 __ lw(T0, Address(SP, 0 * kWordSize)); |
| 2164 __ lw(T1, Address(SP, 1 * kWordSize)); | 2164 __ lw(T1, Address(SP, 1 * kWordSize)); |
| 2165 __ Ret(); | 2165 __ Ret(); |
| 2166 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); | 2166 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize)); |
| 2167 } | 2167 } |
| 2168 | 2168 |
| 2169 } // namespace dart | 2169 } // namespace dart |
| 2170 | 2170 |
| 2171 #endif // defined TARGET_ARCH_MIPS | 2171 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |