| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include <limits.h> // For LONG_MIN, LONG_MAX | 28 #include <limits.h> // For LONG_MIN, LONG_MAX. |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 | 31 |
| 32 #if defined(V8_TARGET_ARCH_MIPS) | 32 #if defined(V8_TARGET_ARCH_MIPS) |
| 33 | 33 |
| 34 #include "bootstrapper.h" | 34 #include "bootstrapper.h" |
| 35 #include "codegen-inl.h" | 35 #include "codegen.h" |
| 36 #include "debug.h" | 36 #include "debug.h" |
| 37 #include "runtime.h" | 37 #include "runtime.h" |
| 38 | 38 |
| 39 namespace v8 { | 39 namespace v8 { |
| 40 namespace internal { | 40 namespace internal { |
| 41 | 41 |
| 42 MacroAssembler::MacroAssembler(void* buffer, int size) | 42 MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size) |
| 43 : Assembler(buffer, size), | 43 : Assembler(arg_isolate, buffer, size), |
| 44 generating_stub_(false), | 44 generating_stub_(false), |
| 45 allow_stub_calls_(true), | 45 allow_stub_calls_(true) { |
| 46 code_object_(HEAP->undefined_value()) { | 46 if (isolate() != NULL) { |
| 47 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(), |
| 48 isolate()); |
| 49 } |
| 47 } | 50 } |
| 48 | 51 |
| 49 | 52 |
| 50 // Arguments macros | 53 // Arguments macros. |
| 51 #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2 | 54 #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2 |
| 52 #define COND_ARGS cond, r1, r2 | 55 #define COND_ARGS cond, r1, r2 |
| 53 | 56 |
| 54 #define REGISTER_TARGET_BODY(Name) \ | 57 #define REGISTER_TARGET_BODY(Name) \ |
| 55 void MacroAssembler::Name(Register target, \ | 58 void MacroAssembler::Name(Register target, \ |
| 56 BranchDelaySlot bd) { \ | 59 BranchDelaySlot bd) { \ |
| 57 Name(Operand(target), bd); \ | 60 Name(Operand(target), bd); \ |
| 58 } \ | 61 } \ |
| 59 void MacroAssembler::Name(Register target, COND_TYPED_ARGS, \ | 62 void MacroAssembler::Name(Register target, COND_TYPED_ARGS, \ |
| 60 BranchDelaySlot bd) { \ | 63 BranchDelaySlot bd) { \ |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 Condition cond, | 157 Condition cond, |
| 155 Register src1, const Operand& src2) { | 158 Register src1, const Operand& src2) { |
| 156 Branch(2, NegateCondition(cond), src1, src2); | 159 Branch(2, NegateCondition(cond), src1, src2); |
| 157 sw(source, MemOperand(s6, index << kPointerSizeLog2)); | 160 sw(source, MemOperand(s6, index << kPointerSizeLog2)); |
| 158 } | 161 } |
| 159 | 162 |
| 160 | 163 |
| 161 void MacroAssembler::RecordWriteHelper(Register object, | 164 void MacroAssembler::RecordWriteHelper(Register object, |
| 162 Register address, | 165 Register address, |
| 163 Register scratch) { | 166 Register scratch) { |
| 164 if (FLAG_debug_code) { | 167 if (emit_debug_code()) { |
| 165 // Check that the object is not in new space. | 168 // Check that the object is not in new space. |
| 166 Label not_in_new_space; | 169 Label not_in_new_space; |
| 167 InNewSpace(object, scratch, ne, ¬_in_new_space); | 170 InNewSpace(object, scratch, ne, ¬_in_new_space); |
| 168 Abort("new-space object passed to RecordWriteHelper"); | 171 Abort("new-space object passed to RecordWriteHelper"); |
| 169 bind(¬_in_new_space); | 172 bind(¬_in_new_space); |
| 170 } | 173 } |
| 171 | 174 |
| 172 // Calculate page address: Clear bits from 0 to kPageSizeBits. | 175 // Calculate page address: Clear bits from 0 to kPageSizeBits. |
| 173 if (mips32r2) { | 176 if (mips32r2) { |
| 174 Ins(object, zero_reg, 0, kPageSizeBits); | 177 Ins(object, zero_reg, 0, kPageSizeBits); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 223 // Add offset into the object. | 226 // Add offset into the object. |
| 224 Addu(scratch0, object, offset); | 227 Addu(scratch0, object, offset); |
| 225 | 228 |
| 226 // Record the actual write. | 229 // Record the actual write. |
| 227 RecordWriteHelper(object, scratch0, scratch1); | 230 RecordWriteHelper(object, scratch0, scratch1); |
| 228 | 231 |
| 229 bind(&done); | 232 bind(&done); |
| 230 | 233 |
| 231 // Clobber all input registers when running with the debug-code flag | 234 // Clobber all input registers when running with the debug-code flag |
| 232 // turned on to provoke errors. | 235 // turned on to provoke errors. |
| 233 if (FLAG_debug_code) { | 236 if (emit_debug_code()) { |
| 234 li(object, Operand(BitCast<int32_t>(kZapValue))); | 237 li(object, Operand(BitCast<int32_t>(kZapValue))); |
| 235 li(scratch0, Operand(BitCast<int32_t>(kZapValue))); | 238 li(scratch0, Operand(BitCast<int32_t>(kZapValue))); |
| 236 li(scratch1, Operand(BitCast<int32_t>(kZapValue))); | 239 li(scratch1, Operand(BitCast<int32_t>(kZapValue))); |
| 237 } | 240 } |
| 238 } | 241 } |
| 239 | 242 |
| 240 | 243 |
| 241 // Will clobber 4 registers: object, address, scratch, ip. The | 244 // Will clobber 4 registers: object, address, scratch, ip. The |
| 242 // register 'object' contains a heap object pointer. The heap object | 245 // register 'object' contains a heap object pointer. The heap object |
| 243 // tag is shifted away. | 246 // tag is shifted away. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 255 // region marks for new space pages. | 258 // region marks for new space pages. |
| 256 InNewSpace(object, scratch, eq, &done); | 259 InNewSpace(object, scratch, eq, &done); |
| 257 | 260 |
| 258 // Record the actual write. | 261 // Record the actual write. |
| 259 RecordWriteHelper(object, address, scratch); | 262 RecordWriteHelper(object, address, scratch); |
| 260 | 263 |
| 261 bind(&done); | 264 bind(&done); |
| 262 | 265 |
| 263 // Clobber all input registers when running with the debug-code flag | 266 // Clobber all input registers when running with the debug-code flag |
| 264 // turned on to provoke errors. | 267 // turned on to provoke errors. |
| 265 if (FLAG_debug_code) { | 268 if (emit_debug_code()) { |
| 266 li(object, Operand(BitCast<int32_t>(kZapValue))); | 269 li(object, Operand(BitCast<int32_t>(kZapValue))); |
| 267 li(address, Operand(BitCast<int32_t>(kZapValue))); | 270 li(address, Operand(BitCast<int32_t>(kZapValue))); |
| 268 li(scratch, Operand(BitCast<int32_t>(kZapValue))); | 271 li(scratch, Operand(BitCast<int32_t>(kZapValue))); |
| 269 } | 272 } |
| 270 } | 273 } |
| 271 | 274 |
| 272 | 275 |
| 273 // ----------------------------------------------------------------------------- | 276 // ----------------------------------------------------------------------------- |
| 274 // Allocation support | 277 // Allocation support. |
| 275 | 278 |
| 276 | 279 |
| 277 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 280 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
| 278 Register scratch, | 281 Register scratch, |
| 279 Label* miss) { | 282 Label* miss) { |
| 280 Label same_contexts; | 283 Label same_contexts; |
| 281 | 284 |
| 282 ASSERT(!holder_reg.is(scratch)); | 285 ASSERT(!holder_reg.is(scratch)); |
| 283 ASSERT(!holder_reg.is(at)); | 286 ASSERT(!holder_reg.is(at)); |
| 284 ASSERT(!scratch.is(at)); | 287 ASSERT(!scratch.is(at)); |
| 285 | 288 |
| 286 // Load current lexical context from the stack frame. | 289 // Load current lexical context from the stack frame. |
| 287 lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 290 lw(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 288 // In debug mode, make sure the lexical context is set. | 291 // In debug mode, make sure the lexical context is set. |
| 289 #ifdef DEBUG | 292 #ifdef DEBUG |
| 290 Check(ne, "we should not have an empty lexical context", | 293 Check(ne, "we should not have an empty lexical context", |
| 291 scratch, Operand(zero_reg)); | 294 scratch, Operand(zero_reg)); |
| 292 #endif | 295 #endif |
| 293 | 296 |
| 294 // Load the global context of the current context. | 297 // Load the global context of the current context. |
| 295 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 298 int offset = Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
| 296 lw(scratch, FieldMemOperand(scratch, offset)); | 299 lw(scratch, FieldMemOperand(scratch, offset)); |
| 297 lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); | 300 lw(scratch, FieldMemOperand(scratch, GlobalObject::kGlobalContextOffset)); |
| 298 | 301 |
| 299 // Check the context is a global context. | 302 // Check the context is a global context. |
| 300 if (FLAG_debug_code) { | 303 if (emit_debug_code()) { |
| 301 // TODO(119): Avoid push(holder_reg)/pop(holder_reg). | 304 // TODO(119): Avoid push(holder_reg)/pop(holder_reg). |
| 302 Push(holder_reg); // Temporarily save holder on the stack. | 305 push(holder_reg); // Temporarily save holder on the stack. |
| 303 // Read the first word and compare to the global_context_map. | 306 // Read the first word and compare to the global_context_map. |
| 304 lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); | 307 lw(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset)); |
| 305 LoadRoot(at, Heap::kGlobalContextMapRootIndex); | 308 LoadRoot(at, Heap::kGlobalContextMapRootIndex); |
| 306 Check(eq, "JSGlobalObject::global_context should be a global context.", | 309 Check(eq, "JSGlobalObject::global_context should be a global context.", |
| 307 holder_reg, Operand(at)); | 310 holder_reg, Operand(at)); |
| 308 Pop(holder_reg); // Restore holder. | 311 pop(holder_reg); // Restore holder. |
| 309 } | 312 } |
| 310 | 313 |
| 311 // Check if both contexts are the same. | 314 // Check if both contexts are the same. |
| 312 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 315 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
| 313 Branch(&same_contexts, eq, scratch, Operand(at)); | 316 Branch(&same_contexts, eq, scratch, Operand(at)); |
| 314 | 317 |
| 315 // Check the context is a global context. | 318 // Check the context is a global context. |
| 316 if (FLAG_debug_code) { | 319 if (emit_debug_code()) { |
| 317 // TODO(119): Avoid push(holder_reg)/pop(holder_reg). | 320 // TODO(119): Avoid push(holder_reg)/pop(holder_reg). |
| 318 Push(holder_reg); // Temporarily save holder on the stack. | 321 push(holder_reg); // Temporarily save holder on the stack. |
| 319 mov(holder_reg, at); // Move at to its holding place. | 322 mov(holder_reg, at); // Move at to its holding place. |
| 320 LoadRoot(at, Heap::kNullValueRootIndex); | 323 LoadRoot(at, Heap::kNullValueRootIndex); |
| 321 Check(ne, "JSGlobalProxy::context() should not be null.", | 324 Check(ne, "JSGlobalProxy::context() should not be null.", |
| 322 holder_reg, Operand(at)); | 325 holder_reg, Operand(at)); |
| 323 | 326 |
| 324 lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); | 327 lw(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset)); |
| 325 LoadRoot(at, Heap::kGlobalContextMapRootIndex); | 328 LoadRoot(at, Heap::kGlobalContextMapRootIndex); |
| 326 Check(eq, "JSGlobalObject::global_context should be a global context.", | 329 Check(eq, "JSGlobalObject::global_context should be a global context.", |
| 327 holder_reg, Operand(at)); | 330 holder_reg, Operand(at)); |
| 328 // Restore at is not needed. at is reloaded below. | 331 // Restore at is not needed. at is reloaded below. |
| 329 Pop(holder_reg); // Restore holder. | 332 pop(holder_reg); // Restore holder. |
| 330 // Restore at to holder's context. | 333 // Restore at to holder's context. |
| 331 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); | 334 lw(at, FieldMemOperand(holder_reg, JSGlobalProxy::kContextOffset)); |
| 332 } | 335 } |
| 333 | 336 |
| 334 // Check that the security token in the calling global object is | 337 // Check that the security token in the calling global object is |
| 335 // compatible with the security token in the receiving global | 338 // compatible with the security token in the receiving global |
| 336 // object. | 339 // object. |
| 337 int token_offset = Context::kHeaderSize + | 340 int token_offset = Context::kHeaderSize + |
| 338 Context::SECURITY_TOKEN_INDEX * kPointerSize; | 341 Context::SECURITY_TOKEN_INDEX * kPointerSize; |
| 339 | 342 |
| 340 lw(scratch, FieldMemOperand(scratch, token_offset)); | 343 lw(scratch, FieldMemOperand(scratch, token_offset)); |
| 341 lw(at, FieldMemOperand(at, token_offset)); | 344 lw(at, FieldMemOperand(at, token_offset)); |
| 342 Branch(miss, ne, scratch, Operand(at)); | 345 Branch(miss, ne, scratch, Operand(at)); |
| 343 | 346 |
| 344 bind(&same_contexts); | 347 bind(&same_contexts); |
| 345 } | 348 } |
| 346 | 349 |
| 347 | 350 |
| 348 // --------------------------------------------------------------------------- | 351 // --------------------------------------------------------------------------- |
| 349 // Instruction macros | 352 // Instruction macros. |
| 350 | 353 |
| 351 void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) { | 354 void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) { |
| 352 if (rt.is_reg()) { | 355 if (rt.is_reg()) { |
| 353 addu(rd, rs, rt.rm()); | 356 addu(rd, rs, rt.rm()); |
| 354 } else { | 357 } else { |
| 355 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { | 358 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { |
| 356 addiu(rd, rs, rt.imm32_); | 359 addiu(rd, rs, rt.imm32_); |
| 357 } else { | 360 } else { |
| 358 // li handles the relocation. | 361 // li handles the relocation. |
| 359 ASSERT(!rs.is(at)); | 362 ASSERT(!rs.is(at)); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 nor(rd, rs, rt.rm()); | 496 nor(rd, rs, rt.rm()); |
| 494 } else { | 497 } else { |
| 495 // li handles the relocation. | 498 // li handles the relocation. |
| 496 ASSERT(!rs.is(at)); | 499 ASSERT(!rs.is(at)); |
| 497 li(at, rt); | 500 li(at, rt); |
| 498 nor(rd, rs, at); | 501 nor(rd, rs, at); |
| 499 } | 502 } |
| 500 } | 503 } |
| 501 | 504 |
| 502 | 505 |
| 506 void MacroAssembler::Neg(Register rs, const Operand& rt) { |
| 507 ASSERT(rt.is_reg()); |
| 508 ASSERT(!at.is(rs)); |
| 509 ASSERT(!at.is(rt.rm())); |
| 510 li(at, -1); |
| 511 xor_(rs, rt.rm(), at); |
| 512 } |
| 513 |
| 514 |
| 503 void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) { | 515 void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) { |
| 504 if (rt.is_reg()) { | 516 if (rt.is_reg()) { |
| 505 slt(rd, rs, rt.rm()); | 517 slt(rd, rs, rt.rm()); |
| 506 } else { | 518 } else { |
| 507 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { | 519 if (is_int16(rt.imm32_) && !MustUseReg(rt.rmode_)) { |
| 508 slti(rd, rs, rt.imm32_); | 520 slti(rd, rs, rt.imm32_); |
| 509 } else { | 521 } else { |
| 510 // li handles the relocation. | 522 // li handles the relocation. |
| 511 ASSERT(!rs.is(at)); | 523 ASSERT(!rs.is(at)); |
| 512 li(at, rt); | 524 li(at, rt); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 } else { | 586 } else { |
| 575 lui(rd, (j.imm32_ & kHiMask) >> kLuiShift); | 587 lui(rd, (j.imm32_ & kHiMask) >> kLuiShift); |
| 576 ori(rd, rd, (j.imm32_ & kImm16Mask)); | 588 ori(rd, rd, (j.imm32_ & kImm16Mask)); |
| 577 } | 589 } |
| 578 } else if (MustUseReg(j.rmode_) || gen2instr) { | 590 } else if (MustUseReg(j.rmode_) || gen2instr) { |
| 579 if (MustUseReg(j.rmode_)) { | 591 if (MustUseReg(j.rmode_)) { |
| 580 RecordRelocInfo(j.rmode_, j.imm32_); | 592 RecordRelocInfo(j.rmode_, j.imm32_); |
| 581 } | 593 } |
| 582 // We need always the same number of instructions as we may need to patch | 594 // We need always the same number of instructions as we may need to patch |
| 583 // this code to load another value which may need 2 instructions to load. | 595 // this code to load another value which may need 2 instructions to load. |
| 584 if (is_int16(j.imm32_)) { | 596 lui(rd, (j.imm32_ & kHiMask) >> kLuiShift); |
| 585 nop(); | 597 ori(rd, rd, (j.imm32_ & kImm16Mask)); |
| 586 addiu(rd, zero_reg, j.imm32_); | |
| 587 } else if (!(j.imm32_ & kHiMask)) { | |
| 588 nop(); | |
| 589 ori(rd, zero_reg, j.imm32_); | |
| 590 } else if (!(j.imm32_ & kImm16Mask)) { | |
| 591 nop(); | |
| 592 lui(rd, (j.imm32_ & kHiMask) >> kLuiShift); | |
| 593 } else { | |
| 594 lui(rd, (j.imm32_ & kHiMask) >> kLuiShift); | |
| 595 ori(rd, rd, (j.imm32_ & kImm16Mask)); | |
| 596 } | |
| 597 } | 598 } |
| 598 } | 599 } |
| 599 | 600 |
| 600 | 601 |
| 601 // Exception-generating instructions and debugging support | 602 // Exception-generating instructions and debugging support. |
| 602 void MacroAssembler::stop(const char* msg) { | 603 void MacroAssembler::stop(const char* msg) { |
| 603 // TO_UPGRADE: Just a break for now. Maybe we could upgrade it. | 604 // TO_UPGRADE: Just a break for now. Maybe we could upgrade it. |
| 604 // We use the 0x54321 value to be able to find it easily when reading memory. | 605 // We use the 0x54321 value to be able to find it easily when reading memory. |
| 605 break_(0x54321); | 606 break_(0x54321); |
| 606 } | 607 } |
| 607 | 608 |
| 608 | 609 |
| 609 void MacroAssembler::MultiPush(RegList regs) { | 610 void MacroAssembler::MultiPush(RegList regs) { |
| 610 int16_t NumSaved = 0; | 611 int16_t NumSaved = 0; |
| 611 int16_t NumToPush = NumberOfBitsSet(regs); | 612 int16_t NumToPush = NumberOfBitsSet(regs); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 720 | 721 |
| 721 void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) { | 722 void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) { |
| 722 // Convert rs to a FP value in fd (and fd + 1). | 723 // Convert rs to a FP value in fd (and fd + 1). |
| 723 // We do this by converting rs minus the MSB to avoid sign conversion, | 724 // We do this by converting rs minus the MSB to avoid sign conversion, |
| 724 // then adding 2^31-1 and 1 to the result. | 725 // then adding 2^31-1 and 1 to the result. |
| 725 | 726 |
| 726 ASSERT(!fd.is(f20)); | 727 ASSERT(!fd.is(f20)); |
| 727 ASSERT(!rs.is(t9)); | 728 ASSERT(!rs.is(t9)); |
| 728 ASSERT(!rs.is(t8)); | 729 ASSERT(!rs.is(t8)); |
| 729 | 730 |
| 730 // Save rs's MSB to t8 | 731 // Save rs's MSB to t8. |
| 731 And(t8, rs, 0x80000000); | 732 And(t8, rs, 0x80000000); |
| 732 // Remove rs's MSB. | 733 // Remove rs's MSB. |
| 733 And(t9, rs, 0x7FFFFFFF); | 734 And(t9, rs, 0x7FFFFFFF); |
| 734 // Move t9 to fd | 735 // Move t9 to fd. |
| 735 mtc1(t9, fd); | 736 mtc1(t9, fd); |
| 736 | 737 |
| 737 // Convert fd to a real FP value. | 738 // Convert fd to a real FP value. |
| 738 cvt_d_w(fd, fd); | 739 cvt_d_w(fd, fd); |
| 739 | 740 |
| 740 Label conversion_done; | 741 Label conversion_done; |
| 741 | 742 |
| 742 // If rs's MSB was 0, it's done. | 743 // If rs's MSB was 0, it's done. |
| 743 // Otherwise we need to add that to the FP register. | 744 // Otherwise we need to add that to the FP register. |
| 744 Branch(&conversion_done, eq, t8, Operand(zero_reg)); | 745 Branch(&conversion_done, eq, t8, Operand(zero_reg)); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 Branch(not_int32, gt, scratch2, Operand(non_smi_exponent)); | 833 Branch(not_int32, gt, scratch2, Operand(non_smi_exponent)); |
| 833 | 834 |
| 834 // We know the exponent is smaller than 30 (biased). If it is less than | 835 // We know the exponent is smaller than 30 (biased). If it is less than |
| 835 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie | 836 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie |
| 836 // it rounds to zero. | 837 // it rounds to zero. |
| 837 const uint32_t zero_exponent = | 838 const uint32_t zero_exponent = |
| 838 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; | 839 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; |
| 839 Subu(scratch2, scratch2, Operand(zero_exponent)); | 840 Subu(scratch2, scratch2, Operand(zero_exponent)); |
| 840 // Dest already has a Smi zero. | 841 // Dest already has a Smi zero. |
| 841 Branch(&done, lt, scratch2, Operand(zero_reg)); | 842 Branch(&done, lt, scratch2, Operand(zero_reg)); |
| 842 if (!Isolate::Current()->cpu_features()->IsSupported(FPU)) { | 843 if (!CpuFeatures::IsSupported(FPU)) { |
| 843 // We have a shifted exponent between 0 and 30 in scratch2. | 844 // We have a shifted exponent between 0 and 30 in scratch2. |
| 844 srl(dest, scratch2, HeapNumber::kExponentShift); | 845 srl(dest, scratch2, HeapNumber::kExponentShift); |
| 845 // We now have the exponent in dest. Subtract from 30 to get | 846 // We now have the exponent in dest. Subtract from 30 to get |
| 846 // how much to shift down. | 847 // how much to shift down. |
| 847 li(at, Operand(30)); | 848 li(at, Operand(30)); |
| 848 subu(dest, at, dest); | 849 subu(dest, at, dest); |
| 849 } | 850 } |
| 850 bind(&right_exponent); | 851 bind(&right_exponent); |
| 851 if (Isolate::Current()->cpu_features()->IsSupported(FPU)) { | 852 if (CpuFeatures::IsSupported(FPU)) { |
| 852 CpuFeatures::Scope scope(FPU); | 853 CpuFeatures::Scope scope(FPU); |
| 853 // MIPS FPU instructions implementing double precision to integer | 854 // MIPS FPU instructions implementing double precision to integer |
| 854 // conversion using round to zero. Since the FP value was qualified | 855 // conversion using round to zero. Since the FP value was qualified |
| 855 // above, the resulting integer should be a legal int32. | 856 // above, the resulting integer should be a legal int32. |
| 856 // The original 'Exponent' word is still in scratch. | 857 // The original 'Exponent' word is still in scratch. |
| 857 lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset)); | 858 lwc1(double_scratch, FieldMemOperand(source, HeapNumber::kMantissaOffset)); |
| 858 mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1)); | 859 mtc1(scratch, FPURegister::from_code(double_scratch.code() + 1)); |
| 859 trunc_w_d(double_scratch, double_scratch); | 860 trunc_w_d(double_scratch, double_scratch); |
| 860 mfc1(dest, double_scratch); | 861 mfc1(dest, double_scratch); |
| 861 } else { | 862 } else { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 891 // Trick to check sign bit (msb) held in dest, count leading zero. | 892 // Trick to check sign bit (msb) held in dest, count leading zero. |
| 892 // 0 indicates negative, save negative version with conditional move. | 893 // 0 indicates negative, save negative version with conditional move. |
| 893 clz(dest, dest); | 894 clz(dest, dest); |
| 894 movz(scratch, scratch2, dest); | 895 movz(scratch, scratch2, dest); |
| 895 mov(dest, scratch); | 896 mov(dest, scratch); |
| 896 } | 897 } |
| 897 bind(&done); | 898 bind(&done); |
| 898 } | 899 } |
| 899 | 900 |
| 900 | 901 |
| 902 void MacroAssembler::EmitOutOfInt32RangeTruncate(Register result, |
| 903 Register input_high, |
| 904 Register input_low, |
| 905 Register scratch) { |
| 906 Label done, normal_exponent, restore_sign; |
| 907 // Extract the biased exponent in result. |
| 908 Ext(result, |
| 909 input_high, |
| 910 HeapNumber::kExponentShift, |
| 911 HeapNumber::kExponentBits); |
| 912 |
| 913 // Check for Infinity and NaNs, which should return 0. |
| 914 Subu(scratch, result, HeapNumber::kExponentMask); |
| 915 movz(result, zero_reg, scratch); |
| 916 Branch(&done, eq, scratch, Operand(zero_reg)); |
| 917 |
| 918 // Express exponent as delta to (number of mantissa bits + 31). |
| 919 Subu(result, |
| 920 result, |
| 921 Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 31)); |
| 922 |
| 923 // If the delta is strictly positive, all bits would be shifted away, |
| 924 // which means that we can return 0. |
| 925 Branch(&normal_exponent, le, result, Operand(zero_reg)); |
| 926 mov(result, zero_reg); |
| 927 Branch(&done); |
| 928 |
| 929 bind(&normal_exponent); |
| 930 const int kShiftBase = HeapNumber::kNonMantissaBitsInTopWord - 1; |
| 931 // Calculate shift. |
| 932 Addu(scratch, result, Operand(kShiftBase + HeapNumber::kMantissaBits)); |
| 933 |
| 934 // Save the sign. |
| 935 Register sign = result; |
| 936 result = no_reg; |
| 937 And(sign, input_high, Operand(HeapNumber::kSignMask)); |
| 938 |
| 939 // On ARM shifts > 31 bits are valid and will result in zero. On MIPS we need |
| 940 // to check for this specific case. |
| 941 Label high_shift_needed, high_shift_done; |
| 942 Branch(&high_shift_needed, lt, scratch, Operand(32)); |
| 943 mov(input_high, zero_reg); |
| 944 Branch(&high_shift_done); |
| 945 bind(&high_shift_needed); |
| 946 |
| 947 // Set the implicit 1 before the mantissa part in input_high. |
| 948 Or(input_high, |
| 949 input_high, |
| 950 Operand(1 << HeapNumber::kMantissaBitsInTopWord)); |
| 951 // Shift the mantissa bits to the correct position. |
| 952 // We don't need to clear non-mantissa bits as they will be shifted away. |
| 953 // If they weren't, it would mean that the answer is in the 32bit range. |
| 954 sllv(input_high, input_high, scratch); |
| 955 |
| 956 bind(&high_shift_done); |
| 957 |
| 958 // Replace the shifted bits with bits from the lower mantissa word. |
| 959 Label pos_shift, shift_done; |
| 960 li(at, 32); |
| 961 subu(scratch, at, scratch); |
| 962 Branch(&pos_shift, ge, scratch, Operand(zero_reg)); |
| 963 |
| 964 // Negate scratch. |
| 965 Subu(scratch, zero_reg, scratch); |
| 966 sllv(input_low, input_low, scratch); |
| 967 Branch(&shift_done); |
| 968 |
| 969 bind(&pos_shift); |
| 970 srlv(input_low, input_low, scratch); |
| 971 |
| 972 bind(&shift_done); |
| 973 Or(input_high, input_high, Operand(input_low)); |
| 974 // Restore sign if necessary. |
| 975 mov(scratch, sign); |
| 976 result = sign; |
| 977 sign = no_reg; |
| 978 Subu(result, zero_reg, input_high); |
| 979 movz(result, input_high, scratch); |
| 980 bind(&done); |
| 981 } |
| 982 |
| 983 |
| 984 void MacroAssembler::GetLeastBitsFromSmi(Register dst, |
| 985 Register src, |
| 986 int num_least_bits) { |
| 987 Ext(dst, src, kSmiTagSize, num_least_bits); |
| 988 } |
| 989 |
| 990 |
| 991 void MacroAssembler::GetLeastBitsFromInt32(Register dst, |
| 992 Register src, |
| 993 int num_least_bits) { |
| 994 And(dst, src, Operand((1 << num_least_bits) - 1)); |
| 995 } |
| 996 |
| 997 |
| 901 // Emulated condtional branches do not emit a nop in the branch delay slot. | 998 // Emulated condtional branches do not emit a nop in the branch delay slot. |
| 902 // | 999 // |
| 903 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. | 1000 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct. |
| 904 #define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \ | 1001 #define BRANCH_ARGS_CHECK(cond, rs, rt) ASSERT( \ |
| 905 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ | 1002 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \ |
| 906 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) | 1003 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg)))) |
| 907 | 1004 |
| 908 | 1005 |
| 909 void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { | 1006 void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) { |
| 910 b(offset); | 1007 b(offset); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 930 switch (cond) { | 1027 switch (cond) { |
| 931 case cc_always: | 1028 case cc_always: |
| 932 b(offset); | 1029 b(offset); |
| 933 break; | 1030 break; |
| 934 case eq: | 1031 case eq: |
| 935 beq(rs, r2, offset); | 1032 beq(rs, r2, offset); |
| 936 break; | 1033 break; |
| 937 case ne: | 1034 case ne: |
| 938 bne(rs, r2, offset); | 1035 bne(rs, r2, offset); |
| 939 break; | 1036 break; |
| 940 // Signed comparison | 1037 // Signed comparison. |
| 941 case greater: | 1038 case greater: |
| 942 if (r2.is(zero_reg)) { | 1039 if (r2.is(zero_reg)) { |
| 943 bgtz(rs, offset); | 1040 bgtz(rs, offset); |
| 944 } else { | 1041 } else { |
| 945 slt(scratch, r2, rs); | 1042 slt(scratch, r2, rs); |
| 946 bne(scratch, zero_reg, offset); | 1043 bne(scratch, zero_reg, offset); |
| 947 } | 1044 } |
| 948 break; | 1045 break; |
| 949 case greater_equal: | 1046 case greater_equal: |
| 950 if (r2.is(zero_reg)) { | 1047 if (r2.is(zero_reg)) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1021 li(r2, rt); | 1118 li(r2, rt); |
| 1022 beq(rs, r2, offset); | 1119 beq(rs, r2, offset); |
| 1023 break; | 1120 break; |
| 1024 case ne: | 1121 case ne: |
| 1025 // We don't want any other register but scratch clobbered. | 1122 // We don't want any other register but scratch clobbered. |
| 1026 ASSERT(!scratch.is(rs)); | 1123 ASSERT(!scratch.is(rs)); |
| 1027 r2 = scratch; | 1124 r2 = scratch; |
| 1028 li(r2, rt); | 1125 li(r2, rt); |
| 1029 bne(rs, r2, offset); | 1126 bne(rs, r2, offset); |
| 1030 break; | 1127 break; |
| 1031 // Signed comparison | 1128 // Signed comparison. |
| 1032 case greater: | 1129 case greater: |
| 1033 if (rt.imm32_ == 0) { | 1130 if (rt.imm32_ == 0) { |
| 1034 bgtz(rs, offset); | 1131 bgtz(rs, offset); |
| 1035 } else { | 1132 } else { |
| 1036 r2 = scratch; | 1133 r2 = scratch; |
| 1037 li(r2, rt); | 1134 li(r2, rt); |
| 1038 slt(scratch, r2, rs); | 1135 slt(scratch, r2, rs); |
| 1039 bne(scratch, zero_reg, offset); | 1136 bne(scratch, zero_reg, offset); |
| 1040 } | 1137 } |
| 1041 break; | 1138 break; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 b(offset); | 1260 b(offset); |
| 1164 break; | 1261 break; |
| 1165 case eq: | 1262 case eq: |
| 1166 offset = shifted_branch_offset(L, false); | 1263 offset = shifted_branch_offset(L, false); |
| 1167 beq(rs, r2, offset); | 1264 beq(rs, r2, offset); |
| 1168 break; | 1265 break; |
| 1169 case ne: | 1266 case ne: |
| 1170 offset = shifted_branch_offset(L, false); | 1267 offset = shifted_branch_offset(L, false); |
| 1171 bne(rs, r2, offset); | 1268 bne(rs, r2, offset); |
| 1172 break; | 1269 break; |
| 1173 // Signed comparison | 1270 // Signed comparison. |
| 1174 case greater: | 1271 case greater: |
| 1175 if (r2.is(zero_reg)) { | 1272 if (r2.is(zero_reg)) { |
| 1176 offset = shifted_branch_offset(L, false); | 1273 offset = shifted_branch_offset(L, false); |
| 1177 bgtz(rs, offset); | 1274 bgtz(rs, offset); |
| 1178 } else { | 1275 } else { |
| 1179 slt(scratch, r2, rs); | 1276 slt(scratch, r2, rs); |
| 1180 offset = shifted_branch_offset(L, false); | 1277 offset = shifted_branch_offset(L, false); |
| 1181 bne(scratch, zero_reg, offset); | 1278 bne(scratch, zero_reg, offset); |
| 1182 } | 1279 } |
| 1183 break; | 1280 break; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1269 li(r2, rt); | 1366 li(r2, rt); |
| 1270 offset = shifted_branch_offset(L, false); | 1367 offset = shifted_branch_offset(L, false); |
| 1271 beq(rs, r2, offset); | 1368 beq(rs, r2, offset); |
| 1272 break; | 1369 break; |
| 1273 case ne: | 1370 case ne: |
| 1274 r2 = scratch; | 1371 r2 = scratch; |
| 1275 li(r2, rt); | 1372 li(r2, rt); |
| 1276 offset = shifted_branch_offset(L, false); | 1373 offset = shifted_branch_offset(L, false); |
| 1277 bne(rs, r2, offset); | 1374 bne(rs, r2, offset); |
| 1278 break; | 1375 break; |
| 1279 // Signed comparison | 1376 // Signed comparison. |
| 1280 case greater: | 1377 case greater: |
| 1281 if (rt.imm32_ == 0) { | 1378 if (rt.imm32_ == 0) { |
| 1282 offset = shifted_branch_offset(L, false); | 1379 offset = shifted_branch_offset(L, false); |
| 1283 bgtz(rs, offset); | 1380 bgtz(rs, offset); |
| 1284 } else { | 1381 } else { |
| 1285 r2 = scratch; | 1382 r2 = scratch; |
| 1286 li(r2, rt); | 1383 li(r2, rt); |
| 1287 slt(scratch, r2, rs); | 1384 slt(scratch, r2, rs); |
| 1288 offset = shifted_branch_offset(L, false); | 1385 offset = shifted_branch_offset(L, false); |
| 1289 bne(scratch, zero_reg, offset); | 1386 bne(scratch, zero_reg, offset); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1437 bne(rs, r2, 2); | 1534 bne(rs, r2, 2); |
| 1438 nop(); | 1535 nop(); |
| 1439 bal(offset); | 1536 bal(offset); |
| 1440 break; | 1537 break; |
| 1441 case ne: | 1538 case ne: |
| 1442 beq(rs, r2, 2); | 1539 beq(rs, r2, 2); |
| 1443 nop(); | 1540 nop(); |
| 1444 bal(offset); | 1541 bal(offset); |
| 1445 break; | 1542 break; |
| 1446 | 1543 |
| 1447 // Signed comparison | 1544 // Signed comparison. |
| 1448 case greater: | 1545 case greater: |
| 1449 slt(scratch, r2, rs); | 1546 slt(scratch, r2, rs); |
| 1450 addiu(scratch, scratch, -1); | 1547 addiu(scratch, scratch, -1); |
| 1451 bgezal(scratch, offset); | 1548 bgezal(scratch, offset); |
| 1452 break; | 1549 break; |
| 1453 case greater_equal: | 1550 case greater_equal: |
| 1454 slt(scratch, rs, r2); | 1551 slt(scratch, rs, r2); |
| 1455 addiu(scratch, scratch, -1); | 1552 addiu(scratch, scratch, -1); |
| 1456 bltzal(scratch, offset); | 1553 bltzal(scratch, offset); |
| 1457 break; | 1554 break; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 offset = shifted_branch_offset(L, false); | 1629 offset = shifted_branch_offset(L, false); |
| 1533 bal(offset); | 1630 bal(offset); |
| 1534 break; | 1631 break; |
| 1535 case ne: | 1632 case ne: |
| 1536 beq(rs, r2, 2); | 1633 beq(rs, r2, 2); |
| 1537 nop(); | 1634 nop(); |
| 1538 offset = shifted_branch_offset(L, false); | 1635 offset = shifted_branch_offset(L, false); |
| 1539 bal(offset); | 1636 bal(offset); |
| 1540 break; | 1637 break; |
| 1541 | 1638 |
| 1542 // Signed comparison | 1639 // Signed comparison. |
| 1543 case greater: | 1640 case greater: |
| 1544 slt(scratch, r2, rs); | 1641 slt(scratch, r2, rs); |
| 1545 addiu(scratch, scratch, -1); | 1642 addiu(scratch, scratch, -1); |
| 1546 offset = shifted_branch_offset(L, false); | 1643 offset = shifted_branch_offset(L, false); |
| 1547 bgezal(scratch, offset); | 1644 bgezal(scratch, offset); |
| 1548 break; | 1645 break; |
| 1549 case greater_equal: | 1646 case greater_equal: |
| 1550 slt(scratch, rs, r2); | 1647 slt(scratch, rs, r2); |
| 1551 addiu(scratch, scratch, -1); | 1648 addiu(scratch, scratch, -1); |
| 1552 offset = shifted_branch_offset(L, false); | 1649 offset = shifted_branch_offset(L, false); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1635 jr(target.rm()); | 1732 jr(target.rm()); |
| 1636 } | 1733 } |
| 1637 } else { // Not register target. | 1734 } else { // Not register target. |
| 1638 if (!MustUseReg(target.rmode_)) { | 1735 if (!MustUseReg(target.rmode_)) { |
| 1639 if (cond == cc_always) { | 1736 if (cond == cc_always) { |
| 1640 j(target.imm32_); | 1737 j(target.imm32_); |
| 1641 } else { | 1738 } else { |
| 1642 Branch(2, NegateCondition(cond), rs, rt); | 1739 Branch(2, NegateCondition(cond), rs, rt); |
| 1643 j(target.imm32_); // Will generate only one instruction. | 1740 j(target.imm32_); // Will generate only one instruction. |
| 1644 } | 1741 } |
| 1645 } else { // MustUseReg(target) | 1742 } else { // MustUseReg(target). |
| 1646 li(t9, target); | 1743 li(t9, target); |
| 1647 if (cond == cc_always) { | 1744 if (cond == cc_always) { |
| 1648 jr(t9); | 1745 jr(t9); |
| 1649 } else { | 1746 } else { |
| 1650 Branch(2, NegateCondition(cond), rs, rt); | 1747 Branch(2, NegateCondition(cond), rs, rt); |
| 1651 jr(t9); // Will generate only one instruction. | 1748 jr(t9); // Will generate only one instruction. |
| 1652 } | 1749 } |
| 1653 } | 1750 } |
| 1654 } | 1751 } |
| 1655 // Emit a nop in the branch delay slot if required. | 1752 // Emit a nop in the branch delay slot if required. |
| 1656 if (bdslot == PROTECT) | 1753 if (bdslot == PROTECT) |
| 1657 nop(); | 1754 nop(); |
| 1658 } | 1755 } |
| 1659 | 1756 |
| 1660 | 1757 |
| 1661 int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode) { | 1758 int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode) { |
| 1662 UNIMPLEMENTED_MIPS(); | 1759 return 4 * kInstrSize; |
| 1663 return 0; | |
| 1664 } | 1760 } |
| 1665 | 1761 |
| 1666 | 1762 |
| 1667 int MacroAssembler::CallSize(Register reg) { | 1763 int MacroAssembler::CallSize(Register reg) { |
| 1668 UNIMPLEMENTED_MIPS(); | 1764 return 2 * kInstrSize; |
| 1669 return 0; | |
| 1670 } | 1765 } |
| 1671 | 1766 |
| 1672 | 1767 |
| 1673 // Note: To call gcc-compiled C code on mips, you must call thru t9. | 1768 // Note: To call gcc-compiled C code on mips, you must call thru t9. |
| 1674 void MacroAssembler::Call(const Operand& target, BranchDelaySlot bdslot) { | 1769 void MacroAssembler::Call(const Operand& target, BranchDelaySlot bdslot) { |
| 1675 BlockTrampolinePoolScope block_trampoline_pool(this); | 1770 BlockTrampolinePoolScope block_trampoline_pool(this); |
| 1676 if (target.is_reg()) { | 1771 if (target.is_reg()) { |
| 1677 jalr(target.rm()); | 1772 jalr(target.rm()); |
| 1678 } else { // !target.is_reg() | 1773 } else { // !target.is_reg(). |
| 1679 if (!MustUseReg(target.rmode_)) { | 1774 if (!MustUseReg(target.rmode_)) { |
| 1680 jal(target.imm32_); | 1775 jal(target.imm32_); |
| 1681 } else { // MustUseReg(target) | 1776 } else { // MustUseReg(target). |
| 1777 // Must record previous source positions before the |
| 1778 // li() generates a new code target. |
| 1779 positions_recorder()->WriteRecordedPositions(); |
| 1682 li(t9, target); | 1780 li(t9, target); |
| 1683 jalr(t9); | 1781 jalr(t9); |
| 1684 } | 1782 } |
| 1685 } | 1783 } |
| 1686 // Emit a nop in the branch delay slot if required. | 1784 // Emit a nop in the branch delay slot if required. |
| 1687 if (bdslot == PROTECT) | 1785 if (bdslot == PROTECT) |
| 1688 nop(); | 1786 nop(); |
| 1689 } | 1787 } |
| 1690 | 1788 |
| 1691 | 1789 |
| 1692 // Note: To call gcc-compiled C code on mips, you must call thru t9. | 1790 // Note: To call gcc-compiled C code on mips, you must call thru t9. |
| 1693 void MacroAssembler::Call(const Operand& target, | 1791 void MacroAssembler::Call(const Operand& target, |
| 1694 Condition cond, Register rs, const Operand& rt, | 1792 Condition cond, Register rs, const Operand& rt, |
| 1695 BranchDelaySlot bdslot) { | 1793 BranchDelaySlot bdslot) { |
| 1696 BlockTrampolinePoolScope block_trampoline_pool(this); | 1794 BlockTrampolinePoolScope block_trampoline_pool(this); |
| 1697 BRANCH_ARGS_CHECK(cond, rs, rt); | 1795 BRANCH_ARGS_CHECK(cond, rs, rt); |
| 1698 if (target.is_reg()) { | 1796 if (target.is_reg()) { |
| 1699 if (cond == cc_always) { | 1797 if (cond == cc_always) { |
| 1700 jalr(target.rm()); | 1798 jalr(target.rm()); |
| 1701 } else { | 1799 } else { |
| 1702 Branch(2, NegateCondition(cond), rs, rt); | 1800 Branch(2, NegateCondition(cond), rs, rt); |
| 1703 jalr(target.rm()); | 1801 jalr(target.rm()); |
| 1704 } | 1802 } |
| 1705 } else { // !target.is_reg() | 1803 } else { // !target.is_reg(). |
| 1706 if (!MustUseReg(target.rmode_)) { | 1804 if (!MustUseReg(target.rmode_)) { |
| 1707 if (cond == cc_always) { | 1805 if (cond == cc_always) { |
| 1708 jal(target.imm32_); | 1806 jal(target.imm32_); |
| 1709 } else { | 1807 } else { |
| 1710 Branch(2, NegateCondition(cond), rs, rt); | 1808 Branch(2, NegateCondition(cond), rs, rt); |
| 1711 jal(target.imm32_); // Will generate only one instruction. | 1809 jal(target.imm32_); // Will generate only one instruction. |
| 1712 } | 1810 } |
| 1713 } else { // MustUseReg(target) | 1811 } else { // MustUseReg(target) |
| 1714 li(t9, target); | 1812 li(t9, target); |
| 1715 if (cond == cc_always) { | 1813 if (cond == cc_always) { |
| 1716 jalr(t9); | 1814 jalr(t9); |
| 1717 } else { | 1815 } else { |
| 1718 Branch(2, NegateCondition(cond), rs, rt); | 1816 Branch(2, NegateCondition(cond), rs, rt); |
| 1719 jalr(t9); // Will generate only one instruction. | 1817 jalr(t9); // Will generate only one instruction. |
| 1720 } | 1818 } |
| 1721 } | 1819 } |
| 1722 } | 1820 } |
| 1723 // Emit a nop in the branch delay slot if required. | 1821 // Emit a nop in the branch delay slot if required. |
| 1724 if (bdslot == PROTECT) | 1822 if (bdslot == PROTECT) |
| 1725 nop(); | 1823 nop(); |
| 1726 } | 1824 } |
| 1727 | 1825 |
| 1728 | 1826 |
| 1827 void MacroAssembler::CallWithAstId(Handle<Code> code, |
| 1828 RelocInfo::Mode rmode, |
| 1829 unsigned ast_id, |
| 1830 Condition cond, |
| 1831 Register r1, |
| 1832 const Operand& r2) { |
| 1833 ASSERT(rmode == RelocInfo::CODE_TARGET_WITH_ID); |
| 1834 ASSERT(ast_id != kNoASTId); |
| 1835 ASSERT(ast_id_for_reloc_info_ == kNoASTId); |
| 1836 ast_id_for_reloc_info_ = ast_id; |
| 1837 Call(reinterpret_cast<intptr_t>(code.location()), rmode, cond, r1, r2); |
| 1838 } |
| 1839 |
| 1840 |
| 1729 void MacroAssembler::Drop(int count, | 1841 void MacroAssembler::Drop(int count, |
| 1730 Condition cond, | 1842 Condition cond, |
| 1731 Register reg, | 1843 Register reg, |
| 1732 const Operand& op) { | 1844 const Operand& op) { |
| 1733 if (count <= 0) { | 1845 if (count <= 0) { |
| 1734 return; | 1846 return; |
| 1735 } | 1847 } |
| 1736 | 1848 |
| 1737 Label skip; | 1849 Label skip; |
| 1738 | 1850 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1805 mov(a0, zero_reg); | 1917 mov(a0, zero_reg); |
| 1806 li(a1, Operand(ExternalReference(Runtime::kDebugBreak, isolate()))); | 1918 li(a1, Operand(ExternalReference(Runtime::kDebugBreak, isolate()))); |
| 1807 CEntryStub ces(1); | 1919 CEntryStub ces(1); |
| 1808 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 1920 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); |
| 1809 } | 1921 } |
| 1810 | 1922 |
| 1811 #endif // ENABLE_DEBUGGER_SUPPORT | 1923 #endif // ENABLE_DEBUGGER_SUPPORT |
| 1812 | 1924 |
| 1813 | 1925 |
| 1814 // --------------------------------------------------------------------------- | 1926 // --------------------------------------------------------------------------- |
| 1815 // Exception handling | 1927 // Exception handling. |
| 1816 | 1928 |
| 1817 void MacroAssembler::PushTryHandler(CodeLocation try_location, | 1929 void MacroAssembler::PushTryHandler(CodeLocation try_location, |
| 1818 HandlerType type) { | 1930 HandlerType type) { |
| 1819 // Adjust this code if not the case. | 1931 // Adjust this code if not the case. |
| 1820 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); | 1932 ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
| 1821 // The return address is passed in register ra. | 1933 // The return address is passed in register ra. |
| 1822 if (try_location == IN_JAVASCRIPT) { | 1934 if (try_location == IN_JAVASCRIPT) { |
| 1823 if (type == TRY_CATCH_HANDLER) { | 1935 if (type == TRY_CATCH_HANDLER) { |
| 1824 li(t0, Operand(StackHandler::TRY_CATCH)); | 1936 li(t0, Operand(StackHandler::TRY_CATCH)); |
| 1825 } else { | 1937 } else { |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1880 } | 1992 } |
| 1881 | 1993 |
| 1882 | 1994 |
| 1883 void MacroAssembler::AllocateInNewSpace(int object_size, | 1995 void MacroAssembler::AllocateInNewSpace(int object_size, |
| 1884 Register result, | 1996 Register result, |
| 1885 Register scratch1, | 1997 Register scratch1, |
| 1886 Register scratch2, | 1998 Register scratch2, |
| 1887 Label* gc_required, | 1999 Label* gc_required, |
| 1888 AllocationFlags flags) { | 2000 AllocationFlags flags) { |
| 1889 if (!FLAG_inline_new) { | 2001 if (!FLAG_inline_new) { |
| 1890 if (FLAG_debug_code) { | 2002 if (emit_debug_code()) { |
| 1891 // Trash the registers to simulate an allocation failure. | 2003 // Trash the registers to simulate an allocation failure. |
| 1892 li(result, 0x7091); | 2004 li(result, 0x7091); |
| 1893 li(scratch1, 0x7191); | 2005 li(scratch1, 0x7191); |
| 1894 li(scratch2, 0x7291); | 2006 li(scratch2, 0x7291); |
| 1895 } | 2007 } |
| 1896 jmp(gc_required); | 2008 jmp(gc_required); |
| 1897 return; | 2009 return; |
| 1898 } | 2010 } |
| 1899 | 2011 |
| 1900 ASSERT(!result.is(scratch1)); | 2012 ASSERT(!result.is(scratch1)); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1928 Register obj_size_reg = scratch2; | 2040 Register obj_size_reg = scratch2; |
| 1929 li(topaddr, Operand(new_space_allocation_top)); | 2041 li(topaddr, Operand(new_space_allocation_top)); |
| 1930 li(obj_size_reg, Operand(object_size)); | 2042 li(obj_size_reg, Operand(object_size)); |
| 1931 | 2043 |
| 1932 // This code stores a temporary value in t9. | 2044 // This code stores a temporary value in t9. |
| 1933 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 2045 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 1934 // Load allocation top into result and allocation limit into t9. | 2046 // Load allocation top into result and allocation limit into t9. |
| 1935 lw(result, MemOperand(topaddr)); | 2047 lw(result, MemOperand(topaddr)); |
| 1936 lw(t9, MemOperand(topaddr, kPointerSize)); | 2048 lw(t9, MemOperand(topaddr, kPointerSize)); |
| 1937 } else { | 2049 } else { |
| 1938 if (FLAG_debug_code) { | 2050 if (emit_debug_code()) { |
| 1939 // Assert that result actually contains top on entry. t9 is used | 2051 // Assert that result actually contains top on entry. t9 is used |
| 1940 // immediately below so this use of t9 does not cause difference with | 2052 // immediately below so this use of t9 does not cause difference with |
| 1941 // respect to register content between debug and release mode. | 2053 // respect to register content between debug and release mode. |
| 1942 lw(t9, MemOperand(topaddr)); | 2054 lw(t9, MemOperand(topaddr)); |
| 1943 Check(eq, "Unexpected allocation top", result, Operand(t9)); | 2055 Check(eq, "Unexpected allocation top", result, Operand(t9)); |
| 1944 } | 2056 } |
| 1945 // Load allocation limit into t9. Result already contains allocation top. | 2057 // Load allocation limit into t9. Result already contains allocation top. |
| 1946 lw(t9, MemOperand(topaddr, limit - top)); | 2058 lw(t9, MemOperand(topaddr, limit - top)); |
| 1947 } | 2059 } |
| 1948 | 2060 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1959 } | 2071 } |
| 1960 | 2072 |
| 1961 | 2073 |
| 1962 void MacroAssembler::AllocateInNewSpace(Register object_size, | 2074 void MacroAssembler::AllocateInNewSpace(Register object_size, |
| 1963 Register result, | 2075 Register result, |
| 1964 Register scratch1, | 2076 Register scratch1, |
| 1965 Register scratch2, | 2077 Register scratch2, |
| 1966 Label* gc_required, | 2078 Label* gc_required, |
| 1967 AllocationFlags flags) { | 2079 AllocationFlags flags) { |
| 1968 if (!FLAG_inline_new) { | 2080 if (!FLAG_inline_new) { |
| 1969 if (FLAG_debug_code) { | 2081 if (emit_debug_code()) { |
| 1970 // Trash the registers to simulate an allocation failure. | 2082 // Trash the registers to simulate an allocation failure. |
| 1971 li(result, 0x7091); | 2083 li(result, 0x7091); |
| 1972 li(scratch1, 0x7191); | 2084 li(scratch1, 0x7191); |
| 1973 li(scratch2, 0x7291); | 2085 li(scratch2, 0x7291); |
| 1974 } | 2086 } |
| 1975 jmp(gc_required); | 2087 jmp(gc_required); |
| 1976 return; | 2088 return; |
| 1977 } | 2089 } |
| 1978 | 2090 |
| 1979 ASSERT(!result.is(scratch1)); | 2091 ASSERT(!result.is(scratch1)); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1997 // Set up allocation top address and object size registers. | 2109 // Set up allocation top address and object size registers. |
| 1998 Register topaddr = scratch1; | 2110 Register topaddr = scratch1; |
| 1999 li(topaddr, Operand(new_space_allocation_top)); | 2111 li(topaddr, Operand(new_space_allocation_top)); |
| 2000 | 2112 |
| 2001 // This code stores a temporary value in t9. | 2113 // This code stores a temporary value in t9. |
| 2002 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 2114 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 2003 // Load allocation top into result and allocation limit into t9. | 2115 // Load allocation top into result and allocation limit into t9. |
| 2004 lw(result, MemOperand(topaddr)); | 2116 lw(result, MemOperand(topaddr)); |
| 2005 lw(t9, MemOperand(topaddr, kPointerSize)); | 2117 lw(t9, MemOperand(topaddr, kPointerSize)); |
| 2006 } else { | 2118 } else { |
| 2007 if (FLAG_debug_code) { | 2119 if (emit_debug_code()) { |
| 2008 // Assert that result actually contains top on entry. t9 is used | 2120 // Assert that result actually contains top on entry. t9 is used |
| 2009 // immediately below so this use of t9 does not cause difference with | 2121 // immediately below so this use of t9 does not cause difference with |
| 2010 // respect to register content between debug and release mode. | 2122 // respect to register content between debug and release mode. |
| 2011 lw(t9, MemOperand(topaddr)); | 2123 lw(t9, MemOperand(topaddr)); |
| 2012 Check(eq, "Unexpected allocation top", result, Operand(t9)); | 2124 Check(eq, "Unexpected allocation top", result, Operand(t9)); |
| 2013 } | 2125 } |
| 2014 // Load allocation limit into t9. Result already contains allocation top. | 2126 // Load allocation limit into t9. Result already contains allocation top. |
| 2015 lw(t9, MemOperand(topaddr, limit - top)); | 2127 lw(t9, MemOperand(topaddr, limit - top)); |
| 2016 } | 2128 } |
| 2017 | 2129 |
| 2018 // Calculate new top and bail out if new space is exhausted. Use result | 2130 // Calculate new top and bail out if new space is exhausted. Use result |
| 2019 // to calculate the new top. Object size may be in words so a shift is | 2131 // to calculate the new top. Object size may be in words so a shift is |
| 2020 // required to get the number of bytes. | 2132 // required to get the number of bytes. |
| 2021 if ((flags & SIZE_IN_WORDS) != 0) { | 2133 if ((flags & SIZE_IN_WORDS) != 0) { |
| 2022 sll(scratch2, object_size, kPointerSizeLog2); | 2134 sll(scratch2, object_size, kPointerSizeLog2); |
| 2023 Addu(scratch2, result, scratch2); | 2135 Addu(scratch2, result, scratch2); |
| 2024 } else { | 2136 } else { |
| 2025 Addu(scratch2, result, Operand(object_size)); | 2137 Addu(scratch2, result, Operand(object_size)); |
| 2026 } | 2138 } |
| 2027 Branch(gc_required, Ugreater, scratch2, Operand(t9)); | 2139 Branch(gc_required, Ugreater, scratch2, Operand(t9)); |
| 2028 | 2140 |
| 2029 // Update allocation top. result temporarily holds the new top. | 2141 // Update allocation top. result temporarily holds the new top. |
| 2030 if (FLAG_debug_code) { | 2142 if (emit_debug_code()) { |
| 2031 And(t9, scratch2, Operand(kObjectAlignmentMask)); | 2143 And(t9, scratch2, Operand(kObjectAlignmentMask)); |
| 2032 Check(eq, "Unaligned allocation in new space", t9, Operand(zero_reg)); | 2144 Check(eq, "Unaligned allocation in new space", t9, Operand(zero_reg)); |
| 2033 } | 2145 } |
| 2034 sw(scratch2, MemOperand(topaddr)); | 2146 sw(scratch2, MemOperand(topaddr)); |
| 2035 | 2147 |
| 2036 // Tag object if requested. | 2148 // Tag object if requested. |
| 2037 if ((flags & TAG_OBJECT) != 0) { | 2149 if ((flags & TAG_OBJECT) != 0) { |
| 2038 Addu(result, result, Operand(kHeapObjectTag)); | 2150 Addu(result, result, Operand(kHeapObjectTag)); |
| 2039 } | 2151 } |
| 2040 } | 2152 } |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2211 } | 2323 } |
| 2212 ASSERT(!tmp.is(no_reg)); | 2324 ASSERT(!tmp.is(no_reg)); |
| 2213 | 2325 |
| 2214 for (int i = 0; i < field_count; i++) { | 2326 for (int i = 0; i < field_count; i++) { |
| 2215 lw(tmp, FieldMemOperand(src, i * kPointerSize)); | 2327 lw(tmp, FieldMemOperand(src, i * kPointerSize)); |
| 2216 sw(tmp, FieldMemOperand(dst, i * kPointerSize)); | 2328 sw(tmp, FieldMemOperand(dst, i * kPointerSize)); |
| 2217 } | 2329 } |
| 2218 } | 2330 } |
| 2219 | 2331 |
| 2220 | 2332 |
| 2333 void MacroAssembler::CopyBytes(Register src, |
| 2334 Register dst, |
| 2335 Register length, |
| 2336 Register scratch) { |
| 2337 Label align_loop, align_loop_1, word_loop, byte_loop, byte_loop_1, done; |
| 2338 |
| 2339 // Align src before copying in word size chunks. |
| 2340 bind(&align_loop); |
| 2341 Branch(&done, eq, length, Operand(zero_reg)); |
| 2342 bind(&align_loop_1); |
| 2343 And(scratch, src, kPointerSize - 1); |
| 2344 Branch(&word_loop, eq, scratch, Operand(zero_reg)); |
| 2345 lbu(scratch, MemOperand(src)); |
| 2346 Addu(src, src, 1); |
| 2347 sb(scratch, MemOperand(dst)); |
| 2348 Addu(dst, dst, 1); |
| 2349 Subu(length, length, Operand(1)); |
| 2350 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); |
| 2351 |
| 2352 // Copy bytes in word size chunks. |
| 2353 bind(&word_loop); |
| 2354 if (FLAG_debug_code) { |
| 2355 And(scratch, src, kPointerSize - 1); |
| 2356 Assert(eq, "Expecting alignment for CopyBytes", |
| 2357 scratch, Operand(zero_reg)); |
| 2358 } |
| 2359 Branch(&byte_loop, lt, length, Operand(kPointerSize)); |
| 2360 lw(scratch, MemOperand(src)); |
| 2361 Addu(src, src, kPointerSize); |
| 2362 |
| 2363 // TODO(kalmard) check if this can be optimized to use sw in most cases. |
| 2364 // Can't use unaligned access - copy byte by byte. |
| 2365 sb(scratch, MemOperand(dst, 0)); |
| 2366 srl(scratch, scratch, 8); |
| 2367 sb(scratch, MemOperand(dst, 1)); |
| 2368 srl(scratch, scratch, 8); |
| 2369 sb(scratch, MemOperand(dst, 2)); |
| 2370 srl(scratch, scratch, 8); |
| 2371 sb(scratch, MemOperand(dst, 3)); |
| 2372 Addu(dst, dst, 4); |
| 2373 |
| 2374 Subu(length, length, Operand(kPointerSize)); |
| 2375 Branch(&word_loop); |
| 2376 |
| 2377 // Copy the last bytes if any left. |
| 2378 bind(&byte_loop); |
| 2379 Branch(&done, eq, length, Operand(zero_reg)); |
| 2380 bind(&byte_loop_1); |
| 2381 lbu(scratch, MemOperand(src)); |
| 2382 Addu(src, src, 1); |
| 2383 sb(scratch, MemOperand(dst)); |
| 2384 Addu(dst, dst, 1); |
| 2385 Subu(length, length, Operand(1)); |
| 2386 Branch(&byte_loop_1, ne, length, Operand(zero_reg)); |
| 2387 bind(&done); |
| 2388 } |
| 2389 |
| 2390 |
| 2221 void MacroAssembler::CheckMap(Register obj, | 2391 void MacroAssembler::CheckMap(Register obj, |
| 2222 Register scratch, | 2392 Register scratch, |
| 2223 Handle<Map> map, | 2393 Handle<Map> map, |
| 2224 Label* fail, | 2394 Label* fail, |
| 2225 bool is_heap_object) { | 2395 bool is_heap_object) { |
| 2226 if (!is_heap_object) { | 2396 if (!is_heap_object) { |
| 2227 JumpIfSmi(obj, fail); | 2397 JumpIfSmi(obj, fail); |
| 2228 } | 2398 } |
| 2229 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); | 2399 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 2230 li(at, Operand(map)); | 2400 li(at, Operand(map)); |
| 2231 Branch(fail, ne, scratch, Operand(at)); | 2401 Branch(fail, ne, scratch, Operand(at)); |
| 2232 } | 2402 } |
| 2233 | 2403 |
| 2234 | 2404 |
| 2235 void MacroAssembler::CheckMap(Register obj, | 2405 void MacroAssembler::CheckMap(Register obj, |
| 2236 Register scratch, | 2406 Register scratch, |
| 2237 Heap::RootListIndex index, | 2407 Heap::RootListIndex index, |
| 2238 Label* fail, | 2408 Label* fail, |
| 2239 bool is_heap_object) { | 2409 bool is_heap_object) { |
| 2240 if (!is_heap_object) { | 2410 if (!is_heap_object) { |
| 2241 JumpIfSmi(obj, fail); | 2411 JumpIfSmi(obj, fail); |
| 2242 } | 2412 } |
| 2243 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); | 2413 lw(scratch, FieldMemOperand(obj, HeapObject::kMapOffset)); |
| 2244 LoadRoot(at, index); | 2414 LoadRoot(at, index); |
| 2245 Branch(fail, ne, scratch, Operand(at)); | 2415 Branch(fail, ne, scratch, Operand(at)); |
| 2246 } | 2416 } |
| 2247 | 2417 |
| 2248 | 2418 |
| 2419 void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) { |
| 2420 if (IsMipsSoftFloatABI) { |
| 2421 mtc1(v0, dst); |
| 2422 mtc1(v1, FPURegister::from_code(dst.code() + 1)); |
| 2423 } else { |
| 2424 if (!dst.is(f0)) { |
| 2425 mov_d(dst, f0); // Reg f0 is o32 ABI FP return value. |
| 2426 } |
| 2427 } |
| 2428 } |
| 2429 |
| 2430 |
| 2249 // ----------------------------------------------------------------------------- | 2431 // ----------------------------------------------------------------------------- |
| 2250 // JavaScript invokes | 2432 // JavaScript invokes. |
| 2251 | 2433 |
| 2252 void MacroAssembler::InvokePrologue(const ParameterCount& expected, | 2434 void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
| 2253 const ParameterCount& actual, | 2435 const ParameterCount& actual, |
| 2254 Handle<Code> code_constant, | 2436 Handle<Code> code_constant, |
| 2255 Register code_reg, | 2437 Register code_reg, |
| 2256 Label* done, | 2438 Label* done, |
| 2257 InvokeFlag flag, | 2439 InvokeFlag flag, |
| 2258 const CallWrapper& call_wrapper) { | 2440 const CallWrapper& call_wrapper) { |
| 2259 bool definitely_matches = false; | 2441 bool definitely_matches = false; |
| 2260 Label regular_invoke; | 2442 Label regular_invoke; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2283 if (expected.immediate() == sentinel) { | 2465 if (expected.immediate() == sentinel) { |
| 2284 // Don't worry about adapting arguments for builtins that | 2466 // Don't worry about adapting arguments for builtins that |
| 2285 // don't want that done. Skip adaption code by making it look | 2467 // don't want that done. Skip adaption code by making it look |
| 2286 // like we have a match between expected and actual number of | 2468 // like we have a match between expected and actual number of |
| 2287 // arguments. | 2469 // arguments. |
| 2288 definitely_matches = true; | 2470 definitely_matches = true; |
| 2289 } else { | 2471 } else { |
| 2290 li(a2, Operand(expected.immediate())); | 2472 li(a2, Operand(expected.immediate())); |
| 2291 } | 2473 } |
| 2292 } | 2474 } |
| 2475 } else if (actual.is_immediate()) { |
| 2476 Branch(®ular_invoke, eq, expected.reg(), Operand(actual.immediate())); |
| 2477 li(a0, Operand(actual.immediate())); |
| 2293 } else { | 2478 } else { |
| 2294 if (actual.is_immediate()) { | 2479 Branch(®ular_invoke, eq, expected.reg(), Operand(actual.reg())); |
| 2295 Branch(®ular_invoke, eq, expected.reg(), Operand(actual.immediate())); | |
| 2296 li(a0, Operand(actual.immediate())); | |
| 2297 } else { | |
| 2298 Branch(®ular_invoke, eq, expected.reg(), Operand(actual.reg())); | |
| 2299 } | |
| 2300 } | 2480 } |
| 2301 | 2481 |
| 2302 if (!definitely_matches) { | 2482 if (!definitely_matches) { |
| 2303 if (!code_constant.is_null()) { | 2483 if (!code_constant.is_null()) { |
| 2304 li(a3, Operand(code_constant)); | 2484 li(a3, Operand(code_constant)); |
| 2305 addiu(a3, a3, Code::kHeaderSize - kHeapObjectTag); | 2485 addiu(a3, a3, Code::kHeaderSize - kHeapObjectTag); |
| 2306 } | 2486 } |
| 2307 | 2487 |
| 2308 Handle<Code> adaptor = | 2488 Handle<Code> adaptor = |
| 2309 isolate()->builtins()->ArgumentsAdaptorTrampoline(); | 2489 isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2484 | 2664 |
| 2485 void MacroAssembler::GetObjectType(Register object, | 2665 void MacroAssembler::GetObjectType(Register object, |
| 2486 Register map, | 2666 Register map, |
| 2487 Register type_reg) { | 2667 Register type_reg) { |
| 2488 lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); | 2668 lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2489 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 2669 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 2490 } | 2670 } |
| 2491 | 2671 |
| 2492 | 2672 |
| 2493 // ----------------------------------------------------------------------------- | 2673 // ----------------------------------------------------------------------------- |
| 2494 // Runtime calls | 2674 // Runtime calls. |
| 2495 | 2675 |
| 2496 void MacroAssembler::CallStub(CodeStub* stub, Condition cond, | 2676 void MacroAssembler::CallStub(CodeStub* stub, Condition cond, |
| 2497 Register r1, const Operand& r2) { | 2677 Register r1, const Operand& r2) { |
| 2498 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. | 2678 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. |
| 2499 Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2); | 2679 Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2); |
| 2500 } | 2680 } |
| 2501 | 2681 |
| 2502 | 2682 |
| 2503 void MacroAssembler::TailCallStub(CodeStub* stub) { | 2683 void MacroAssembler::TailCallStub(CodeStub* stub) { |
| 2504 ASSERT(allow_stub_calls()); // stub calls are not allowed in some stubs | 2684 ASSERT(allow_stub_calls()); // Stub calls are not allowed in some stubs. |
| 2505 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); | 2685 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); |
| 2506 } | 2686 } |
| 2507 | 2687 |
| 2508 | 2688 |
| 2509 void MacroAssembler::IllegalOperation(int num_arguments) { | 2689 void MacroAssembler::IllegalOperation(int num_arguments) { |
| 2510 if (num_arguments > 0) { | 2690 if (num_arguments > 0) { |
| 2511 addiu(sp, sp, num_arguments * kPointerSize); | 2691 addiu(sp, sp, num_arguments * kPointerSize); |
| 2512 } | 2692 } |
| 2513 LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 2693 LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
| 2514 } | 2694 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2560 li(mask_reg, HeapNumber::kExponentMask); | 2740 li(mask_reg, HeapNumber::kExponentMask); |
| 2561 | 2741 |
| 2562 And(exponent, exponent, mask_reg); | 2742 And(exponent, exponent, mask_reg); |
| 2563 Branch(not_number, eq, exponent, Operand(mask_reg)); | 2743 Branch(not_number, eq, exponent, Operand(mask_reg)); |
| 2564 } | 2744 } |
| 2565 ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset)); | 2745 ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset)); |
| 2566 bind(&done); | 2746 bind(&done); |
| 2567 } | 2747 } |
| 2568 | 2748 |
| 2569 | 2749 |
| 2570 | |
| 2571 void MacroAssembler::SmiToDoubleFPURegister(Register smi, | 2750 void MacroAssembler::SmiToDoubleFPURegister(Register smi, |
| 2572 FPURegister value, | 2751 FPURegister value, |
| 2573 Register scratch1) { | 2752 Register scratch1) { |
| 2574 sra(scratch1, smi, kSmiTagSize); | 2753 sra(scratch1, smi, kSmiTagSize); |
| 2575 mtc1(scratch1, value); | 2754 mtc1(scratch1, value); |
| 2576 cvt_d_w(value, value); | 2755 cvt_d_w(value, value); |
| 2577 } | 2756 } |
| 2578 | 2757 |
| 2579 | 2758 |
| 2759 void MacroAssembler::AdduAndCheckForOverflow(Register dst, |
| 2760 Register left, |
| 2761 Register right, |
| 2762 Register overflow_dst, |
| 2763 Register scratch) { |
| 2764 ASSERT(!dst.is(overflow_dst)); |
| 2765 ASSERT(!dst.is(scratch)); |
| 2766 ASSERT(!overflow_dst.is(scratch)); |
| 2767 ASSERT(!overflow_dst.is(left)); |
| 2768 ASSERT(!overflow_dst.is(right)); |
| 2769 ASSERT(!left.is(right)); |
| 2770 |
| 2771 // TODO(kalmard) There must be a way to optimize dst == left and dst == right |
| 2772 // cases. |
| 2773 |
| 2774 if (dst.is(left)) { |
| 2775 addu(overflow_dst, left, right); |
| 2776 xor_(dst, overflow_dst, left); |
| 2777 xor_(scratch, overflow_dst, right); |
| 2778 and_(scratch, scratch, dst); |
| 2779 mov(dst, overflow_dst); |
| 2780 mov(overflow_dst, scratch); |
| 2781 } else if (dst.is(right)) { |
| 2782 addu(overflow_dst, left, right); |
| 2783 xor_(dst, overflow_dst, right); |
| 2784 xor_(scratch, overflow_dst, left); |
| 2785 and_(scratch, scratch, dst); |
| 2786 mov(dst, overflow_dst); |
| 2787 mov(overflow_dst, scratch); |
| 2788 } else { |
| 2789 addu(dst, left, right); |
| 2790 xor_(overflow_dst, dst, left); |
| 2791 xor_(scratch, dst, right); |
| 2792 and_(overflow_dst, scratch, overflow_dst); |
| 2793 } |
| 2794 } |
| 2795 |
| 2796 |
| 2797 void MacroAssembler::SubuAndCheckForOverflow(Register dst, |
| 2798 Register left, |
| 2799 Register right, |
| 2800 Register overflow_dst, |
| 2801 Register scratch) { |
| 2802 ASSERT(!dst.is(overflow_dst)); |
| 2803 ASSERT(!dst.is(scratch)); |
| 2804 ASSERT(!overflow_dst.is(scratch)); |
| 2805 ASSERT(!overflow_dst.is(left)); |
| 2806 ASSERT(!overflow_dst.is(right)); |
| 2807 ASSERT(!left.is(right)); |
| 2808 ASSERT(!scratch.is(left)); |
| 2809 ASSERT(!scratch.is(right)); |
| 2810 |
| 2811 // TODO(kalmard) There must be a way to optimize dst == left and dst == right |
| 2812 // cases. |
| 2813 |
| 2814 if (dst.is(left)) { |
| 2815 subu(overflow_dst, left, right); |
| 2816 xor_(scratch, overflow_dst, left); |
| 2817 xor_(dst, left, right); |
| 2818 and_(scratch, scratch, dst); |
| 2819 mov(dst, overflow_dst); |
| 2820 mov(overflow_dst, scratch); |
| 2821 } else if (dst.is(right)) { |
| 2822 subu(overflow_dst, left, right); |
| 2823 xor_(dst, left, right); |
| 2824 xor_(scratch, overflow_dst, left); |
| 2825 and_(scratch, scratch, dst); |
| 2826 mov(dst, overflow_dst); |
| 2827 mov(overflow_dst, scratch); |
| 2828 } else { |
| 2829 subu(dst, left, right); |
| 2830 xor_(overflow_dst, dst, left); |
| 2831 xor_(scratch, left, right); |
| 2832 and_(overflow_dst, scratch, overflow_dst); |
| 2833 } |
| 2834 } |
| 2835 |
| 2836 |
| 2580 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 2837 void MacroAssembler::CallRuntime(const Runtime::Function* f, |
| 2581 int num_arguments) { | 2838 int num_arguments) { |
| 2582 // All parameters are on the stack. v0 has the return value after call. | 2839 // All parameters are on the stack. v0 has the return value after call. |
| 2583 | 2840 |
| 2584 // If the expected number of arguments of the runtime function is | 2841 // If the expected number of arguments of the runtime function is |
| 2585 // constant, we check that the actual number of arguments match the | 2842 // constant, we check that the actual number of arguments match the |
| 2586 // expectation. | 2843 // expectation. |
| 2587 if (f->nargs >= 0 && f->nargs != num_arguments) { | 2844 if (f->nargs >= 0 && f->nargs != num_arguments) { |
| 2588 IllegalOperation(num_arguments); | 2845 IllegalOperation(num_arguments); |
| 2589 return; | 2846 return; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2715 if (FLAG_native_code_counters && counter->Enabled()) { | 2972 if (FLAG_native_code_counters && counter->Enabled()) { |
| 2716 li(scratch2, Operand(ExternalReference(counter))); | 2973 li(scratch2, Operand(ExternalReference(counter))); |
| 2717 lw(scratch1, MemOperand(scratch2)); | 2974 lw(scratch1, MemOperand(scratch2)); |
| 2718 Subu(scratch1, scratch1, Operand(value)); | 2975 Subu(scratch1, scratch1, Operand(value)); |
| 2719 sw(scratch1, MemOperand(scratch2)); | 2976 sw(scratch1, MemOperand(scratch2)); |
| 2720 } | 2977 } |
| 2721 } | 2978 } |
| 2722 | 2979 |
| 2723 | 2980 |
| 2724 // ----------------------------------------------------------------------------- | 2981 // ----------------------------------------------------------------------------- |
| 2725 // Debugging | 2982 // Debugging. |
| 2726 | 2983 |
| 2727 void MacroAssembler::Assert(Condition cc, const char* msg, | 2984 void MacroAssembler::Assert(Condition cc, const char* msg, |
| 2728 Register rs, Operand rt) { | 2985 Register rs, Operand rt) { |
| 2729 if (FLAG_debug_code) | 2986 if (emit_debug_code()) |
| 2730 Check(cc, msg, rs, rt); | 2987 Check(cc, msg, rs, rt); |
| 2731 } | 2988 } |
| 2732 | 2989 |
| 2733 | 2990 |
| 2734 void MacroAssembler::AssertRegisterIsRoot(Register reg, | 2991 void MacroAssembler::AssertRegisterIsRoot(Register reg, |
| 2735 Heap::RootListIndex index) { | 2992 Heap::RootListIndex index) { |
| 2736 if (FLAG_debug_code) { | 2993 if (emit_debug_code()) { |
| 2737 LoadRoot(at, index); | 2994 LoadRoot(at, index); |
| 2738 Check(eq, "Register did not match expected root", reg, Operand(at)); | 2995 Check(eq, "Register did not match expected root", reg, Operand(at)); |
| 2739 } | 2996 } |
| 2740 } | 2997 } |
| 2741 | 2998 |
| 2742 | 2999 |
| 2743 void MacroAssembler::AssertFastElements(Register elements) { | 3000 void MacroAssembler::AssertFastElements(Register elements) { |
| 2744 if (FLAG_debug_code) { | 3001 if (emit_debug_code()) { |
| 2745 ASSERT(!elements.is(at)); | 3002 ASSERT(!elements.is(at)); |
| 2746 Label ok; | 3003 Label ok; |
| 2747 Push(elements); | 3004 push(elements); |
| 2748 lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); | 3005 lw(elements, FieldMemOperand(elements, HeapObject::kMapOffset)); |
| 2749 LoadRoot(at, Heap::kFixedArrayMapRootIndex); | 3006 LoadRoot(at, Heap::kFixedArrayMapRootIndex); |
| 2750 Branch(&ok, eq, elements, Operand(at)); | 3007 Branch(&ok, eq, elements, Operand(at)); |
| 2751 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); | 3008 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex); |
| 2752 Branch(&ok, eq, elements, Operand(at)); | 3009 Branch(&ok, eq, elements, Operand(at)); |
| 2753 Abort("JSObject with fast elements map has slow elements"); | 3010 Abort("JSObject with fast elements map has slow elements"); |
| 2754 bind(&ok); | 3011 bind(&ok); |
| 2755 Pop(elements); | 3012 pop(elements); |
| 2756 } | 3013 } |
| 2757 } | 3014 } |
| 2758 | 3015 |
| 2759 | 3016 |
| 2760 void MacroAssembler::Check(Condition cc, const char* msg, | 3017 void MacroAssembler::Check(Condition cc, const char* msg, |
| 2761 Register rs, Operand rt) { | 3018 Register rs, Operand rt) { |
| 2762 Label L; | 3019 Label L; |
| 2763 Branch(&L, cc, rs, rt); | 3020 Branch(&L, cc, rs, rt); |
| 2764 Abort(msg); | 3021 Abort(msg); |
| 2765 // will not return here | 3022 // Will not return here. |
| 2766 bind(&L); | 3023 bind(&L); |
| 2767 } | 3024 } |
| 2768 | 3025 |
| 2769 | 3026 |
| 2770 void MacroAssembler::Abort(const char* msg) { | 3027 void MacroAssembler::Abort(const char* msg) { |
| 2771 Label abort_start; | 3028 Label abort_start; |
| 2772 bind(&abort_start); | 3029 bind(&abort_start); |
| 2773 // We want to pass the msg string like a smi to avoid GC | 3030 // We want to pass the msg string like a smi to avoid GC |
| 2774 // problems, however msg is not guaranteed to be aligned | 3031 // problems, however msg is not guaranteed to be aligned |
| 2775 // properly. Instead, we pass an aligned pointer that is | 3032 // properly. Instead, we pass an aligned pointer that is |
| 2776 // a proper v8 smi, but also pass the alignment difference | 3033 // a proper v8 smi, but also pass the alignment difference |
| 2777 // from the real pointer as a smi. | 3034 // from the real pointer as a smi. |
| 2778 intptr_t p1 = reinterpret_cast<intptr_t>(msg); | 3035 intptr_t p1 = reinterpret_cast<intptr_t>(msg); |
| 2779 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; | 3036 intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag; |
| 2780 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); | 3037 ASSERT(reinterpret_cast<Object*>(p0)->IsSmi()); |
| 2781 #ifdef DEBUG | 3038 #ifdef DEBUG |
| 2782 if (msg != NULL) { | 3039 if (msg != NULL) { |
| 2783 RecordComment("Abort message: "); | 3040 RecordComment("Abort message: "); |
| 2784 RecordComment(msg); | 3041 RecordComment(msg); |
| 2785 } | 3042 } |
| 2786 #endif | 3043 #endif |
| 2787 // Disable stub call restrictions to always allow calls to abort. | 3044 // Disable stub call restrictions to always allow calls to abort. |
| 2788 AllowStubCallsScope allow_scope(this, true); | 3045 AllowStubCallsScope allow_scope(this, true); |
| 2789 | 3046 |
| 2790 li(a0, Operand(p0)); | 3047 li(a0, Operand(p0)); |
| 2791 Push(a0); | 3048 push(a0); |
| 2792 li(a0, Operand(Smi::FromInt(p1 - p0))); | 3049 li(a0, Operand(Smi::FromInt(p1 - p0))); |
| 2793 Push(a0); | 3050 push(a0); |
| 2794 CallRuntime(Runtime::kAbort, 2); | 3051 CallRuntime(Runtime::kAbort, 2); |
| 2795 // will not return here | 3052 // Will not return here. |
| 2796 if (is_trampoline_pool_blocked()) { | 3053 if (is_trampoline_pool_blocked()) { |
| 2797 // If the calling code cares about the exact number of | 3054 // If the calling code cares about the exact number of |
| 2798 // instructions generated, we insert padding here to keep the size | 3055 // instructions generated, we insert padding here to keep the size |
| 2799 // of the Abort macro constant. | 3056 // of the Abort macro constant. |
| 2800 // Currently in debug mode with debug_code enabled the number of | 3057 // Currently in debug mode with debug_code enabled the number of |
| 2801 // generated instructions is 14, so we use this as a maximum value. | 3058 // generated instructions is 14, so we use this as a maximum value. |
| 2802 static const int kExpectedAbortInstructions = 14; | 3059 static const int kExpectedAbortInstructions = 14; |
| 2803 int abort_instructions = InstructionsGeneratedSince(&abort_start); | 3060 int abort_instructions = InstructionsGeneratedSince(&abort_start); |
| 2804 ASSERT(abort_instructions <= kExpectedAbortInstructions); | 3061 ASSERT(abort_instructions <= kExpectedAbortInstructions); |
| 2805 while (abort_instructions++ < kExpectedAbortInstructions) { | 3062 while (abort_instructions++ < kExpectedAbortInstructions) { |
| 2806 nop(); | 3063 nop(); |
| 2807 } | 3064 } |
| 2808 } | 3065 } |
| 2809 } | 3066 } |
| 2810 | 3067 |
| 2811 | 3068 |
| 2812 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { | 3069 void MacroAssembler::LoadContext(Register dst, int context_chain_length) { |
| 2813 if (context_chain_length > 0) { | 3070 if (context_chain_length > 0) { |
| 2814 // Move up the chain of contexts to the context containing the slot. | 3071 // Move up the chain of contexts to the context containing the slot. |
| 2815 lw(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX))); | 3072 lw(dst, MemOperand(cp, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 2816 // Load the function context (which is the incoming, outer context). | 3073 // Load the function context (which is the incoming, outer context). |
| 2817 lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); | 3074 lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); |
| 2818 for (int i = 1; i < context_chain_length; i++) { | 3075 for (int i = 1; i < context_chain_length; i++) { |
| 2819 lw(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); | 3076 lw(dst, MemOperand(dst, Context::SlotOffset(Context::CLOSURE_INDEX))); |
| 2820 lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); | 3077 lw(dst, FieldMemOperand(dst, JSFunction::kContextOffset)); |
| 2821 } | 3078 } |
| 2822 // The context may be an intermediate context, not a function context. | 3079 } else { |
| 2823 lw(dst, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 3080 // Slot is in the current function context. Move it into the |
| 2824 } else { // Slot is in the current function context. | 3081 // destination register in case we store into it (the write barrier |
| 2825 // The context may be an intermediate context, not a function context. | 3082 // cannot be allowed to destroy the context in esi). |
| 2826 lw(dst, MemOperand(cp, Context::SlotOffset(Context::FCONTEXT_INDEX))); | 3083 Move(dst, cp); |
| 3084 } |
| 3085 |
| 3086 // We should not have found a 'with' context by walking the context chain |
| 3087 // (i.e., the static scope chain and runtime context chain do not agree). |
| 3088 // A variable occurring in such a scope should have slot type LOOKUP and |
| 3089 // not CONTEXT. |
| 3090 if (emit_debug_code()) { |
| 3091 lw(t9, MemOperand(dst, Context::SlotOffset(Context::FCONTEXT_INDEX))); |
| 3092 Check(eq, "Yo dawg, I heard you liked function contexts " |
| 3093 "so I put function contexts in all your contexts", |
| 3094 dst, Operand(t9)); |
| 2827 } | 3095 } |
| 2828 } | 3096 } |
| 2829 | 3097 |
| 2830 | 3098 |
| 2831 void MacroAssembler::LoadGlobalFunction(int index, Register function) { | 3099 void MacroAssembler::LoadGlobalFunction(int index, Register function) { |
| 2832 // Load the global or builtins object from the current context. | 3100 // Load the global or builtins object from the current context. |
| 2833 lw(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); | 3101 lw(function, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2834 // Load the global context from the global or builtins object. | 3102 // Load the global context from the global or builtins object. |
| 2835 lw(function, FieldMemOperand(function, | 3103 lw(function, FieldMemOperand(function, |
| 2836 GlobalObject::kGlobalContextOffset)); | 3104 GlobalObject::kGlobalContextOffset)); |
| 2837 // Load the function from the global context. | 3105 // Load the function from the global context. |
| 2838 lw(function, MemOperand(function, Context::SlotOffset(index))); | 3106 lw(function, MemOperand(function, Context::SlotOffset(index))); |
| 2839 } | 3107 } |
| 2840 | 3108 |
| 2841 | 3109 |
| 2842 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, | 3110 void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, |
| 2843 Register map, | 3111 Register map, |
| 2844 Register scratch) { | 3112 Register scratch) { |
| 2845 // Load the initial map. The global functions all have initial maps. | 3113 // Load the initial map. The global functions all have initial maps. |
| 2846 lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 3114 lw(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2847 if (FLAG_debug_code) { | 3115 if (emit_debug_code()) { |
| 2848 Label ok, fail; | 3116 Label ok, fail; |
| 2849 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); | 3117 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, false); |
| 2850 Branch(&ok); | 3118 Branch(&ok); |
| 2851 bind(&fail); | 3119 bind(&fail); |
| 2852 Abort("Global functions must have initial map"); | 3120 Abort("Global functions must have initial map"); |
| 2853 bind(&ok); | 3121 bind(&ok); |
| 2854 } | 3122 } |
| 2855 } | 3123 } |
| 2856 | 3124 |
| 2857 | 3125 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2884 sll(t8, a0, kPointerSizeLog2); | 3152 sll(t8, a0, kPointerSizeLog2); |
| 2885 addu(hold_argv, sp, t8); | 3153 addu(hold_argv, sp, t8); |
| 2886 addiu(hold_argv, hold_argv, -kPointerSize); | 3154 addiu(hold_argv, hold_argv, -kPointerSize); |
| 2887 | 3155 |
| 2888 // Compute callee's stack pointer before making changes and save it as | 3156 // Compute callee's stack pointer before making changes and save it as |
| 2889 // t9 register so that it is restored as sp register on exit, thereby | 3157 // t9 register so that it is restored as sp register on exit, thereby |
| 2890 // popping the args. | 3158 // popping the args. |
| 2891 // t9 = sp + kPointerSize * #args | 3159 // t9 = sp + kPointerSize * #args |
| 2892 addu(t9, sp, t8); | 3160 addu(t9, sp, t8); |
| 2893 | 3161 |
| 2894 // Compute the argv pointer and keep it in a callee-saved register. | |
| 2895 // This only seems to be needed for crankshaft and may cause problems | |
| 2896 // so it's disabled for now. | |
| 2897 // Subu(s6, t9, Operand(kPointerSize)); | |
| 2898 | |
| 2899 // Align the stack at this point. | 3162 // Align the stack at this point. |
| 2900 AlignStack(0); | 3163 AlignStack(0); |
| 2901 | 3164 |
| 2902 // Save registers. | 3165 // Save registers. |
| 2903 addiu(sp, sp, -12); | 3166 addiu(sp, sp, -12); |
| 2904 sw(t9, MemOperand(sp, 8)); | 3167 sw(t9, MemOperand(sp, 8)); |
| 2905 sw(ra, MemOperand(sp, 4)); | 3168 sw(ra, MemOperand(sp, 4)); |
| 2906 sw(fp, MemOperand(sp, 0)); | 3169 sw(fp, MemOperand(sp, 0)); |
| 2907 mov(fp, sp); // Setup new frame pointer. | 3170 mov(fp, sp); // Setup new frame pointer. |
| 2908 | 3171 |
| 2909 li(t8, Operand(CodeObject())); | 3172 li(t8, Operand(CodeObject())); |
| 2910 Push(t8); // Accessed from ExitFrame::code_slot. | 3173 push(t8); // Accessed from ExitFrame::code_slot. |
| 2911 | 3174 |
| 2912 // Save the frame pointer and the context in top. | 3175 // Save the frame pointer and the context in top. |
| 2913 li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate()))); | 3176 li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate()))); |
| 2914 sw(fp, MemOperand(t8)); | 3177 sw(fp, MemOperand(t8)); |
| 2915 li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate()))); | 3178 li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate()))); |
| 2916 sw(cp, MemOperand(t8)); | 3179 sw(cp, MemOperand(t8)); |
| 2917 | 3180 |
| 2918 // Setup argc and the builtin function in callee-saved registers. | 3181 // Setup argc and the builtin function in callee-saved registers. |
| 2919 mov(hold_argc, a0); | 3182 mov(hold_argc, a0); |
| 2920 mov(hold_function, a1); | 3183 mov(hold_function, a1); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3085 } | 3348 } |
| 3086 | 3349 |
| 3087 | 3350 |
| 3088 void MacroAssembler::AbortIfNotSmi(Register object) { | 3351 void MacroAssembler::AbortIfNotSmi(Register object) { |
| 3089 STATIC_ASSERT(kSmiTag == 0); | 3352 STATIC_ASSERT(kSmiTag == 0); |
| 3090 andi(at, object, kSmiTagMask); | 3353 andi(at, object, kSmiTagMask); |
| 3091 Assert(eq, "Operand is a smi", at, Operand(zero_reg)); | 3354 Assert(eq, "Operand is a smi", at, Operand(zero_reg)); |
| 3092 } | 3355 } |
| 3093 | 3356 |
| 3094 | 3357 |
| 3358 void MacroAssembler::AbortIfNotString(Register object) { |
| 3359 STATIC_ASSERT(kSmiTag == 0); |
| 3360 And(t0, object, Operand(kSmiTagMask)); |
| 3361 Assert(ne, "Operand is not a string", t0, Operand(zero_reg)); |
| 3362 push(object); |
| 3363 lw(object, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 3364 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset)); |
| 3365 Assert(lo, "Operand is not a string", object, Operand(FIRST_NONSTRING_TYPE)); |
| 3366 pop(object); |
| 3367 } |
| 3368 |
| 3369 |
| 3095 void MacroAssembler::AbortIfNotRootValue(Register src, | 3370 void MacroAssembler::AbortIfNotRootValue(Register src, |
| 3096 Heap::RootListIndex root_value_index, | 3371 Heap::RootListIndex root_value_index, |
| 3097 const char* message) { | 3372 const char* message) { |
| 3098 ASSERT(!src.is(at)); | 3373 ASSERT(!src.is(at)); |
| 3099 LoadRoot(at, root_value_index); | 3374 LoadRoot(at, root_value_index); |
| 3100 Assert(eq, message, src, Operand(at)); | 3375 Assert(eq, message, src, Operand(at)); |
| 3101 } | 3376 } |
| 3102 | 3377 |
| 3103 | 3378 |
| 3104 void MacroAssembler::JumpIfNotHeapNumber(Register object, | 3379 void MacroAssembler::JumpIfNotHeapNumber(Register object, |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3176 And(scratch, type, Operand(kFlatAsciiStringMask)); | 3451 And(scratch, type, Operand(kFlatAsciiStringMask)); |
| 3177 Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag)); | 3452 Branch(failure, ne, scratch, Operand(kFlatAsciiStringTag)); |
| 3178 } | 3453 } |
| 3179 | 3454 |
| 3180 | 3455 |
| 3181 static const int kRegisterPassedArguments = 4; | 3456 static const int kRegisterPassedArguments = 4; |
| 3182 | 3457 |
| 3183 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { | 3458 void MacroAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { |
| 3184 int frame_alignment = ActivationFrameAlignment(); | 3459 int frame_alignment = ActivationFrameAlignment(); |
| 3185 | 3460 |
| 3186 // Reserve space for Isolate address which is always passed as last parameter | |
| 3187 num_arguments += 1; | |
| 3188 | |
| 3189 // Up to four simple arguments are passed in registers a0..a3. | 3461 // Up to four simple arguments are passed in registers a0..a3. |
| 3190 // Those four arguments must have reserved argument slots on the stack for | 3462 // Those four arguments must have reserved argument slots on the stack for |
| 3191 // mips, even though those argument slots are not normally used. | 3463 // mips, even though those argument slots are not normally used. |
| 3192 // Remaining arguments are pushed on the stack, above (higher address than) | 3464 // Remaining arguments are pushed on the stack, above (higher address than) |
| 3193 // the argument slots. | 3465 // the argument slots. |
| 3194 ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); | 3466 ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); |
| 3195 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? | 3467 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? |
| 3196 0 : num_arguments - kRegisterPassedArguments) + | 3468 0 : num_arguments - kRegisterPassedArguments) + |
| 3197 (StandardFrameConstants::kCArgsSlotsSize / | 3469 (StandardFrameConstants::kCArgsSlotsSize / |
| 3198 kPointerSize); | 3470 kPointerSize); |
| 3199 if (frame_alignment > kPointerSize) { | 3471 if (frame_alignment > kPointerSize) { |
| 3200 // Make stack end at alignment and make room for num_arguments - 4 words | 3472 // Make stack end at alignment and make room for num_arguments - 4 words |
| 3201 // and the original value of sp. | 3473 // and the original value of sp. |
| 3202 mov(scratch, sp); | 3474 mov(scratch, sp); |
| 3203 Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); | 3475 Subu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); |
| 3204 ASSERT(IsPowerOf2(frame_alignment)); | 3476 ASSERT(IsPowerOf2(frame_alignment)); |
| 3205 And(sp, sp, Operand(-frame_alignment)); | 3477 And(sp, sp, Operand(-frame_alignment)); |
| 3206 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 3478 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); |
| 3207 } else { | 3479 } else { |
| 3208 Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); | 3480 Subu(sp, sp, Operand(stack_passed_arguments * kPointerSize)); |
| 3209 } | 3481 } |
| 3210 } | 3482 } |
| 3211 | 3483 |
| 3212 | 3484 |
| 3213 void MacroAssembler::CallCFunction(ExternalReference function, | 3485 void MacroAssembler::CallCFunction(ExternalReference function, |
| 3214 int num_arguments) { | 3486 int num_arguments) { |
| 3215 CallCFunctionHelper(no_reg, function, at, num_arguments); | 3487 CallCFunctionHelper(no_reg, function, t8, num_arguments); |
| 3216 } | 3488 } |
| 3217 | 3489 |
| 3218 | 3490 |
| 3219 void MacroAssembler::CallCFunction(Register function, | 3491 void MacroAssembler::CallCFunction(Register function, |
| 3220 Register scratch, | 3492 Register scratch, |
| 3221 int num_arguments) { | 3493 int num_arguments) { |
| 3222 CallCFunctionHelper(function, | 3494 CallCFunctionHelper(function, |
| 3223 ExternalReference::the_hole_value_location(isolate()), | 3495 ExternalReference::the_hole_value_location(isolate()), |
| 3224 scratch, | 3496 scratch, |
| 3225 num_arguments); | 3497 num_arguments); |
| 3226 } | 3498 } |
| 3227 | 3499 |
| 3228 | 3500 |
| 3229 void MacroAssembler::CallCFunctionHelper(Register function, | 3501 void MacroAssembler::CallCFunctionHelper(Register function, |
| 3230 ExternalReference function_reference, | 3502 ExternalReference function_reference, |
| 3231 Register scratch, | 3503 Register scratch, |
| 3232 int num_arguments) { | 3504 int num_arguments) { |
| 3233 // Push Isolate address as the last argument. | |
| 3234 if (num_arguments < kRegisterPassedArguments) { | |
| 3235 Register arg_to_reg[] = {a0, a1, a2, a3}; | |
| 3236 Register r = arg_to_reg[num_arguments]; | |
| 3237 li(r, Operand(ExternalReference::isolate_address())); | |
| 3238 } else { | |
| 3239 int stack_passed_arguments = num_arguments - kRegisterPassedArguments + | |
| 3240 (StandardFrameConstants::kCArgsSlotsSize / | |
| 3241 kPointerSize); | |
| 3242 // Push Isolate address on the stack after the arguments. | |
| 3243 li(scratch, Operand(ExternalReference::isolate_address())); | |
| 3244 sw(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); | |
| 3245 } | |
| 3246 num_arguments += 1; | |
| 3247 | |
| 3248 // Make sure that the stack is aligned before calling a C function unless | 3505 // Make sure that the stack is aligned before calling a C function unless |
| 3249 // running in the simulator. The simulator has its own alignment check which | 3506 // running in the simulator. The simulator has its own alignment check which |
| 3250 // provides more information. | 3507 // provides more information. |
| 3251 // The argument stots are presumed to have been set up by | 3508 // The argument stots are presumed to have been set up by |
| 3252 // PrepareCallCFunction. The C function must be called via t9, for mips ABI. | 3509 // PrepareCallCFunction. The C function must be called via t9, for mips ABI. |
| 3253 | 3510 |
| 3254 #if defined(V8_HOST_ARCH_MIPS) | 3511 #if defined(V8_HOST_ARCH_MIPS) |
| 3255 if (emit_debug_code()) { | 3512 if (emit_debug_code()) { |
| 3256 int frame_alignment = OS::ActivationFrameAlignment(); | 3513 int frame_alignment = OS::ActivationFrameAlignment(); |
| 3257 int frame_alignment_mask = frame_alignment - 1; | 3514 int frame_alignment_mask = frame_alignment - 1; |
| 3258 if (frame_alignment > kPointerSize) { | 3515 if (frame_alignment > kPointerSize) { |
| 3259 ASSERT(IsPowerOf2(frame_alignment)); | 3516 ASSERT(IsPowerOf2(frame_alignment)); |
| 3260 Label alignment_as_expected; | 3517 Label alignment_as_expected; |
| 3261 And(at, sp, Operand(frame_alignment_mask)); | 3518 And(at, sp, Operand(frame_alignment_mask)); |
| 3262 Branch(&alignment_as_expected, eq, at, Operand(zero_reg)); | 3519 Branch(&alignment_as_expected, eq, at, Operand(zero_reg)); |
| 3263 // Don't use Check here, as it will call Runtime_Abort possibly | 3520 // Don't use Check here, as it will call Runtime_Abort possibly |
| 3264 // re-entering here. | 3521 // re-entering here. |
| 3265 stop("Unexpected alignment in CallCFunction"); | 3522 stop("Unexpected alignment in CallCFunction"); |
| 3266 bind(&alignment_as_expected); | 3523 bind(&alignment_as_expected); |
| 3267 } | 3524 } |
| 3268 } | 3525 } |
| 3269 #endif // V8_HOST_ARCH_MIPS | 3526 #endif // V8_HOST_ARCH_MIPS |
| 3270 | 3527 |
| 3271 // Just call directly. The function called cannot cause a GC, or | 3528 // Just call directly. The function called cannot cause a GC, or |
| 3272 // allow preemption, so the return address in the link register | 3529 // allow preemption, so the return address in the link register |
| 3273 // stays correct. | 3530 // stays correct. |
| 3274 if (!function.is(t9)) { | 3531 |
| 3532 if (function.is(no_reg)) { |
| 3533 function = t9; |
| 3534 li(function, Operand(function_reference)); |
| 3535 } else if (!function.is(t9)) { |
| 3275 mov(t9, function); | 3536 mov(t9, function); |
| 3276 function = t9; | 3537 function = t9; |
| 3277 } | 3538 } |
| 3278 | 3539 |
| 3279 if (function.is(no_reg)) { | |
| 3280 li(t9, Operand(function_reference)); | |
| 3281 function = t9; | |
| 3282 } | |
| 3283 | |
| 3284 Call(function); | 3540 Call(function); |
| 3285 | 3541 |
| 3286 ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); | 3542 ASSERT(StandardFrameConstants::kCArgsSlotsSize % kPointerSize == 0); |
| 3287 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? | 3543 int stack_passed_arguments = ((num_arguments <= kRegisterPassedArguments) ? |
| 3288 0 : num_arguments - kRegisterPassedArguments) + | 3544 0 : num_arguments - kRegisterPassedArguments) + |
| 3289 (StandardFrameConstants::kCArgsSlotsSize / | 3545 (StandardFrameConstants::kCArgsSlotsSize / |
| 3290 kPointerSize); | 3546 kPointerSize); |
| 3291 | 3547 |
| 3292 if (OS::ActivationFrameAlignment() > kPointerSize) { | 3548 if (OS::ActivationFrameAlignment() > kPointerSize) { |
| 3293 lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); | 3549 lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); |
| 3294 } else { | 3550 } else { |
| 3295 Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); | 3551 Addu(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); |
| 3296 } | 3552 } |
| 3297 } | 3553 } |
| 3298 | 3554 |
| 3299 | 3555 |
| 3300 #undef BRANCH_ARGS_CHECK | 3556 #undef BRANCH_ARGS_CHECK |
| 3301 | 3557 |
| 3302 | 3558 |
| 3303 #ifdef ENABLE_DEBUGGER_SUPPORT | |
| 3304 CodePatcher::CodePatcher(byte* address, int instructions) | 3559 CodePatcher::CodePatcher(byte* address, int instructions) |
| 3305 : address_(address), | 3560 : address_(address), |
| 3306 instructions_(instructions), | 3561 instructions_(instructions), |
| 3307 size_(instructions * Assembler::kInstrSize), | 3562 size_(instructions * Assembler::kInstrSize), |
| 3308 masm_(address, size_ + Assembler::kGap) { | 3563 masm_(Isolate::Current(), address, size_ + Assembler::kGap) { |
| 3309 // Create a new macro assembler pointing to the address of the code to patch. | 3564 // Create a new macro assembler pointing to the address of the code to patch. |
| 3310 // The size is adjusted with kGap on order for the assembler to generate size | 3565 // The size is adjusted with kGap on order for the assembler to generate size |
| 3311 // bytes of instructions without failing with buffer size constraints. | 3566 // bytes of instructions without failing with buffer size constraints. |
| 3312 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 3567 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 3313 } | 3568 } |
| 3314 | 3569 |
| 3315 | 3570 |
| 3316 CodePatcher::~CodePatcher() { | 3571 CodePatcher::~CodePatcher() { |
| 3317 // Indicate that code has changed. | 3572 // Indicate that code has changed. |
| 3318 CPU::FlushICache(address_, size_); | 3573 CPU::FlushICache(address_, size_); |
| 3319 | 3574 |
| 3320 // Check that the code was patched as expected. | 3575 // Check that the code was patched as expected. |
| 3321 ASSERT(masm_.pc_ == address_ + size_); | 3576 ASSERT(masm_.pc_ == address_ + size_); |
| 3322 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 3577 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
| 3323 } | 3578 } |
| 3324 | 3579 |
| 3325 | 3580 |
| 3326 void CodePatcher::Emit(Instr x) { | 3581 void CodePatcher::Emit(Instr instr) { |
| 3327 masm()->emit(x); | 3582 masm()->emit(instr); |
| 3328 } | 3583 } |
| 3329 | 3584 |
| 3330 | 3585 |
| 3331 void CodePatcher::Emit(Address addr) { | 3586 void CodePatcher::Emit(Address addr) { |
| 3332 masm()->emit(reinterpret_cast<Instr>(addr)); | 3587 masm()->emit(reinterpret_cast<Instr>(addr)); |
| 3333 } | 3588 } |
| 3334 | 3589 |
| 3335 | 3590 |
| 3336 #endif // ENABLE_DEBUGGER_SUPPORT | 3591 void CodePatcher::ChangeBranchCondition(Condition cond) { |
| 3592 Instr instr = Assembler::instr_at(masm_.pc_); |
| 3593 ASSERT(Assembler::IsBranch(instr)); |
| 3594 uint32_t opcode = Assembler::GetOpcodeField(instr); |
| 3595 // Currently only the 'eq' and 'ne' cond values are supported and the simple |
| 3596 // branch instructions (with opcode being the branch type). |
| 3597 // There are some special cases (see Assembler::IsBranch()) so extending this |
| 3598 // would be tricky. |
| 3599 ASSERT(opcode == BEQ || |
| 3600 opcode == BNE || |
| 3601 opcode == BLEZ || |
| 3602 opcode == BGTZ || |
| 3603 opcode == BEQL || |
| 3604 opcode == BNEL || |
| 3605 opcode == BLEZL || |
| 3606 opcode == BGTZL); |
| 3607 opcode = (cond == eq) ? BEQ : BNE; |
| 3608 instr = (instr & ~kOpcodeMask) | opcode; |
| 3609 masm_.emit(instr); |
| 3610 } |
| 3337 | 3611 |
| 3338 | 3612 |
| 3339 } } // namespace v8::internal | 3613 } } // namespace v8::internal |
| 3340 | 3614 |
| 3341 #endif // V8_TARGET_ARCH_MIPS | 3615 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |