| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM64 | 7 #if V8_TARGET_ARCH_ARM64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 | 67 |
| 68 // If the operation is NOT, invert the operation and immediate. | 68 // If the operation is NOT, invert the operation and immediate. |
| 69 if ((op & NOT) == NOT) { | 69 if ((op & NOT) == NOT) { |
| 70 op = static_cast<LogicalOp>(op & ~NOT); | 70 op = static_cast<LogicalOp>(op & ~NOT); |
| 71 immediate = ~immediate; | 71 immediate = ~immediate; |
| 72 } | 72 } |
| 73 | 73 |
| 74 // Ignore the top 32 bits of an immediate if we're moving to a W register. | 74 // Ignore the top 32 bits of an immediate if we're moving to a W register. |
| 75 if (rd.Is32Bits()) { | 75 if (rd.Is32Bits()) { |
| 76 // Check that the top 32 bits are consistent. | 76 // Check that the top 32 bits are consistent. |
| 77 ASSERT(((immediate >> kWRegSizeInBits) == 0) || | 77 DCHECK(((immediate >> kWRegSizeInBits) == 0) || |
| 78 ((immediate >> kWRegSizeInBits) == -1)); | 78 ((immediate >> kWRegSizeInBits) == -1)); |
| 79 immediate &= kWRegMask; | 79 immediate &= kWRegMask; |
| 80 } | 80 } |
| 81 | 81 |
| 82 ASSERT(rd.Is64Bits() || is_uint32(immediate)); | 82 DCHECK(rd.Is64Bits() || is_uint32(immediate)); |
| 83 | 83 |
| 84 // Special cases for all set or all clear immediates. | 84 // Special cases for all set or all clear immediates. |
| 85 if (immediate == 0) { | 85 if (immediate == 0) { |
| 86 switch (op) { | 86 switch (op) { |
| 87 case AND: | 87 case AND: |
| 88 Mov(rd, 0); | 88 Mov(rd, 0); |
| 89 return; | 89 return; |
| 90 case ORR: // Fall through. | 90 case ORR: // Fall through. |
| 91 case EOR: | 91 case EOR: |
| 92 Mov(rd, rn); | 92 Mov(rd, rn); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 // register so we use the temp register as an intermediate again. | 130 // register so we use the temp register as an intermediate again. |
| 131 Logical(temp, rn, imm_operand, op); | 131 Logical(temp, rn, imm_operand, op); |
| 132 Mov(csp, temp); | 132 Mov(csp, temp); |
| 133 AssertStackConsistency(); | 133 AssertStackConsistency(); |
| 134 } else { | 134 } else { |
| 135 Logical(rd, rn, imm_operand, op); | 135 Logical(rd, rn, imm_operand, op); |
| 136 } | 136 } |
| 137 } | 137 } |
| 138 | 138 |
| 139 } else if (operand.IsExtendedRegister()) { | 139 } else if (operand.IsExtendedRegister()) { |
| 140 ASSERT(operand.reg().SizeInBits() <= rd.SizeInBits()); | 140 DCHECK(operand.reg().SizeInBits() <= rd.SizeInBits()); |
| 141 // Add/sub extended supports shift <= 4. We want to support exactly the | 141 // Add/sub extended supports shift <= 4. We want to support exactly the |
| 142 // same modes here. | 142 // same modes here. |
| 143 ASSERT(operand.shift_amount() <= 4); | 143 DCHECK(operand.shift_amount() <= 4); |
| 144 ASSERT(operand.reg().Is64Bits() || | 144 DCHECK(operand.reg().Is64Bits() || |
| 145 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); | 145 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); |
| 146 Register temp = temps.AcquireSameSizeAs(rn); | 146 Register temp = temps.AcquireSameSizeAs(rn); |
| 147 EmitExtendShift(temp, operand.reg(), operand.extend(), | 147 EmitExtendShift(temp, operand.reg(), operand.extend(), |
| 148 operand.shift_amount()); | 148 operand.shift_amount()); |
| 149 Logical(rd, rn, temp, op); | 149 Logical(rd, rn, temp, op); |
| 150 | 150 |
| 151 } else { | 151 } else { |
| 152 // The operand can be encoded in the instruction. | 152 // The operand can be encoded in the instruction. |
| 153 ASSERT(operand.IsShiftedRegister()); | 153 DCHECK(operand.IsShiftedRegister()); |
| 154 Logical(rd, rn, operand, op); | 154 Logical(rd, rn, operand, op); |
| 155 } | 155 } |
| 156 } | 156 } |
| 157 | 157 |
| 158 | 158 |
| 159 void MacroAssembler::Mov(const Register& rd, uint64_t imm) { | 159 void MacroAssembler::Mov(const Register& rd, uint64_t imm) { |
| 160 ASSERT(allow_macro_instructions_); | 160 DCHECK(allow_macro_instructions_); |
| 161 ASSERT(is_uint32(imm) || is_int32(imm) || rd.Is64Bits()); | 161 DCHECK(is_uint32(imm) || is_int32(imm) || rd.Is64Bits()); |
| 162 ASSERT(!rd.IsZero()); | 162 DCHECK(!rd.IsZero()); |
| 163 | 163 |
| 164 // TODO(all) extend to support more immediates. | 164 // TODO(all) extend to support more immediates. |
| 165 // | 165 // |
| 166 // Immediates on Aarch64 can be produced using an initial value, and zero to | 166 // Immediates on Aarch64 can be produced using an initial value, and zero to |
| 167 // three move keep operations. | 167 // three move keep operations. |
| 168 // | 168 // |
| 169 // Initial values can be generated with: | 169 // Initial values can be generated with: |
| 170 // 1. 64-bit move zero (movz). | 170 // 1. 64-bit move zero (movz). |
| 171 // 2. 32-bit move inverted (movn). | 171 // 2. 32-bit move inverted (movn). |
| 172 // 3. 64-bit move inverted. | 172 // 3. 64-bit move inverted. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 198 invert_move = true; | 198 invert_move = true; |
| 199 } | 199 } |
| 200 | 200 |
| 201 // Mov instructions can't move immediate values into the stack pointer, so | 201 // Mov instructions can't move immediate values into the stack pointer, so |
| 202 // set up a temporary register, if needed. | 202 // set up a temporary register, if needed. |
| 203 UseScratchRegisterScope temps(this); | 203 UseScratchRegisterScope temps(this); |
| 204 Register temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd; | 204 Register temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd; |
| 205 | 205 |
| 206 // Iterate through the halfwords. Use movn/movz for the first non-ignored | 206 // Iterate through the halfwords. Use movn/movz for the first non-ignored |
| 207 // halfword, and movk for subsequent halfwords. | 207 // halfword, and movk for subsequent halfwords. |
| 208 ASSERT((reg_size % 16) == 0); | 208 DCHECK((reg_size % 16) == 0); |
| 209 bool first_mov_done = false; | 209 bool first_mov_done = false; |
| 210 for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) { | 210 for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) { |
| 211 uint64_t imm16 = (imm >> (16 * i)) & 0xffffL; | 211 uint64_t imm16 = (imm >> (16 * i)) & 0xffffL; |
| 212 if (imm16 != ignored_halfword) { | 212 if (imm16 != ignored_halfword) { |
| 213 if (!first_mov_done) { | 213 if (!first_mov_done) { |
| 214 if (invert_move) { | 214 if (invert_move) { |
| 215 movn(temp, (~imm16) & 0xffffL, 16 * i); | 215 movn(temp, (~imm16) & 0xffffL, 16 * i); |
| 216 } else { | 216 } else { |
| 217 movz(temp, imm16, 16 * i); | 217 movz(temp, imm16, 16 * i); |
| 218 } | 218 } |
| 219 first_mov_done = true; | 219 first_mov_done = true; |
| 220 } else { | 220 } else { |
| 221 // Construct a wider constant. | 221 // Construct a wider constant. |
| 222 movk(temp, imm16, 16 * i); | 222 movk(temp, imm16, 16 * i); |
| 223 } | 223 } |
| 224 } | 224 } |
| 225 } | 225 } |
| 226 ASSERT(first_mov_done); | 226 DCHECK(first_mov_done); |
| 227 | 227 |
| 228 // Move the temporary if the original destination register was the stack | 228 // Move the temporary if the original destination register was the stack |
| 229 // pointer. | 229 // pointer. |
| 230 if (rd.IsSP()) { | 230 if (rd.IsSP()) { |
| 231 mov(rd, temp); | 231 mov(rd, temp); |
| 232 AssertStackConsistency(); | 232 AssertStackConsistency(); |
| 233 } | 233 } |
| 234 } | 234 } |
| 235 } | 235 } |
| 236 | 236 |
| 237 | 237 |
| 238 void MacroAssembler::Mov(const Register& rd, | 238 void MacroAssembler::Mov(const Register& rd, |
| 239 const Operand& operand, | 239 const Operand& operand, |
| 240 DiscardMoveMode discard_mode) { | 240 DiscardMoveMode discard_mode) { |
| 241 ASSERT(allow_macro_instructions_); | 241 DCHECK(allow_macro_instructions_); |
| 242 ASSERT(!rd.IsZero()); | 242 DCHECK(!rd.IsZero()); |
| 243 | 243 |
| 244 // Provide a swap register for instructions that need to write into the | 244 // Provide a swap register for instructions that need to write into the |
| 245 // system stack pointer (and can't do this inherently). | 245 // system stack pointer (and can't do this inherently). |
| 246 UseScratchRegisterScope temps(this); | 246 UseScratchRegisterScope temps(this); |
| 247 Register dst = (rd.IsSP()) ? temps.AcquireSameSizeAs(rd) : rd; | 247 Register dst = (rd.IsSP()) ? temps.AcquireSameSizeAs(rd) : rd; |
| 248 | 248 |
| 249 if (operand.NeedsRelocation(this)) { | 249 if (operand.NeedsRelocation(this)) { |
| 250 Ldr(dst, operand.immediate()); | 250 Ldr(dst, operand.immediate()); |
| 251 | 251 |
| 252 } else if (operand.IsImmediate()) { | 252 } else if (operand.IsImmediate()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 278 if (!rd.Is(operand.reg()) || (rd.Is32Bits() && | 278 if (!rd.Is(operand.reg()) || (rd.Is32Bits() && |
| 279 (discard_mode == kDontDiscardForSameWReg))) { | 279 (discard_mode == kDontDiscardForSameWReg))) { |
| 280 Assembler::mov(rd, operand.reg()); | 280 Assembler::mov(rd, operand.reg()); |
| 281 } | 281 } |
| 282 // This case can handle writes into the system stack pointer directly. | 282 // This case can handle writes into the system stack pointer directly. |
| 283 dst = rd; | 283 dst = rd; |
| 284 } | 284 } |
| 285 | 285 |
| 286 // Copy the result to the system stack pointer. | 286 // Copy the result to the system stack pointer. |
| 287 if (!dst.Is(rd)) { | 287 if (!dst.Is(rd)) { |
| 288 ASSERT(rd.IsSP()); | 288 DCHECK(rd.IsSP()); |
| 289 Assembler::mov(rd, dst); | 289 Assembler::mov(rd, dst); |
| 290 } | 290 } |
| 291 } | 291 } |
| 292 | 292 |
| 293 | 293 |
| 294 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { | 294 void MacroAssembler::Mvn(const Register& rd, const Operand& operand) { |
| 295 ASSERT(allow_macro_instructions_); | 295 DCHECK(allow_macro_instructions_); |
| 296 | 296 |
| 297 if (operand.NeedsRelocation(this)) { | 297 if (operand.NeedsRelocation(this)) { |
| 298 Ldr(rd, operand.immediate()); | 298 Ldr(rd, operand.immediate()); |
| 299 mvn(rd, rd); | 299 mvn(rd, rd); |
| 300 | 300 |
| 301 } else if (operand.IsImmediate()) { | 301 } else if (operand.IsImmediate()) { |
| 302 // Call the macro assembler for generic immediates. | 302 // Call the macro assembler for generic immediates. |
| 303 Mov(rd, ~operand.ImmediateValue()); | 303 Mov(rd, ~operand.ImmediateValue()); |
| 304 | 304 |
| 305 } else if (operand.IsExtendedRegister()) { | 305 } else if (operand.IsExtendedRegister()) { |
| 306 // Emit two instructions for the extend case. This differs from Mov, as | 306 // Emit two instructions for the extend case. This differs from Mov, as |
| 307 // the extend and invert can't be achieved in one instruction. | 307 // the extend and invert can't be achieved in one instruction. |
| 308 EmitExtendShift(rd, operand.reg(), operand.extend(), | 308 EmitExtendShift(rd, operand.reg(), operand.extend(), |
| 309 operand.shift_amount()); | 309 operand.shift_amount()); |
| 310 mvn(rd, rd); | 310 mvn(rd, rd); |
| 311 | 311 |
| 312 } else { | 312 } else { |
| 313 mvn(rd, operand); | 313 mvn(rd, operand); |
| 314 } | 314 } |
| 315 } | 315 } |
| 316 | 316 |
| 317 | 317 |
| 318 unsigned MacroAssembler::CountClearHalfWords(uint64_t imm, unsigned reg_size) { | 318 unsigned MacroAssembler::CountClearHalfWords(uint64_t imm, unsigned reg_size) { |
| 319 ASSERT((reg_size % 8) == 0); | 319 DCHECK((reg_size % 8) == 0); |
| 320 int count = 0; | 320 int count = 0; |
| 321 for (unsigned i = 0; i < (reg_size / 16); i++) { | 321 for (unsigned i = 0; i < (reg_size / 16); i++) { |
| 322 if ((imm & 0xffff) == 0) { | 322 if ((imm & 0xffff) == 0) { |
| 323 count++; | 323 count++; |
| 324 } | 324 } |
| 325 imm >>= 16; | 325 imm >>= 16; |
| 326 } | 326 } |
| 327 return count; | 327 return count; |
| 328 } | 328 } |
| 329 | 329 |
| 330 | 330 |
| 331 // The movz instruction can generate immediates containing an arbitrary 16-bit | 331 // The movz instruction can generate immediates containing an arbitrary 16-bit |
| 332 // half-word, with remaining bits clear, eg. 0x00001234, 0x0000123400000000. | 332 // half-word, with remaining bits clear, eg. 0x00001234, 0x0000123400000000. |
| 333 bool MacroAssembler::IsImmMovz(uint64_t imm, unsigned reg_size) { | 333 bool MacroAssembler::IsImmMovz(uint64_t imm, unsigned reg_size) { |
| 334 ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits)); | 334 DCHECK((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits)); |
| 335 return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1); | 335 return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1); |
| 336 } | 336 } |
| 337 | 337 |
| 338 | 338 |
| 339 // The movn instruction can generate immediates containing an arbitrary 16-bit | 339 // The movn instruction can generate immediates containing an arbitrary 16-bit |
| 340 // half-word, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff. | 340 // half-word, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff. |
| 341 bool MacroAssembler::IsImmMovn(uint64_t imm, unsigned reg_size) { | 341 bool MacroAssembler::IsImmMovn(uint64_t imm, unsigned reg_size) { |
| 342 return IsImmMovz(~imm, reg_size); | 342 return IsImmMovz(~imm, reg_size); |
| 343 } | 343 } |
| 344 | 344 |
| 345 | 345 |
| 346 void MacroAssembler::ConditionalCompareMacro(const Register& rn, | 346 void MacroAssembler::ConditionalCompareMacro(const Register& rn, |
| 347 const Operand& operand, | 347 const Operand& operand, |
| 348 StatusFlags nzcv, | 348 StatusFlags nzcv, |
| 349 Condition cond, | 349 Condition cond, |
| 350 ConditionalCompareOp op) { | 350 ConditionalCompareOp op) { |
| 351 ASSERT((cond != al) && (cond != nv)); | 351 DCHECK((cond != al) && (cond != nv)); |
| 352 if (operand.NeedsRelocation(this)) { | 352 if (operand.NeedsRelocation(this)) { |
| 353 UseScratchRegisterScope temps(this); | 353 UseScratchRegisterScope temps(this); |
| 354 Register temp = temps.AcquireX(); | 354 Register temp = temps.AcquireX(); |
| 355 Ldr(temp, operand.immediate()); | 355 Ldr(temp, operand.immediate()); |
| 356 ConditionalCompareMacro(rn, temp, nzcv, cond, op); | 356 ConditionalCompareMacro(rn, temp, nzcv, cond, op); |
| 357 | 357 |
| 358 } else if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) || | 358 } else if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) || |
| 359 (operand.IsImmediate() && | 359 (operand.IsImmediate() && |
| 360 IsImmConditionalCompare(operand.ImmediateValue()))) { | 360 IsImmConditionalCompare(operand.ImmediateValue()))) { |
| 361 // The immediate can be encoded in the instruction, or the operand is an | 361 // The immediate can be encoded in the instruction, or the operand is an |
| 362 // unshifted register: call the assembler. | 362 // unshifted register: call the assembler. |
| 363 ConditionalCompare(rn, operand, nzcv, cond, op); | 363 ConditionalCompare(rn, operand, nzcv, cond, op); |
| 364 | 364 |
| 365 } else { | 365 } else { |
| 366 // The operand isn't directly supported by the instruction: perform the | 366 // The operand isn't directly supported by the instruction: perform the |
| 367 // operation on a temporary register. | 367 // operation on a temporary register. |
| 368 UseScratchRegisterScope temps(this); | 368 UseScratchRegisterScope temps(this); |
| 369 Register temp = temps.AcquireSameSizeAs(rn); | 369 Register temp = temps.AcquireSameSizeAs(rn); |
| 370 Mov(temp, operand); | 370 Mov(temp, operand); |
| 371 ConditionalCompare(rn, temp, nzcv, cond, op); | 371 ConditionalCompare(rn, temp, nzcv, cond, op); |
| 372 } | 372 } |
| 373 } | 373 } |
| 374 | 374 |
| 375 | 375 |
| 376 void MacroAssembler::Csel(const Register& rd, | 376 void MacroAssembler::Csel(const Register& rd, |
| 377 const Register& rn, | 377 const Register& rn, |
| 378 const Operand& operand, | 378 const Operand& operand, |
| 379 Condition cond) { | 379 Condition cond) { |
| 380 ASSERT(allow_macro_instructions_); | 380 DCHECK(allow_macro_instructions_); |
| 381 ASSERT(!rd.IsZero()); | 381 DCHECK(!rd.IsZero()); |
| 382 ASSERT((cond != al) && (cond != nv)); | 382 DCHECK((cond != al) && (cond != nv)); |
| 383 if (operand.IsImmediate()) { | 383 if (operand.IsImmediate()) { |
| 384 // Immediate argument. Handle special cases of 0, 1 and -1 using zero | 384 // Immediate argument. Handle special cases of 0, 1 and -1 using zero |
| 385 // register. | 385 // register. |
| 386 int64_t imm = operand.ImmediateValue(); | 386 int64_t imm = operand.ImmediateValue(); |
| 387 Register zr = AppropriateZeroRegFor(rn); | 387 Register zr = AppropriateZeroRegFor(rn); |
| 388 if (imm == 0) { | 388 if (imm == 0) { |
| 389 csel(rd, rn, zr, cond); | 389 csel(rd, rn, zr, cond); |
| 390 } else if (imm == 1) { | 390 } else if (imm == 1) { |
| 391 csinc(rd, rn, zr, cond); | 391 csinc(rd, rn, zr, cond); |
| 392 } else if (imm == -1) { | 392 } else if (imm == -1) { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 AddSub(rd, rn, operand, S, op); | 504 AddSub(rd, rn, operand, S, op); |
| 505 } | 505 } |
| 506 } | 506 } |
| 507 | 507 |
| 508 | 508 |
| 509 void MacroAssembler::AddSubWithCarryMacro(const Register& rd, | 509 void MacroAssembler::AddSubWithCarryMacro(const Register& rd, |
| 510 const Register& rn, | 510 const Register& rn, |
| 511 const Operand& operand, | 511 const Operand& operand, |
| 512 FlagsUpdate S, | 512 FlagsUpdate S, |
| 513 AddSubWithCarryOp op) { | 513 AddSubWithCarryOp op) { |
| 514 ASSERT(rd.SizeInBits() == rn.SizeInBits()); | 514 DCHECK(rd.SizeInBits() == rn.SizeInBits()); |
| 515 UseScratchRegisterScope temps(this); | 515 UseScratchRegisterScope temps(this); |
| 516 | 516 |
| 517 if (operand.NeedsRelocation(this)) { | 517 if (operand.NeedsRelocation(this)) { |
| 518 Register temp = temps.AcquireX(); | 518 Register temp = temps.AcquireX(); |
| 519 Ldr(temp, operand.immediate()); | 519 Ldr(temp, operand.immediate()); |
| 520 AddSubWithCarryMacro(rd, rn, temp, S, op); | 520 AddSubWithCarryMacro(rd, rn, temp, S, op); |
| 521 | 521 |
| 522 } else if (operand.IsImmediate() || | 522 } else if (operand.IsImmediate() || |
| 523 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { | 523 (operand.IsShiftedRegister() && (operand.shift() == ROR))) { |
| 524 // Add/sub with carry (immediate or ROR shifted register.) | 524 // Add/sub with carry (immediate or ROR shifted register.) |
| 525 Register temp = temps.AcquireSameSizeAs(rn); | 525 Register temp = temps.AcquireSameSizeAs(rn); |
| 526 Mov(temp, operand); | 526 Mov(temp, operand); |
| 527 AddSubWithCarry(rd, rn, temp, S, op); | 527 AddSubWithCarry(rd, rn, temp, S, op); |
| 528 | 528 |
| 529 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) { | 529 } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) { |
| 530 // Add/sub with carry (shifted register). | 530 // Add/sub with carry (shifted register). |
| 531 ASSERT(operand.reg().SizeInBits() == rd.SizeInBits()); | 531 DCHECK(operand.reg().SizeInBits() == rd.SizeInBits()); |
| 532 ASSERT(operand.shift() != ROR); | 532 DCHECK(operand.shift() != ROR); |
| 533 ASSERT(is_uintn(operand.shift_amount(), | 533 DCHECK(is_uintn(operand.shift_amount(), |
| 534 rd.SizeInBits() == kXRegSizeInBits ? kXRegSizeInBitsLog2 | 534 rd.SizeInBits() == kXRegSizeInBits ? kXRegSizeInBitsLog2 |
| 535 : kWRegSizeInBitsLog2)); | 535 : kWRegSizeInBitsLog2)); |
| 536 Register temp = temps.AcquireSameSizeAs(rn); | 536 Register temp = temps.AcquireSameSizeAs(rn); |
| 537 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount()); | 537 EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount()); |
| 538 AddSubWithCarry(rd, rn, temp, S, op); | 538 AddSubWithCarry(rd, rn, temp, S, op); |
| 539 | 539 |
| 540 } else if (operand.IsExtendedRegister()) { | 540 } else if (operand.IsExtendedRegister()) { |
| 541 // Add/sub with carry (extended register). | 541 // Add/sub with carry (extended register). |
| 542 ASSERT(operand.reg().SizeInBits() <= rd.SizeInBits()); | 542 DCHECK(operand.reg().SizeInBits() <= rd.SizeInBits()); |
| 543 // Add/sub extended supports a shift <= 4. We want to support exactly the | 543 // Add/sub extended supports a shift <= 4. We want to support exactly the |
| 544 // same modes. | 544 // same modes. |
| 545 ASSERT(operand.shift_amount() <= 4); | 545 DCHECK(operand.shift_amount() <= 4); |
| 546 ASSERT(operand.reg().Is64Bits() || | 546 DCHECK(operand.reg().Is64Bits() || |
| 547 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); | 547 ((operand.extend() != UXTX) && (operand.extend() != SXTX))); |
| 548 Register temp = temps.AcquireSameSizeAs(rn); | 548 Register temp = temps.AcquireSameSizeAs(rn); |
| 549 EmitExtendShift(temp, operand.reg(), operand.extend(), | 549 EmitExtendShift(temp, operand.reg(), operand.extend(), |
| 550 operand.shift_amount()); | 550 operand.shift_amount()); |
| 551 AddSubWithCarry(rd, rn, temp, S, op); | 551 AddSubWithCarry(rd, rn, temp, S, op); |
| 552 | 552 |
| 553 } else { | 553 } else { |
| 554 // The addressing mode is directly supported by the instruction. | 554 // The addressing mode is directly supported by the instruction. |
| 555 AddSubWithCarry(rd, rn, operand, S, op); | 555 AddSubWithCarry(rd, rn, operand, S, op); |
| 556 } | 556 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 585 } else { | 585 } else { |
| 586 // Encodable in one load/store instruction. | 586 // Encodable in one load/store instruction. |
| 587 LoadStore(rt, addr, op); | 587 LoadStore(rt, addr, op); |
| 588 } | 588 } |
| 589 } | 589 } |
| 590 | 590 |
| 591 | 591 |
| 592 void MacroAssembler::Load(const Register& rt, | 592 void MacroAssembler::Load(const Register& rt, |
| 593 const MemOperand& addr, | 593 const MemOperand& addr, |
| 594 Representation r) { | 594 Representation r) { |
| 595 ASSERT(!r.IsDouble()); | 595 DCHECK(!r.IsDouble()); |
| 596 | 596 |
| 597 if (r.IsInteger8()) { | 597 if (r.IsInteger8()) { |
| 598 Ldrsb(rt, addr); | 598 Ldrsb(rt, addr); |
| 599 } else if (r.IsUInteger8()) { | 599 } else if (r.IsUInteger8()) { |
| 600 Ldrb(rt, addr); | 600 Ldrb(rt, addr); |
| 601 } else if (r.IsInteger16()) { | 601 } else if (r.IsInteger16()) { |
| 602 Ldrsh(rt, addr); | 602 Ldrsh(rt, addr); |
| 603 } else if (r.IsUInteger16()) { | 603 } else if (r.IsUInteger16()) { |
| 604 Ldrh(rt, addr); | 604 Ldrh(rt, addr); |
| 605 } else if (r.IsInteger32()) { | 605 } else if (r.IsInteger32()) { |
| 606 Ldr(rt.W(), addr); | 606 Ldr(rt.W(), addr); |
| 607 } else { | 607 } else { |
| 608 ASSERT(rt.Is64Bits()); | 608 DCHECK(rt.Is64Bits()); |
| 609 Ldr(rt, addr); | 609 Ldr(rt, addr); |
| 610 } | 610 } |
| 611 } | 611 } |
| 612 | 612 |
| 613 | 613 |
| 614 void MacroAssembler::Store(const Register& rt, | 614 void MacroAssembler::Store(const Register& rt, |
| 615 const MemOperand& addr, | 615 const MemOperand& addr, |
| 616 Representation r) { | 616 Representation r) { |
| 617 ASSERT(!r.IsDouble()); | 617 DCHECK(!r.IsDouble()); |
| 618 | 618 |
| 619 if (r.IsInteger8() || r.IsUInteger8()) { | 619 if (r.IsInteger8() || r.IsUInteger8()) { |
| 620 Strb(rt, addr); | 620 Strb(rt, addr); |
| 621 } else if (r.IsInteger16() || r.IsUInteger16()) { | 621 } else if (r.IsInteger16() || r.IsUInteger16()) { |
| 622 Strh(rt, addr); | 622 Strh(rt, addr); |
| 623 } else if (r.IsInteger32()) { | 623 } else if (r.IsInteger32()) { |
| 624 Str(rt.W(), addr); | 624 Str(rt.W(), addr); |
| 625 } else { | 625 } else { |
| 626 ASSERT(rt.Is64Bits()); | 626 DCHECK(rt.Is64Bits()); |
| 627 if (r.IsHeapObject()) { | 627 if (r.IsHeapObject()) { |
| 628 AssertNotSmi(rt); | 628 AssertNotSmi(rt); |
| 629 } else if (r.IsSmi()) { | 629 } else if (r.IsSmi()) { |
| 630 AssertSmi(rt); | 630 AssertSmi(rt); |
| 631 } | 631 } |
| 632 Str(rt, addr); | 632 Str(rt, addr); |
| 633 } | 633 } |
| 634 } | 634 } |
| 635 | 635 |
| 636 | 636 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 654 // Also maintain the next pool check. | 654 // Also maintain the next pool check. |
| 655 next_veneer_pool_check_ = | 655 next_veneer_pool_check_ = |
| 656 Min(next_veneer_pool_check_, | 656 Min(next_veneer_pool_check_, |
| 657 max_reachable_pc - kVeneerDistanceCheckMargin); | 657 max_reachable_pc - kVeneerDistanceCheckMargin); |
| 658 } | 658 } |
| 659 return need_longer_range; | 659 return need_longer_range; |
| 660 } | 660 } |
| 661 | 661 |
| 662 | 662 |
| 663 void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) { | 663 void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) { |
| 664 ASSERT(allow_macro_instructions_); | 664 DCHECK(allow_macro_instructions_); |
| 665 ASSERT(!rd.IsZero()); | 665 DCHECK(!rd.IsZero()); |
| 666 | 666 |
| 667 if (hint == kAdrNear) { | 667 if (hint == kAdrNear) { |
| 668 adr(rd, label); | 668 adr(rd, label); |
| 669 return; | 669 return; |
| 670 } | 670 } |
| 671 | 671 |
| 672 ASSERT(hint == kAdrFar); | 672 DCHECK(hint == kAdrFar); |
| 673 if (label->is_bound()) { | 673 if (label->is_bound()) { |
| 674 int label_offset = label->pos() - pc_offset(); | 674 int label_offset = label->pos() - pc_offset(); |
| 675 if (Instruction::IsValidPCRelOffset(label_offset)) { | 675 if (Instruction::IsValidPCRelOffset(label_offset)) { |
| 676 adr(rd, label); | 676 adr(rd, label); |
| 677 } else { | 677 } else { |
| 678 ASSERT(label_offset <= 0); | 678 DCHECK(label_offset <= 0); |
| 679 int min_adr_offset = -(1 << (Instruction::ImmPCRelRangeBitwidth - 1)); | 679 int min_adr_offset = -(1 << (Instruction::ImmPCRelRangeBitwidth - 1)); |
| 680 adr(rd, min_adr_offset); | 680 adr(rd, min_adr_offset); |
| 681 Add(rd, rd, label_offset - min_adr_offset); | 681 Add(rd, rd, label_offset - min_adr_offset); |
| 682 } | 682 } |
| 683 } else { | 683 } else { |
| 684 UseScratchRegisterScope temps(this); | 684 UseScratchRegisterScope temps(this); |
| 685 Register scratch = temps.AcquireX(); | 685 Register scratch = temps.AcquireX(); |
| 686 | 686 |
| 687 InstructionAccurateScope scope( | 687 InstructionAccurateScope scope( |
| 688 this, PatchingAssembler::kAdrFarPatchableNInstrs); | 688 this, PatchingAssembler::kAdrFarPatchableNInstrs); |
| 689 adr(rd, label); | 689 adr(rd, label); |
| 690 for (int i = 0; i < PatchingAssembler::kAdrFarPatchableNNops; ++i) { | 690 for (int i = 0; i < PatchingAssembler::kAdrFarPatchableNNops; ++i) { |
| 691 nop(ADR_FAR_NOP); | 691 nop(ADR_FAR_NOP); |
| 692 } | 692 } |
| 693 movz(scratch, 0); | 693 movz(scratch, 0); |
| 694 } | 694 } |
| 695 } | 695 } |
| 696 | 696 |
| 697 | 697 |
| 698 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) { | 698 void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) { |
| 699 ASSERT((reg.Is(NoReg) || type >= kBranchTypeFirstUsingReg) && | 699 DCHECK((reg.Is(NoReg) || type >= kBranchTypeFirstUsingReg) && |
| 700 (bit == -1 || type >= kBranchTypeFirstUsingBit)); | 700 (bit == -1 || type >= kBranchTypeFirstUsingBit)); |
| 701 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) { | 701 if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) { |
| 702 B(static_cast<Condition>(type), label); | 702 B(static_cast<Condition>(type), label); |
| 703 } else { | 703 } else { |
| 704 switch (type) { | 704 switch (type) { |
| 705 case always: B(label); break; | 705 case always: B(label); break; |
| 706 case never: break; | 706 case never: break; |
| 707 case reg_zero: Cbz(reg, label); break; | 707 case reg_zero: Cbz(reg, label); break; |
| 708 case reg_not_zero: Cbnz(reg, label); break; | 708 case reg_not_zero: Cbnz(reg, label); break; |
| 709 case reg_bit_clear: Tbz(reg, bit, label); break; | 709 case reg_bit_clear: Tbz(reg, bit, label); break; |
| 710 case reg_bit_set: Tbnz(reg, bit, label); break; | 710 case reg_bit_set: Tbnz(reg, bit, label); break; |
| 711 default: | 711 default: |
| 712 UNREACHABLE(); | 712 UNREACHABLE(); |
| 713 } | 713 } |
| 714 } | 714 } |
| 715 } | 715 } |
| 716 | 716 |
| 717 | 717 |
| 718 void MacroAssembler::B(Label* label, Condition cond) { | 718 void MacroAssembler::B(Label* label, Condition cond) { |
| 719 ASSERT(allow_macro_instructions_); | 719 DCHECK(allow_macro_instructions_); |
| 720 ASSERT((cond != al) && (cond != nv)); | 720 DCHECK((cond != al) && (cond != nv)); |
| 721 | 721 |
| 722 Label done; | 722 Label done; |
| 723 bool need_extra_instructions = | 723 bool need_extra_instructions = |
| 724 NeedExtraInstructionsOrRegisterBranch(label, CondBranchType); | 724 NeedExtraInstructionsOrRegisterBranch(label, CondBranchType); |
| 725 | 725 |
| 726 if (need_extra_instructions) { | 726 if (need_extra_instructions) { |
| 727 b(&done, NegateCondition(cond)); | 727 b(&done, NegateCondition(cond)); |
| 728 B(label); | 728 B(label); |
| 729 } else { | 729 } else { |
| 730 b(label, cond); | 730 b(label, cond); |
| 731 } | 731 } |
| 732 bind(&done); | 732 bind(&done); |
| 733 } | 733 } |
| 734 | 734 |
| 735 | 735 |
| 736 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) { | 736 void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) { |
| 737 ASSERT(allow_macro_instructions_); | 737 DCHECK(allow_macro_instructions_); |
| 738 | 738 |
| 739 Label done; | 739 Label done; |
| 740 bool need_extra_instructions = | 740 bool need_extra_instructions = |
| 741 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType); | 741 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType); |
| 742 | 742 |
| 743 if (need_extra_instructions) { | 743 if (need_extra_instructions) { |
| 744 tbz(rt, bit_pos, &done); | 744 tbz(rt, bit_pos, &done); |
| 745 B(label); | 745 B(label); |
| 746 } else { | 746 } else { |
| 747 tbnz(rt, bit_pos, label); | 747 tbnz(rt, bit_pos, label); |
| 748 } | 748 } |
| 749 bind(&done); | 749 bind(&done); |
| 750 } | 750 } |
| 751 | 751 |
| 752 | 752 |
| 753 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) { | 753 void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) { |
| 754 ASSERT(allow_macro_instructions_); | 754 DCHECK(allow_macro_instructions_); |
| 755 | 755 |
| 756 Label done; | 756 Label done; |
| 757 bool need_extra_instructions = | 757 bool need_extra_instructions = |
| 758 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType); | 758 NeedExtraInstructionsOrRegisterBranch(label, TestBranchType); |
| 759 | 759 |
| 760 if (need_extra_instructions) { | 760 if (need_extra_instructions) { |
| 761 tbnz(rt, bit_pos, &done); | 761 tbnz(rt, bit_pos, &done); |
| 762 B(label); | 762 B(label); |
| 763 } else { | 763 } else { |
| 764 tbz(rt, bit_pos, label); | 764 tbz(rt, bit_pos, label); |
| 765 } | 765 } |
| 766 bind(&done); | 766 bind(&done); |
| 767 } | 767 } |
| 768 | 768 |
| 769 | 769 |
| 770 void MacroAssembler::Cbnz(const Register& rt, Label* label) { | 770 void MacroAssembler::Cbnz(const Register& rt, Label* label) { |
| 771 ASSERT(allow_macro_instructions_); | 771 DCHECK(allow_macro_instructions_); |
| 772 | 772 |
| 773 Label done; | 773 Label done; |
| 774 bool need_extra_instructions = | 774 bool need_extra_instructions = |
| 775 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType); | 775 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType); |
| 776 | 776 |
| 777 if (need_extra_instructions) { | 777 if (need_extra_instructions) { |
| 778 cbz(rt, &done); | 778 cbz(rt, &done); |
| 779 B(label); | 779 B(label); |
| 780 } else { | 780 } else { |
| 781 cbnz(rt, label); | 781 cbnz(rt, label); |
| 782 } | 782 } |
| 783 bind(&done); | 783 bind(&done); |
| 784 } | 784 } |
| 785 | 785 |
| 786 | 786 |
| 787 void MacroAssembler::Cbz(const Register& rt, Label* label) { | 787 void MacroAssembler::Cbz(const Register& rt, Label* label) { |
| 788 ASSERT(allow_macro_instructions_); | 788 DCHECK(allow_macro_instructions_); |
| 789 | 789 |
| 790 Label done; | 790 Label done; |
| 791 bool need_extra_instructions = | 791 bool need_extra_instructions = |
| 792 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType); | 792 NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType); |
| 793 | 793 |
| 794 if (need_extra_instructions) { | 794 if (need_extra_instructions) { |
| 795 cbnz(rt, &done); | 795 cbnz(rt, &done); |
| 796 B(label); | 796 B(label); |
| 797 } else { | 797 } else { |
| 798 cbz(rt, label); | 798 cbz(rt, label); |
| 799 } | 799 } |
| 800 bind(&done); | 800 bind(&done); |
| 801 } | 801 } |
| 802 | 802 |
| 803 | 803 |
| 804 // Pseudo-instructions. | 804 // Pseudo-instructions. |
| 805 | 805 |
| 806 | 806 |
| 807 void MacroAssembler::Abs(const Register& rd, const Register& rm, | 807 void MacroAssembler::Abs(const Register& rd, const Register& rm, |
| 808 Label* is_not_representable, | 808 Label* is_not_representable, |
| 809 Label* is_representable) { | 809 Label* is_representable) { |
| 810 ASSERT(allow_macro_instructions_); | 810 DCHECK(allow_macro_instructions_); |
| 811 ASSERT(AreSameSizeAndType(rd, rm)); | 811 DCHECK(AreSameSizeAndType(rd, rm)); |
| 812 | 812 |
| 813 Cmp(rm, 1); | 813 Cmp(rm, 1); |
| 814 Cneg(rd, rm, lt); | 814 Cneg(rd, rm, lt); |
| 815 | 815 |
| 816 // If the comparison sets the v flag, the input was the smallest value | 816 // If the comparison sets the v flag, the input was the smallest value |
| 817 // representable by rm, and the mathematical result of abs(rm) is not | 817 // representable by rm, and the mathematical result of abs(rm) is not |
| 818 // representable using two's complement. | 818 // representable using two's complement. |
| 819 if ((is_not_representable != NULL) && (is_representable != NULL)) { | 819 if ((is_not_representable != NULL) && (is_representable != NULL)) { |
| 820 B(is_not_representable, vs); | 820 B(is_not_representable, vs); |
| 821 B(is_representable); | 821 B(is_representable); |
| 822 } else if (is_not_representable != NULL) { | 822 } else if (is_not_representable != NULL) { |
| 823 B(is_not_representable, vs); | 823 B(is_not_representable, vs); |
| 824 } else if (is_representable != NULL) { | 824 } else if (is_representable != NULL) { |
| 825 B(is_representable, vc); | 825 B(is_representable, vc); |
| 826 } | 826 } |
| 827 } | 827 } |
| 828 | 828 |
| 829 | 829 |
| 830 // Abstracted stack operations. | 830 // Abstracted stack operations. |
| 831 | 831 |
| 832 | 832 |
| 833 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1, | 833 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1, |
| 834 const CPURegister& src2, const CPURegister& src3) { | 834 const CPURegister& src2, const CPURegister& src3) { |
| 835 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); | 835 DCHECK(AreSameSizeAndType(src0, src1, src2, src3)); |
| 836 | 836 |
| 837 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid(); | 837 int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid(); |
| 838 int size = src0.SizeInBytes(); | 838 int size = src0.SizeInBytes(); |
| 839 | 839 |
| 840 PushPreamble(count, size); | 840 PushPreamble(count, size); |
| 841 PushHelper(count, size, src0, src1, src2, src3); | 841 PushHelper(count, size, src0, src1, src2, src3); |
| 842 } | 842 } |
| 843 | 843 |
| 844 | 844 |
| 845 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1, | 845 void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1, |
| 846 const CPURegister& src2, const CPURegister& src3, | 846 const CPURegister& src2, const CPURegister& src3, |
| 847 const CPURegister& src4, const CPURegister& src5, | 847 const CPURegister& src4, const CPURegister& src5, |
| 848 const CPURegister& src6, const CPURegister& src7) { | 848 const CPURegister& src6, const CPURegister& src7) { |
| 849 ASSERT(AreSameSizeAndType(src0, src1, src2, src3, src4, src5, src6, src7)); | 849 DCHECK(AreSameSizeAndType(src0, src1, src2, src3, src4, src5, src6, src7)); |
| 850 | 850 |
| 851 int count = 5 + src5.IsValid() + src6.IsValid() + src6.IsValid(); | 851 int count = 5 + src5.IsValid() + src6.IsValid() + src6.IsValid(); |
| 852 int size = src0.SizeInBytes(); | 852 int size = src0.SizeInBytes(); |
| 853 | 853 |
| 854 PushPreamble(count, size); | 854 PushPreamble(count, size); |
| 855 PushHelper(4, size, src0, src1, src2, src3); | 855 PushHelper(4, size, src0, src1, src2, src3); |
| 856 PushHelper(count - 4, size, src4, src5, src6, src7); | 856 PushHelper(count - 4, size, src4, src5, src6, src7); |
| 857 } | 857 } |
| 858 | 858 |
| 859 | 859 |
| 860 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, | 860 void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1, |
| 861 const CPURegister& dst2, const CPURegister& dst3) { | 861 const CPURegister& dst2, const CPURegister& dst3) { |
| 862 // It is not valid to pop into the same register more than once in one | 862 // It is not valid to pop into the same register more than once in one |
| 863 // instruction, not even into the zero register. | 863 // instruction, not even into the zero register. |
| 864 ASSERT(!AreAliased(dst0, dst1, dst2, dst3)); | 864 DCHECK(!AreAliased(dst0, dst1, dst2, dst3)); |
| 865 ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3)); | 865 DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3)); |
| 866 ASSERT(dst0.IsValid()); | 866 DCHECK(dst0.IsValid()); |
| 867 | 867 |
| 868 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid(); | 868 int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid(); |
| 869 int size = dst0.SizeInBytes(); | 869 int size = dst0.SizeInBytes(); |
| 870 | 870 |
| 871 PopHelper(count, size, dst0, dst1, dst2, dst3); | 871 PopHelper(count, size, dst0, dst1, dst2, dst3); |
| 872 PopPostamble(count, size); | 872 PopPostamble(count, size); |
| 873 } | 873 } |
| 874 | 874 |
| 875 | 875 |
| 876 void MacroAssembler::Push(const Register& src0, const FPRegister& src1) { | 876 void MacroAssembler::Push(const Register& src0, const FPRegister& src1) { |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1001 count -= 4; | 1001 count -= 4; |
| 1002 } | 1002 } |
| 1003 if (count >= 2) { | 1003 if (count >= 2) { |
| 1004 PushHelper(2, size, src, src, NoReg, NoReg); | 1004 PushHelper(2, size, src, src, NoReg, NoReg); |
| 1005 count -= 2; | 1005 count -= 2; |
| 1006 } | 1006 } |
| 1007 if (count == 1) { | 1007 if (count == 1) { |
| 1008 PushHelper(1, size, src, NoReg, NoReg, NoReg); | 1008 PushHelper(1, size, src, NoReg, NoReg, NoReg); |
| 1009 count -= 1; | 1009 count -= 1; |
| 1010 } | 1010 } |
| 1011 ASSERT(count == 0); | 1011 DCHECK(count == 0); |
| 1012 } | 1012 } |
| 1013 | 1013 |
| 1014 | 1014 |
| 1015 void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) { | 1015 void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) { |
| 1016 PushPreamble(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes()))); | 1016 PushPreamble(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes()))); |
| 1017 | 1017 |
| 1018 UseScratchRegisterScope temps(this); | 1018 UseScratchRegisterScope temps(this); |
| 1019 Register temp = temps.AcquireSameSizeAs(count); | 1019 Register temp = temps.AcquireSameSizeAs(count); |
| 1020 | 1020 |
| 1021 if (FLAG_optimize_for_size) { | 1021 if (FLAG_optimize_for_size) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1059 | 1059 |
| 1060 | 1060 |
| 1061 void MacroAssembler::PushHelper(int count, int size, | 1061 void MacroAssembler::PushHelper(int count, int size, |
| 1062 const CPURegister& src0, | 1062 const CPURegister& src0, |
| 1063 const CPURegister& src1, | 1063 const CPURegister& src1, |
| 1064 const CPURegister& src2, | 1064 const CPURegister& src2, |
| 1065 const CPURegister& src3) { | 1065 const CPURegister& src3) { |
| 1066 // Ensure that we don't unintentially modify scratch or debug registers. | 1066 // Ensure that we don't unintentially modify scratch or debug registers. |
| 1067 InstructionAccurateScope scope(this); | 1067 InstructionAccurateScope scope(this); |
| 1068 | 1068 |
| 1069 ASSERT(AreSameSizeAndType(src0, src1, src2, src3)); | 1069 DCHECK(AreSameSizeAndType(src0, src1, src2, src3)); |
| 1070 ASSERT(size == src0.SizeInBytes()); | 1070 DCHECK(size == src0.SizeInBytes()); |
| 1071 | 1071 |
| 1072 // When pushing multiple registers, the store order is chosen such that | 1072 // When pushing multiple registers, the store order is chosen such that |
| 1073 // Push(a, b) is equivalent to Push(a) followed by Push(b). | 1073 // Push(a, b) is equivalent to Push(a) followed by Push(b). |
| 1074 switch (count) { | 1074 switch (count) { |
| 1075 case 1: | 1075 case 1: |
| 1076 ASSERT(src1.IsNone() && src2.IsNone() && src3.IsNone()); | 1076 DCHECK(src1.IsNone() && src2.IsNone() && src3.IsNone()); |
| 1077 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex)); | 1077 str(src0, MemOperand(StackPointer(), -1 * size, PreIndex)); |
| 1078 break; | 1078 break; |
| 1079 case 2: | 1079 case 2: |
| 1080 ASSERT(src2.IsNone() && src3.IsNone()); | 1080 DCHECK(src2.IsNone() && src3.IsNone()); |
| 1081 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex)); | 1081 stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex)); |
| 1082 break; | 1082 break; |
| 1083 case 3: | 1083 case 3: |
| 1084 ASSERT(src3.IsNone()); | 1084 DCHECK(src3.IsNone()); |
| 1085 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex)); | 1085 stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex)); |
| 1086 str(src0, MemOperand(StackPointer(), 2 * size)); | 1086 str(src0, MemOperand(StackPointer(), 2 * size)); |
| 1087 break; | 1087 break; |
| 1088 case 4: | 1088 case 4: |
| 1089 // Skip over 4 * size, then fill in the gap. This allows four W registers | 1089 // Skip over 4 * size, then fill in the gap. This allows four W registers |
| 1090 // to be pushed using csp, whilst maintaining 16-byte alignment for csp | 1090 // to be pushed using csp, whilst maintaining 16-byte alignment for csp |
| 1091 // at all times. | 1091 // at all times. |
| 1092 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex)); | 1092 stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex)); |
| 1093 stp(src1, src0, MemOperand(StackPointer(), 2 * size)); | 1093 stp(src1, src0, MemOperand(StackPointer(), 2 * size)); |
| 1094 break; | 1094 break; |
| 1095 default: | 1095 default: |
| 1096 UNREACHABLE(); | 1096 UNREACHABLE(); |
| 1097 } | 1097 } |
| 1098 } | 1098 } |
| 1099 | 1099 |
| 1100 | 1100 |
| 1101 void MacroAssembler::PopHelper(int count, int size, | 1101 void MacroAssembler::PopHelper(int count, int size, |
| 1102 const CPURegister& dst0, | 1102 const CPURegister& dst0, |
| 1103 const CPURegister& dst1, | 1103 const CPURegister& dst1, |
| 1104 const CPURegister& dst2, | 1104 const CPURegister& dst2, |
| 1105 const CPURegister& dst3) { | 1105 const CPURegister& dst3) { |
| 1106 // Ensure that we don't unintentially modify scratch or debug registers. | 1106 // Ensure that we don't unintentially modify scratch or debug registers. |
| 1107 InstructionAccurateScope scope(this); | 1107 InstructionAccurateScope scope(this); |
| 1108 | 1108 |
| 1109 ASSERT(AreSameSizeAndType(dst0, dst1, dst2, dst3)); | 1109 DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3)); |
| 1110 ASSERT(size == dst0.SizeInBytes()); | 1110 DCHECK(size == dst0.SizeInBytes()); |
| 1111 | 1111 |
| 1112 // When popping multiple registers, the load order is chosen such that | 1112 // When popping multiple registers, the load order is chosen such that |
| 1113 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b). | 1113 // Pop(a, b) is equivalent to Pop(a) followed by Pop(b). |
| 1114 switch (count) { | 1114 switch (count) { |
| 1115 case 1: | 1115 case 1: |
| 1116 ASSERT(dst1.IsNone() && dst2.IsNone() && dst3.IsNone()); | 1116 DCHECK(dst1.IsNone() && dst2.IsNone() && dst3.IsNone()); |
| 1117 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex)); | 1117 ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex)); |
| 1118 break; | 1118 break; |
| 1119 case 2: | 1119 case 2: |
| 1120 ASSERT(dst2.IsNone() && dst3.IsNone()); | 1120 DCHECK(dst2.IsNone() && dst3.IsNone()); |
| 1121 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex)); | 1121 ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex)); |
| 1122 break; | 1122 break; |
| 1123 case 3: | 1123 case 3: |
| 1124 ASSERT(dst3.IsNone()); | 1124 DCHECK(dst3.IsNone()); |
| 1125 ldr(dst2, MemOperand(StackPointer(), 2 * size)); | 1125 ldr(dst2, MemOperand(StackPointer(), 2 * size)); |
| 1126 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex)); | 1126 ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex)); |
| 1127 break; | 1127 break; |
| 1128 case 4: | 1128 case 4: |
| 1129 // Load the higher addresses first, then load the lower addresses and | 1129 // Load the higher addresses first, then load the lower addresses and |
| 1130 // skip the whole block in the second instruction. This allows four W | 1130 // skip the whole block in the second instruction. This allows four W |
| 1131 // registers to be popped using csp, whilst maintaining 16-byte alignment | 1131 // registers to be popped using csp, whilst maintaining 16-byte alignment |
| 1132 // for csp at all times. | 1132 // for csp at all times. |
| 1133 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); | 1133 ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size)); |
| 1134 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); | 1134 ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex)); |
| 1135 break; | 1135 break; |
| 1136 default: | 1136 default: |
| 1137 UNREACHABLE(); | 1137 UNREACHABLE(); |
| 1138 } | 1138 } |
| 1139 } | 1139 } |
| 1140 | 1140 |
| 1141 | 1141 |
| 1142 void MacroAssembler::PushPreamble(Operand total_size) { | 1142 void MacroAssembler::PushPreamble(Operand total_size) { |
| 1143 if (csp.Is(StackPointer())) { | 1143 if (csp.Is(StackPointer())) { |
| 1144 // If the current stack pointer is csp, then it must be aligned to 16 bytes | 1144 // If the current stack pointer is csp, then it must be aligned to 16 bytes |
| 1145 // on entry and the total size of the specified registers must also be a | 1145 // on entry and the total size of the specified registers must also be a |
| 1146 // multiple of 16 bytes. | 1146 // multiple of 16 bytes. |
| 1147 if (total_size.IsImmediate()) { | 1147 if (total_size.IsImmediate()) { |
| 1148 ASSERT((total_size.ImmediateValue() % 16) == 0); | 1148 DCHECK((total_size.ImmediateValue() % 16) == 0); |
| 1149 } | 1149 } |
| 1150 | 1150 |
| 1151 // Don't check access size for non-immediate sizes. It's difficult to do | 1151 // Don't check access size for non-immediate sizes. It's difficult to do |
| 1152 // well, and it will be caught by hardware (or the simulator) anyway. | 1152 // well, and it will be caught by hardware (or the simulator) anyway. |
| 1153 } else { | 1153 } else { |
| 1154 // Even if the current stack pointer is not the system stack pointer (csp), | 1154 // Even if the current stack pointer is not the system stack pointer (csp), |
| 1155 // the system stack pointer will still be modified in order to comply with | 1155 // the system stack pointer will still be modified in order to comply with |
| 1156 // ABI rules about accessing memory below the system stack pointer. | 1156 // ABI rules about accessing memory below the system stack pointer. |
| 1157 BumpSystemStackPointer(total_size); | 1157 BumpSystemStackPointer(total_size); |
| 1158 } | 1158 } |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 | 1161 |
| 1162 void MacroAssembler::PopPostamble(Operand total_size) { | 1162 void MacroAssembler::PopPostamble(Operand total_size) { |
| 1163 if (csp.Is(StackPointer())) { | 1163 if (csp.Is(StackPointer())) { |
| 1164 // If the current stack pointer is csp, then it must be aligned to 16 bytes | 1164 // If the current stack pointer is csp, then it must be aligned to 16 bytes |
| 1165 // on entry and the total size of the specified registers must also be a | 1165 // on entry and the total size of the specified registers must also be a |
| 1166 // multiple of 16 bytes. | 1166 // multiple of 16 bytes. |
| 1167 if (total_size.IsImmediate()) { | 1167 if (total_size.IsImmediate()) { |
| 1168 ASSERT((total_size.ImmediateValue() % 16) == 0); | 1168 DCHECK((total_size.ImmediateValue() % 16) == 0); |
| 1169 } | 1169 } |
| 1170 | 1170 |
| 1171 // Don't check access size for non-immediate sizes. It's difficult to do | 1171 // Don't check access size for non-immediate sizes. It's difficult to do |
| 1172 // well, and it will be caught by hardware (or the simulator) anyway. | 1172 // well, and it will be caught by hardware (or the simulator) anyway. |
| 1173 } else if (emit_debug_code()) { | 1173 } else if (emit_debug_code()) { |
| 1174 // It is safe to leave csp where it is when unwinding the JavaScript stack, | 1174 // It is safe to leave csp where it is when unwinding the JavaScript stack, |
| 1175 // but if we keep it matching StackPointer, the simulator can detect memory | 1175 // but if we keep it matching StackPointer, the simulator can detect memory |
| 1176 // accesses in the now-free part of the stack. | 1176 // accesses in the now-free part of the stack. |
| 1177 SyncSystemStackPointer(); | 1177 SyncSystemStackPointer(); |
| 1178 } | 1178 } |
| 1179 } | 1179 } |
| 1180 | 1180 |
| 1181 | 1181 |
| 1182 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { | 1182 void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) { |
| 1183 if (offset.IsImmediate()) { | 1183 if (offset.IsImmediate()) { |
| 1184 ASSERT(offset.ImmediateValue() >= 0); | 1184 DCHECK(offset.ImmediateValue() >= 0); |
| 1185 } else if (emit_debug_code()) { | 1185 } else if (emit_debug_code()) { |
| 1186 Cmp(xzr, offset); | 1186 Cmp(xzr, offset); |
| 1187 Check(le, kStackAccessBelowStackPointer); | 1187 Check(le, kStackAccessBelowStackPointer); |
| 1188 } | 1188 } |
| 1189 | 1189 |
| 1190 Str(src, MemOperand(StackPointer(), offset)); | 1190 Str(src, MemOperand(StackPointer(), offset)); |
| 1191 } | 1191 } |
| 1192 | 1192 |
| 1193 | 1193 |
| 1194 void MacroAssembler::Peek(const CPURegister& dst, const Operand& offset) { | 1194 void MacroAssembler::Peek(const CPURegister& dst, const Operand& offset) { |
| 1195 if (offset.IsImmediate()) { | 1195 if (offset.IsImmediate()) { |
| 1196 ASSERT(offset.ImmediateValue() >= 0); | 1196 DCHECK(offset.ImmediateValue() >= 0); |
| 1197 } else if (emit_debug_code()) { | 1197 } else if (emit_debug_code()) { |
| 1198 Cmp(xzr, offset); | 1198 Cmp(xzr, offset); |
| 1199 Check(le, kStackAccessBelowStackPointer); | 1199 Check(le, kStackAccessBelowStackPointer); |
| 1200 } | 1200 } |
| 1201 | 1201 |
| 1202 Ldr(dst, MemOperand(StackPointer(), offset)); | 1202 Ldr(dst, MemOperand(StackPointer(), offset)); |
| 1203 } | 1203 } |
| 1204 | 1204 |
| 1205 | 1205 |
| 1206 void MacroAssembler::PokePair(const CPURegister& src1, | 1206 void MacroAssembler::PokePair(const CPURegister& src1, |
| 1207 const CPURegister& src2, | 1207 const CPURegister& src2, |
| 1208 int offset) { | 1208 int offset) { |
| 1209 ASSERT(AreSameSizeAndType(src1, src2)); | 1209 DCHECK(AreSameSizeAndType(src1, src2)); |
| 1210 ASSERT((offset >= 0) && ((offset % src1.SizeInBytes()) == 0)); | 1210 DCHECK((offset >= 0) && ((offset % src1.SizeInBytes()) == 0)); |
| 1211 Stp(src1, src2, MemOperand(StackPointer(), offset)); | 1211 Stp(src1, src2, MemOperand(StackPointer(), offset)); |
| 1212 } | 1212 } |
| 1213 | 1213 |
| 1214 | 1214 |
| 1215 void MacroAssembler::PeekPair(const CPURegister& dst1, | 1215 void MacroAssembler::PeekPair(const CPURegister& dst1, |
| 1216 const CPURegister& dst2, | 1216 const CPURegister& dst2, |
| 1217 int offset) { | 1217 int offset) { |
| 1218 ASSERT(AreSameSizeAndType(dst1, dst2)); | 1218 DCHECK(AreSameSizeAndType(dst1, dst2)); |
| 1219 ASSERT((offset >= 0) && ((offset % dst1.SizeInBytes()) == 0)); | 1219 DCHECK((offset >= 0) && ((offset % dst1.SizeInBytes()) == 0)); |
| 1220 Ldp(dst1, dst2, MemOperand(StackPointer(), offset)); | 1220 Ldp(dst1, dst2, MemOperand(StackPointer(), offset)); |
| 1221 } | 1221 } |
| 1222 | 1222 |
| 1223 | 1223 |
| 1224 void MacroAssembler::PushCalleeSavedRegisters() { | 1224 void MacroAssembler::PushCalleeSavedRegisters() { |
| 1225 // Ensure that the macro-assembler doesn't use any scratch registers. | 1225 // Ensure that the macro-assembler doesn't use any scratch registers. |
| 1226 InstructionAccurateScope scope(this); | 1226 InstructionAccurateScope scope(this); |
| 1227 | 1227 |
| 1228 // This method must not be called unless the current stack pointer is the | 1228 // This method must not be called unless the current stack pointer is the |
| 1229 // system stack pointer (csp). | 1229 // system stack pointer (csp). |
| 1230 ASSERT(csp.Is(StackPointer())); | 1230 DCHECK(csp.Is(StackPointer())); |
| 1231 | 1231 |
| 1232 MemOperand tos(csp, -2 * kXRegSize, PreIndex); | 1232 MemOperand tos(csp, -2 * kXRegSize, PreIndex); |
| 1233 | 1233 |
| 1234 stp(d14, d15, tos); | 1234 stp(d14, d15, tos); |
| 1235 stp(d12, d13, tos); | 1235 stp(d12, d13, tos); |
| 1236 stp(d10, d11, tos); | 1236 stp(d10, d11, tos); |
| 1237 stp(d8, d9, tos); | 1237 stp(d8, d9, tos); |
| 1238 | 1238 |
| 1239 stp(x29, x30, tos); | 1239 stp(x29, x30, tos); |
| 1240 stp(x27, x28, tos); // x28 = jssp | 1240 stp(x27, x28, tos); // x28 = jssp |
| 1241 stp(x25, x26, tos); | 1241 stp(x25, x26, tos); |
| 1242 stp(x23, x24, tos); | 1242 stp(x23, x24, tos); |
| 1243 stp(x21, x22, tos); | 1243 stp(x21, x22, tos); |
| 1244 stp(x19, x20, tos); | 1244 stp(x19, x20, tos); |
| 1245 } | 1245 } |
| 1246 | 1246 |
| 1247 | 1247 |
| 1248 void MacroAssembler::PopCalleeSavedRegisters() { | 1248 void MacroAssembler::PopCalleeSavedRegisters() { |
| 1249 // Ensure that the macro-assembler doesn't use any scratch registers. | 1249 // Ensure that the macro-assembler doesn't use any scratch registers. |
| 1250 InstructionAccurateScope scope(this); | 1250 InstructionAccurateScope scope(this); |
| 1251 | 1251 |
| 1252 // This method must not be called unless the current stack pointer is the | 1252 // This method must not be called unless the current stack pointer is the |
| 1253 // system stack pointer (csp). | 1253 // system stack pointer (csp). |
| 1254 ASSERT(csp.Is(StackPointer())); | 1254 DCHECK(csp.Is(StackPointer())); |
| 1255 | 1255 |
| 1256 MemOperand tos(csp, 2 * kXRegSize, PostIndex); | 1256 MemOperand tos(csp, 2 * kXRegSize, PostIndex); |
| 1257 | 1257 |
| 1258 ldp(x19, x20, tos); | 1258 ldp(x19, x20, tos); |
| 1259 ldp(x21, x22, tos); | 1259 ldp(x21, x22, tos); |
| 1260 ldp(x23, x24, tos); | 1260 ldp(x23, x24, tos); |
| 1261 ldp(x25, x26, tos); | 1261 ldp(x25, x26, tos); |
| 1262 ldp(x27, x28, tos); // x28 = jssp | 1262 ldp(x27, x28, tos); // x28 = jssp |
| 1263 ldp(x29, x30, tos); | 1263 ldp(x29, x30, tos); |
| 1264 | 1264 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1418 } | 1418 } |
| 1419 | 1419 |
| 1420 | 1420 |
| 1421 void MacroAssembler::CheckEnumCache(Register object, | 1421 void MacroAssembler::CheckEnumCache(Register object, |
| 1422 Register null_value, | 1422 Register null_value, |
| 1423 Register scratch0, | 1423 Register scratch0, |
| 1424 Register scratch1, | 1424 Register scratch1, |
| 1425 Register scratch2, | 1425 Register scratch2, |
| 1426 Register scratch3, | 1426 Register scratch3, |
| 1427 Label* call_runtime) { | 1427 Label* call_runtime) { |
| 1428 ASSERT(!AreAliased(object, null_value, scratch0, scratch1, scratch2, | 1428 DCHECK(!AreAliased(object, null_value, scratch0, scratch1, scratch2, |
| 1429 scratch3)); | 1429 scratch3)); |
| 1430 | 1430 |
| 1431 Register empty_fixed_array_value = scratch0; | 1431 Register empty_fixed_array_value = scratch0; |
| 1432 Register current_object = scratch1; | 1432 Register current_object = scratch1; |
| 1433 | 1433 |
| 1434 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); | 1434 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
| 1435 Label next, start; | 1435 Label next, start; |
| 1436 | 1436 |
| 1437 Mov(current_object, object); | 1437 Mov(current_object, object); |
| 1438 | 1438 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1500 Operand(isolate()->factory()->allocation_memento_map())); | 1500 Operand(isolate()->factory()->allocation_memento_map())); |
| 1501 } | 1501 } |
| 1502 | 1502 |
| 1503 | 1503 |
| 1504 void MacroAssembler::JumpToHandlerEntry(Register exception, | 1504 void MacroAssembler::JumpToHandlerEntry(Register exception, |
| 1505 Register object, | 1505 Register object, |
| 1506 Register state, | 1506 Register state, |
| 1507 Register scratch1, | 1507 Register scratch1, |
| 1508 Register scratch2) { | 1508 Register scratch2) { |
| 1509 // Handler expects argument in x0. | 1509 // Handler expects argument in x0. |
| 1510 ASSERT(exception.Is(x0)); | 1510 DCHECK(exception.Is(x0)); |
| 1511 | 1511 |
| 1512 // Compute the handler entry address and jump to it. The handler table is | 1512 // Compute the handler entry address and jump to it. The handler table is |
| 1513 // a fixed array of (smi-tagged) code offsets. | 1513 // a fixed array of (smi-tagged) code offsets. |
| 1514 Ldr(scratch1, FieldMemOperand(object, Code::kHandlerTableOffset)); | 1514 Ldr(scratch1, FieldMemOperand(object, Code::kHandlerTableOffset)); |
| 1515 Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag); | 1515 Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag); |
| 1516 STATIC_ASSERT(StackHandler::kKindWidth < kPointerSizeLog2); | 1516 STATIC_ASSERT(StackHandler::kKindWidth < kPointerSizeLog2); |
| 1517 Lsr(scratch2, state, StackHandler::kKindWidth); | 1517 Lsr(scratch2, state, StackHandler::kKindWidth); |
| 1518 Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2)); | 1518 Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2)); |
| 1519 Add(scratch1, object, Code::kHeaderSize - kHeapObjectTag); | 1519 Add(scratch1, object, Code::kHeaderSize - kHeapObjectTag); |
| 1520 Add(scratch1, scratch1, Operand::UntagSmi(scratch2)); | 1520 Add(scratch1, scratch1, Operand::UntagSmi(scratch2)); |
| 1521 Br(scratch1); | 1521 Br(scratch1); |
| 1522 } | 1522 } |
| 1523 | 1523 |
| 1524 | 1524 |
| 1525 void MacroAssembler::InNewSpace(Register object, | 1525 void MacroAssembler::InNewSpace(Register object, |
| 1526 Condition cond, | 1526 Condition cond, |
| 1527 Label* branch) { | 1527 Label* branch) { |
| 1528 ASSERT(cond == eq || cond == ne); | 1528 DCHECK(cond == eq || cond == ne); |
| 1529 UseScratchRegisterScope temps(this); | 1529 UseScratchRegisterScope temps(this); |
| 1530 Register temp = temps.AcquireX(); | 1530 Register temp = temps.AcquireX(); |
| 1531 And(temp, object, ExternalReference::new_space_mask(isolate())); | 1531 And(temp, object, ExternalReference::new_space_mask(isolate())); |
| 1532 Cmp(temp, ExternalReference::new_space_start(isolate())); | 1532 Cmp(temp, ExternalReference::new_space_start(isolate())); |
| 1533 B(cond, branch); | 1533 B(cond, branch); |
| 1534 } | 1534 } |
| 1535 | 1535 |
| 1536 | 1536 |
| 1537 void MacroAssembler::Throw(Register value, | 1537 void MacroAssembler::Throw(Register value, |
| 1538 Register scratch1, | 1538 Register scratch1, |
| 1539 Register scratch2, | 1539 Register scratch2, |
| 1540 Register scratch3, | 1540 Register scratch3, |
| 1541 Register scratch4) { | 1541 Register scratch4) { |
| 1542 // Adjust this code if not the case. | 1542 // Adjust this code if not the case. |
| 1543 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 1543 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
| 1544 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 1544 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 1545 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 1545 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
| 1546 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 1546 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
| 1547 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 1547 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
| 1548 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 1548 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
| 1549 | 1549 |
| 1550 // The handler expects the exception in x0. | 1550 // The handler expects the exception in x0. |
| 1551 ASSERT(value.Is(x0)); | 1551 DCHECK(value.Is(x0)); |
| 1552 | 1552 |
| 1553 // Drop the stack pointer to the top of the top handler. | 1553 // Drop the stack pointer to the top of the top handler. |
| 1554 ASSERT(jssp.Is(StackPointer())); | 1554 DCHECK(jssp.Is(StackPointer())); |
| 1555 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress, | 1555 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress, |
| 1556 isolate()))); | 1556 isolate()))); |
| 1557 Ldr(jssp, MemOperand(scratch1)); | 1557 Ldr(jssp, MemOperand(scratch1)); |
| 1558 // Restore the next handler. | 1558 // Restore the next handler. |
| 1559 Pop(scratch2); | 1559 Pop(scratch2); |
| 1560 Str(scratch2, MemOperand(scratch1)); | 1560 Str(scratch2, MemOperand(scratch1)); |
| 1561 | 1561 |
| 1562 // Get the code object and state. Restore the context and frame pointer. | 1562 // Get the code object and state. Restore the context and frame pointer. |
| 1563 Register object = scratch1; | 1563 Register object = scratch1; |
| 1564 Register state = scratch2; | 1564 Register state = scratch2; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1583 Register scratch4) { | 1583 Register scratch4) { |
| 1584 // Adjust this code if not the case. | 1584 // Adjust this code if not the case. |
| 1585 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 1585 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
| 1586 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 1586 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); |
| 1587 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 1587 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
| 1588 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 1588 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
| 1589 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 1589 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
| 1590 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 1590 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
| 1591 | 1591 |
| 1592 // The handler expects the exception in x0. | 1592 // The handler expects the exception in x0. |
| 1593 ASSERT(value.Is(x0)); | 1593 DCHECK(value.Is(x0)); |
| 1594 | 1594 |
| 1595 // Drop the stack pointer to the top of the top stack handler. | 1595 // Drop the stack pointer to the top of the top stack handler. |
| 1596 ASSERT(jssp.Is(StackPointer())); | 1596 DCHECK(jssp.Is(StackPointer())); |
| 1597 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress, | 1597 Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress, |
| 1598 isolate()))); | 1598 isolate()))); |
| 1599 Ldr(jssp, MemOperand(scratch1)); | 1599 Ldr(jssp, MemOperand(scratch1)); |
| 1600 | 1600 |
| 1601 // Unwind the handlers until the ENTRY handler is found. | 1601 // Unwind the handlers until the ENTRY handler is found. |
| 1602 Label fetch_next, check_kind; | 1602 Label fetch_next, check_kind; |
| 1603 B(&check_kind); | 1603 B(&check_kind); |
| 1604 Bind(&fetch_next); | 1604 Bind(&fetch_next); |
| 1605 Peek(jssp, StackHandlerConstants::kNextOffset); | 1605 Peek(jssp, StackHandlerConstants::kNextOffset); |
| 1606 | 1606 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1617 // saved in the handler). | 1617 // saved in the handler). |
| 1618 Register object = scratch1; | 1618 Register object = scratch1; |
| 1619 Register state = scratch2; | 1619 Register state = scratch2; |
| 1620 Pop(object, state, cp, fp); | 1620 Pop(object, state, cp, fp); |
| 1621 | 1621 |
| 1622 JumpToHandlerEntry(value, object, state, scratch3, scratch4); | 1622 JumpToHandlerEntry(value, object, state, scratch3, scratch4); |
| 1623 } | 1623 } |
| 1624 | 1624 |
| 1625 | 1625 |
| 1626 void MacroAssembler::SmiAbs(const Register& smi, Label* slow) { | 1626 void MacroAssembler::SmiAbs(const Register& smi, Label* slow) { |
| 1627 ASSERT(smi.Is64Bits()); | 1627 DCHECK(smi.Is64Bits()); |
| 1628 Abs(smi, smi, slow); | 1628 Abs(smi, smi, slow); |
| 1629 } | 1629 } |
| 1630 | 1630 |
| 1631 | 1631 |
| 1632 void MacroAssembler::AssertSmi(Register object, BailoutReason reason) { | 1632 void MacroAssembler::AssertSmi(Register object, BailoutReason reason) { |
| 1633 if (emit_debug_code()) { | 1633 if (emit_debug_code()) { |
| 1634 STATIC_ASSERT(kSmiTag == 0); | 1634 STATIC_ASSERT(kSmiTag == 0); |
| 1635 Tst(object, kSmiTagMask); | 1635 Tst(object, kSmiTagMask); |
| 1636 Check(eq, reason); | 1636 Check(eq, reason); |
| 1637 } | 1637 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1683 Tst(object, kSmiTagMask); | 1683 Tst(object, kSmiTagMask); |
| 1684 Check(ne, kOperandIsASmiAndNotAString); | 1684 Check(ne, kOperandIsASmiAndNotAString); |
| 1685 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); | 1685 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 1686 CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE); | 1686 CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE); |
| 1687 Check(lo, kOperandIsNotAString); | 1687 Check(lo, kOperandIsNotAString); |
| 1688 } | 1688 } |
| 1689 } | 1689 } |
| 1690 | 1690 |
| 1691 | 1691 |
| 1692 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { | 1692 void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) { |
| 1693 ASSERT(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. | 1693 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs. |
| 1694 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); | 1694 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id); |
| 1695 } | 1695 } |
| 1696 | 1696 |
| 1697 | 1697 |
| 1698 void MacroAssembler::TailCallStub(CodeStub* stub) { | 1698 void MacroAssembler::TailCallStub(CodeStub* stub) { |
| 1699 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); | 1699 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); |
| 1700 } | 1700 } |
| 1701 | 1701 |
| 1702 | 1702 |
| 1703 void MacroAssembler::CallRuntime(const Runtime::Function* f, | 1703 void MacroAssembler::CallRuntime(const Runtime::Function* f, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1735 ExternalReference next_address = | 1735 ExternalReference next_address = |
| 1736 ExternalReference::handle_scope_next_address(isolate()); | 1736 ExternalReference::handle_scope_next_address(isolate()); |
| 1737 const int kNextOffset = 0; | 1737 const int kNextOffset = 0; |
| 1738 const int kLimitOffset = AddressOffset( | 1738 const int kLimitOffset = AddressOffset( |
| 1739 ExternalReference::handle_scope_limit_address(isolate()), | 1739 ExternalReference::handle_scope_limit_address(isolate()), |
| 1740 next_address); | 1740 next_address); |
| 1741 const int kLevelOffset = AddressOffset( | 1741 const int kLevelOffset = AddressOffset( |
| 1742 ExternalReference::handle_scope_level_address(isolate()), | 1742 ExternalReference::handle_scope_level_address(isolate()), |
| 1743 next_address); | 1743 next_address); |
| 1744 | 1744 |
| 1745 ASSERT(function_address.is(x1) || function_address.is(x2)); | 1745 DCHECK(function_address.is(x1) || function_address.is(x2)); |
| 1746 | 1746 |
| 1747 Label profiler_disabled; | 1747 Label profiler_disabled; |
| 1748 Label end_profiler_check; | 1748 Label end_profiler_check; |
| 1749 Mov(x10, ExternalReference::is_profiling_address(isolate())); | 1749 Mov(x10, ExternalReference::is_profiling_address(isolate())); |
| 1750 Ldrb(w10, MemOperand(x10)); | 1750 Ldrb(w10, MemOperand(x10)); |
| 1751 Cbz(w10, &profiler_disabled); | 1751 Cbz(w10, &profiler_disabled); |
| 1752 Mov(x3, thunk_ref); | 1752 Mov(x3, thunk_ref); |
| 1753 B(&end_profiler_check); | 1753 B(&end_profiler_check); |
| 1754 | 1754 |
| 1755 Bind(&profiler_disabled); | 1755 Bind(&profiler_disabled); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1893 Ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset)); | 1893 Ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset)); |
| 1894 // Load the JavaScript builtin function from the builtins object. | 1894 // Load the JavaScript builtin function from the builtins object. |
| 1895 Ldr(target, FieldMemOperand(target, | 1895 Ldr(target, FieldMemOperand(target, |
| 1896 JSBuiltinsObject::OffsetOfFunctionWithId(id))); | 1896 JSBuiltinsObject::OffsetOfFunctionWithId(id))); |
| 1897 } | 1897 } |
| 1898 | 1898 |
| 1899 | 1899 |
| 1900 void MacroAssembler::GetBuiltinEntry(Register target, | 1900 void MacroAssembler::GetBuiltinEntry(Register target, |
| 1901 Register function, | 1901 Register function, |
| 1902 Builtins::JavaScript id) { | 1902 Builtins::JavaScript id) { |
| 1903 ASSERT(!AreAliased(target, function)); | 1903 DCHECK(!AreAliased(target, function)); |
| 1904 GetBuiltinFunction(function, id); | 1904 GetBuiltinFunction(function, id); |
| 1905 // Load the code entry point from the builtins object. | 1905 // Load the code entry point from the builtins object. |
| 1906 Ldr(target, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 1906 Ldr(target, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 1907 } | 1907 } |
| 1908 | 1908 |
| 1909 | 1909 |
| 1910 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, | 1910 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, |
| 1911 InvokeFlag flag, | 1911 InvokeFlag flag, |
| 1912 const CallWrapper& call_wrapper) { | 1912 const CallWrapper& call_wrapper) { |
| 1913 ASM_LOCATION("MacroAssembler::InvokeBuiltin"); | 1913 ASM_LOCATION("MacroAssembler::InvokeBuiltin"); |
| 1914 // You can't call a builtin without a valid frame. | 1914 // You can't call a builtin without a valid frame. |
| 1915 ASSERT(flag == JUMP_FUNCTION || has_frame()); | 1915 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 1916 | 1916 |
| 1917 // Get the builtin entry in x2 and setup the function object in x1. | 1917 // Get the builtin entry in x2 and setup the function object in x1. |
| 1918 GetBuiltinEntry(x2, x1, id); | 1918 GetBuiltinEntry(x2, x1, id); |
| 1919 if (flag == CALL_FUNCTION) { | 1919 if (flag == CALL_FUNCTION) { |
| 1920 call_wrapper.BeforeCall(CallSize(x2)); | 1920 call_wrapper.BeforeCall(CallSize(x2)); |
| 1921 Call(x2); | 1921 Call(x2); |
| 1922 call_wrapper.AfterCall(); | 1922 call_wrapper.AfterCall(); |
| 1923 } else { | 1923 } else { |
| 1924 ASSERT(flag == JUMP_FUNCTION); | 1924 DCHECK(flag == JUMP_FUNCTION); |
| 1925 Jump(x2); | 1925 Jump(x2); |
| 1926 } | 1926 } |
| 1927 } | 1927 } |
| 1928 | 1928 |
| 1929 | 1929 |
| 1930 void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, | 1930 void MacroAssembler::TailCallExternalReference(const ExternalReference& ext, |
| 1931 int num_arguments, | 1931 int num_arguments, |
| 1932 int result_size) { | 1932 int result_size) { |
| 1933 // TODO(1236192): Most runtime routines don't need the number of | 1933 // TODO(1236192): Most runtime routines don't need the number of |
| 1934 // arguments passed in because it is constant. At some point we | 1934 // arguments passed in because it is constant. At some point we |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1946 num_arguments, | 1946 num_arguments, |
| 1947 result_size); | 1947 result_size); |
| 1948 } | 1948 } |
| 1949 | 1949 |
| 1950 | 1950 |
| 1951 void MacroAssembler::InitializeNewString(Register string, | 1951 void MacroAssembler::InitializeNewString(Register string, |
| 1952 Register length, | 1952 Register length, |
| 1953 Heap::RootListIndex map_index, | 1953 Heap::RootListIndex map_index, |
| 1954 Register scratch1, | 1954 Register scratch1, |
| 1955 Register scratch2) { | 1955 Register scratch2) { |
| 1956 ASSERT(!AreAliased(string, length, scratch1, scratch2)); | 1956 DCHECK(!AreAliased(string, length, scratch1, scratch2)); |
| 1957 LoadRoot(scratch2, map_index); | 1957 LoadRoot(scratch2, map_index); |
| 1958 SmiTag(scratch1, length); | 1958 SmiTag(scratch1, length); |
| 1959 Str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset)); | 1959 Str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 1960 | 1960 |
| 1961 Mov(scratch2, String::kEmptyHashField); | 1961 Mov(scratch2, String::kEmptyHashField); |
| 1962 Str(scratch1, FieldMemOperand(string, String::kLengthOffset)); | 1962 Str(scratch1, FieldMemOperand(string, String::kLengthOffset)); |
| 1963 Str(scratch2, FieldMemOperand(string, String::kHashFieldOffset)); | 1963 Str(scratch2, FieldMemOperand(string, String::kHashFieldOffset)); |
| 1964 } | 1964 } |
| 1965 | 1965 |
| 1966 | 1966 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1993 UseScratchRegisterScope temps(this); | 1993 UseScratchRegisterScope temps(this); |
| 1994 Register temp = temps.AcquireX(); | 1994 Register temp = temps.AcquireX(); |
| 1995 Mov(temp, function); | 1995 Mov(temp, function); |
| 1996 CallCFunction(temp, num_of_reg_args, num_of_double_args); | 1996 CallCFunction(temp, num_of_reg_args, num_of_double_args); |
| 1997 } | 1997 } |
| 1998 | 1998 |
| 1999 | 1999 |
| 2000 void MacroAssembler::CallCFunction(Register function, | 2000 void MacroAssembler::CallCFunction(Register function, |
| 2001 int num_of_reg_args, | 2001 int num_of_reg_args, |
| 2002 int num_of_double_args) { | 2002 int num_of_double_args) { |
| 2003 ASSERT(has_frame()); | 2003 DCHECK(has_frame()); |
| 2004 // We can pass 8 integer arguments in registers. If we need to pass more than | 2004 // We can pass 8 integer arguments in registers. If we need to pass more than |
| 2005 // that, we'll need to implement support for passing them on the stack. | 2005 // that, we'll need to implement support for passing them on the stack. |
| 2006 ASSERT(num_of_reg_args <= 8); | 2006 DCHECK(num_of_reg_args <= 8); |
| 2007 | 2007 |
| 2008 // If we're passing doubles, we're limited to the following prototypes | 2008 // If we're passing doubles, we're limited to the following prototypes |
| 2009 // (defined by ExternalReference::Type): | 2009 // (defined by ExternalReference::Type): |
| 2010 // BUILTIN_COMPARE_CALL: int f(double, double) | 2010 // BUILTIN_COMPARE_CALL: int f(double, double) |
| 2011 // BUILTIN_FP_FP_CALL: double f(double, double) | 2011 // BUILTIN_FP_FP_CALL: double f(double, double) |
| 2012 // BUILTIN_FP_CALL: double f(double) | 2012 // BUILTIN_FP_CALL: double f(double) |
| 2013 // BUILTIN_FP_INT_CALL: double f(double, int) | 2013 // BUILTIN_FP_INT_CALL: double f(double, int) |
| 2014 if (num_of_double_args > 0) { | 2014 if (num_of_double_args > 0) { |
| 2015 ASSERT(num_of_reg_args <= 1); | 2015 DCHECK(num_of_reg_args <= 1); |
| 2016 ASSERT((num_of_double_args + num_of_reg_args) <= 2); | 2016 DCHECK((num_of_double_args + num_of_reg_args) <= 2); |
| 2017 } | 2017 } |
| 2018 | 2018 |
| 2019 | 2019 |
| 2020 // If the stack pointer is not csp, we need to derive an aligned csp from the | 2020 // If the stack pointer is not csp, we need to derive an aligned csp from the |
| 2021 // current stack pointer. | 2021 // current stack pointer. |
| 2022 const Register old_stack_pointer = StackPointer(); | 2022 const Register old_stack_pointer = StackPointer(); |
| 2023 if (!csp.Is(old_stack_pointer)) { | 2023 if (!csp.Is(old_stack_pointer)) { |
| 2024 AssertStackConsistency(); | 2024 AssertStackConsistency(); |
| 2025 | 2025 |
| 2026 int sp_alignment = ActivationFrameAlignment(); | 2026 int sp_alignment = ActivationFrameAlignment(); |
| 2027 // The ABI mandates at least 16-byte alignment. | 2027 // The ABI mandates at least 16-byte alignment. |
| 2028 ASSERT(sp_alignment >= 16); | 2028 DCHECK(sp_alignment >= 16); |
| 2029 ASSERT(IsPowerOf2(sp_alignment)); | 2029 DCHECK(IsPowerOf2(sp_alignment)); |
| 2030 | 2030 |
| 2031 // The current stack pointer is a callee saved register, and is preserved | 2031 // The current stack pointer is a callee saved register, and is preserved |
| 2032 // across the call. | 2032 // across the call. |
| 2033 ASSERT(kCalleeSaved.IncludesAliasOf(old_stack_pointer)); | 2033 DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer)); |
| 2034 | 2034 |
| 2035 // Align and synchronize the system stack pointer with jssp. | 2035 // Align and synchronize the system stack pointer with jssp. |
| 2036 Bic(csp, old_stack_pointer, sp_alignment - 1); | 2036 Bic(csp, old_stack_pointer, sp_alignment - 1); |
| 2037 SetStackPointer(csp); | 2037 SetStackPointer(csp); |
| 2038 } | 2038 } |
| 2039 | 2039 |
| 2040 // Call directly. The function called cannot cause a GC, or allow preemption, | 2040 // Call directly. The function called cannot cause a GC, or allow preemption, |
| 2041 // so the return address in the link register stays correct. | 2041 // so the return address in the link register stays correct. |
| 2042 Call(function); | 2042 Call(function); |
| 2043 | 2043 |
| 2044 if (!csp.Is(old_stack_pointer)) { | 2044 if (!csp.Is(old_stack_pointer)) { |
| 2045 if (emit_debug_code()) { | 2045 if (emit_debug_code()) { |
| 2046 // Because the stack pointer must be aligned on a 16-byte boundary, the | 2046 // Because the stack pointer must be aligned on a 16-byte boundary, the |
| 2047 // aligned csp can be up to 12 bytes below the jssp. This is the case | 2047 // aligned csp can be up to 12 bytes below the jssp. This is the case |
| 2048 // where we only pushed one W register on top of an aligned jssp. | 2048 // where we only pushed one W register on top of an aligned jssp. |
| 2049 UseScratchRegisterScope temps(this); | 2049 UseScratchRegisterScope temps(this); |
| 2050 Register temp = temps.AcquireX(); | 2050 Register temp = temps.AcquireX(); |
| 2051 ASSERT(ActivationFrameAlignment() == 16); | 2051 DCHECK(ActivationFrameAlignment() == 16); |
| 2052 Sub(temp, csp, old_stack_pointer); | 2052 Sub(temp, csp, old_stack_pointer); |
| 2053 // We want temp <= 0 && temp >= -12. | 2053 // We want temp <= 0 && temp >= -12. |
| 2054 Cmp(temp, 0); | 2054 Cmp(temp, 0); |
| 2055 Ccmp(temp, -12, NFlag, le); | 2055 Ccmp(temp, -12, NFlag, le); |
| 2056 Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); | 2056 Check(ge, kTheStackWasCorruptedByMacroAssemblerCall); |
| 2057 } | 2057 } |
| 2058 SetStackPointer(old_stack_pointer); | 2058 SetStackPointer(old_stack_pointer); |
| 2059 } | 2059 } |
| 2060 } | 2060 } |
| 2061 | 2061 |
| 2062 | 2062 |
| 2063 void MacroAssembler::Jump(Register target) { | 2063 void MacroAssembler::Jump(Register target) { |
| 2064 Br(target); | 2064 Br(target); |
| 2065 } | 2065 } |
| 2066 | 2066 |
| 2067 | 2067 |
| 2068 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode) { | 2068 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode) { |
| 2069 UseScratchRegisterScope temps(this); | 2069 UseScratchRegisterScope temps(this); |
| 2070 Register temp = temps.AcquireX(); | 2070 Register temp = temps.AcquireX(); |
| 2071 Mov(temp, Operand(target, rmode)); | 2071 Mov(temp, Operand(target, rmode)); |
| 2072 Br(temp); | 2072 Br(temp); |
| 2073 } | 2073 } |
| 2074 | 2074 |
| 2075 | 2075 |
| 2076 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode) { | 2076 void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode) { |
| 2077 ASSERT(!RelocInfo::IsCodeTarget(rmode)); | 2077 DCHECK(!RelocInfo::IsCodeTarget(rmode)); |
| 2078 Jump(reinterpret_cast<intptr_t>(target), rmode); | 2078 Jump(reinterpret_cast<intptr_t>(target), rmode); |
| 2079 } | 2079 } |
| 2080 | 2080 |
| 2081 | 2081 |
| 2082 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode) { | 2082 void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode) { |
| 2083 ASSERT(RelocInfo::IsCodeTarget(rmode)); | 2083 DCHECK(RelocInfo::IsCodeTarget(rmode)); |
| 2084 AllowDeferredHandleDereference embedding_raw_address; | 2084 AllowDeferredHandleDereference embedding_raw_address; |
| 2085 Jump(reinterpret_cast<intptr_t>(code.location()), rmode); | 2085 Jump(reinterpret_cast<intptr_t>(code.location()), rmode); |
| 2086 } | 2086 } |
| 2087 | 2087 |
| 2088 | 2088 |
| 2089 void MacroAssembler::Call(Register target) { | 2089 void MacroAssembler::Call(Register target) { |
| 2090 BlockPoolsScope scope(this); | 2090 BlockPoolsScope scope(this); |
| 2091 #ifdef DEBUG | 2091 #ifdef DEBUG |
| 2092 Label start_call; | 2092 Label start_call; |
| 2093 Bind(&start_call); | 2093 Bind(&start_call); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2122 BlockPoolsScope scope(this); | 2122 BlockPoolsScope scope(this); |
| 2123 #ifdef DEBUG | 2123 #ifdef DEBUG |
| 2124 Label start_call; | 2124 Label start_call; |
| 2125 Bind(&start_call); | 2125 Bind(&start_call); |
| 2126 #endif | 2126 #endif |
| 2127 // Statement positions are expected to be recorded when the target | 2127 // Statement positions are expected to be recorded when the target |
| 2128 // address is loaded. | 2128 // address is loaded. |
| 2129 positions_recorder()->WriteRecordedPositions(); | 2129 positions_recorder()->WriteRecordedPositions(); |
| 2130 | 2130 |
| 2131 // Addresses always have 64 bits, so we shouldn't encounter NONE32. | 2131 // Addresses always have 64 bits, so we shouldn't encounter NONE32. |
| 2132 ASSERT(rmode != RelocInfo::NONE32); | 2132 DCHECK(rmode != RelocInfo::NONE32); |
| 2133 | 2133 |
| 2134 UseScratchRegisterScope temps(this); | 2134 UseScratchRegisterScope temps(this); |
| 2135 Register temp = temps.AcquireX(); | 2135 Register temp = temps.AcquireX(); |
| 2136 | 2136 |
| 2137 if (rmode == RelocInfo::NONE64) { | 2137 if (rmode == RelocInfo::NONE64) { |
| 2138 // Addresses are 48 bits so we never need to load the upper 16 bits. | 2138 // Addresses are 48 bits so we never need to load the upper 16 bits. |
| 2139 uint64_t imm = reinterpret_cast<uint64_t>(target); | 2139 uint64_t imm = reinterpret_cast<uint64_t>(target); |
| 2140 // If we don't use ARM tagged addresses, the 16 higher bits must be 0. | 2140 // If we don't use ARM tagged addresses, the 16 higher bits must be 0. |
| 2141 ASSERT(((imm >> 48) & 0xffff) == 0); | 2141 DCHECK(((imm >> 48) & 0xffff) == 0); |
| 2142 movz(temp, (imm >> 0) & 0xffff, 0); | 2142 movz(temp, (imm >> 0) & 0xffff, 0); |
| 2143 movk(temp, (imm >> 16) & 0xffff, 16); | 2143 movk(temp, (imm >> 16) & 0xffff, 16); |
| 2144 movk(temp, (imm >> 32) & 0xffff, 32); | 2144 movk(temp, (imm >> 32) & 0xffff, 32); |
| 2145 } else { | 2145 } else { |
| 2146 Ldr(temp, Immediate(reinterpret_cast<intptr_t>(target), rmode)); | 2146 Ldr(temp, Immediate(reinterpret_cast<intptr_t>(target), rmode)); |
| 2147 } | 2147 } |
| 2148 Blr(temp); | 2148 Blr(temp); |
| 2149 #ifdef DEBUG | 2149 #ifdef DEBUG |
| 2150 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target, rmode)); | 2150 AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target, rmode)); |
| 2151 #endif | 2151 #endif |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2184 int MacroAssembler::CallSize(Label* target) { | 2184 int MacroAssembler::CallSize(Label* target) { |
| 2185 USE(target); | 2185 USE(target); |
| 2186 return kInstructionSize; | 2186 return kInstructionSize; |
| 2187 } | 2187 } |
| 2188 | 2188 |
| 2189 | 2189 |
| 2190 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode) { | 2190 int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode) { |
| 2191 USE(target); | 2191 USE(target); |
| 2192 | 2192 |
| 2193 // Addresses always have 64 bits, so we shouldn't encounter NONE32. | 2193 // Addresses always have 64 bits, so we shouldn't encounter NONE32. |
| 2194 ASSERT(rmode != RelocInfo::NONE32); | 2194 DCHECK(rmode != RelocInfo::NONE32); |
| 2195 | 2195 |
| 2196 if (rmode == RelocInfo::NONE64) { | 2196 if (rmode == RelocInfo::NONE64) { |
| 2197 return kCallSizeWithoutRelocation; | 2197 return kCallSizeWithoutRelocation; |
| 2198 } else { | 2198 } else { |
| 2199 return kCallSizeWithRelocation; | 2199 return kCallSizeWithRelocation; |
| 2200 } | 2200 } |
| 2201 } | 2201 } |
| 2202 | 2202 |
| 2203 | 2203 |
| 2204 int MacroAssembler::CallSize(Handle<Code> code, | 2204 int MacroAssembler::CallSize(Handle<Code> code, |
| 2205 RelocInfo::Mode rmode, | 2205 RelocInfo::Mode rmode, |
| 2206 TypeFeedbackId ast_id) { | 2206 TypeFeedbackId ast_id) { |
| 2207 USE(code); | 2207 USE(code); |
| 2208 USE(ast_id); | 2208 USE(ast_id); |
| 2209 | 2209 |
| 2210 // Addresses always have 64 bits, so we shouldn't encounter NONE32. | 2210 // Addresses always have 64 bits, so we shouldn't encounter NONE32. |
| 2211 ASSERT(rmode != RelocInfo::NONE32); | 2211 DCHECK(rmode != RelocInfo::NONE32); |
| 2212 | 2212 |
| 2213 if (rmode == RelocInfo::NONE64) { | 2213 if (rmode == RelocInfo::NONE64) { |
| 2214 return kCallSizeWithoutRelocation; | 2214 return kCallSizeWithoutRelocation; |
| 2215 } else { | 2215 } else { |
| 2216 return kCallSizeWithRelocation; | 2216 return kCallSizeWithRelocation; |
| 2217 } | 2217 } |
| 2218 } | 2218 } |
| 2219 | 2219 |
| 2220 | 2220 |
| 2221 | 2221 |
| 2222 | 2222 |
| 2223 | 2223 |
| 2224 void MacroAssembler::JumpForHeapNumber(Register object, | 2224 void MacroAssembler::JumpForHeapNumber(Register object, |
| 2225 Register heap_number_map, | 2225 Register heap_number_map, |
| 2226 Label* on_heap_number, | 2226 Label* on_heap_number, |
| 2227 Label* on_not_heap_number) { | 2227 Label* on_not_heap_number) { |
| 2228 ASSERT(on_heap_number || on_not_heap_number); | 2228 DCHECK(on_heap_number || on_not_heap_number); |
| 2229 AssertNotSmi(object); | 2229 AssertNotSmi(object); |
| 2230 | 2230 |
| 2231 UseScratchRegisterScope temps(this); | 2231 UseScratchRegisterScope temps(this); |
| 2232 Register temp = temps.AcquireX(); | 2232 Register temp = temps.AcquireX(); |
| 2233 | 2233 |
| 2234 // Load the HeapNumber map if it is not passed. | 2234 // Load the HeapNumber map if it is not passed. |
| 2235 if (heap_number_map.Is(NoReg)) { | 2235 if (heap_number_map.Is(NoReg)) { |
| 2236 heap_number_map = temps.AcquireX(); | 2236 heap_number_map = temps.AcquireX(); |
| 2237 LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2237 LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 2238 } else { | 2238 } else { |
| 2239 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2239 AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
| 2240 } | 2240 } |
| 2241 | 2241 |
| 2242 ASSERT(!AreAliased(temp, heap_number_map)); | 2242 DCHECK(!AreAliased(temp, heap_number_map)); |
| 2243 | 2243 |
| 2244 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); | 2244 Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset)); |
| 2245 Cmp(temp, heap_number_map); | 2245 Cmp(temp, heap_number_map); |
| 2246 | 2246 |
| 2247 if (on_heap_number) { | 2247 if (on_heap_number) { |
| 2248 B(eq, on_heap_number); | 2248 B(eq, on_heap_number); |
| 2249 } | 2249 } |
| 2250 if (on_not_heap_number) { | 2250 if (on_not_heap_number) { |
| 2251 B(ne, on_not_heap_number); | 2251 B(ne, on_not_heap_number); |
| 2252 } | 2252 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2272 on_not_heap_number); | 2272 on_not_heap_number); |
| 2273 } | 2273 } |
| 2274 | 2274 |
| 2275 | 2275 |
| 2276 void MacroAssembler::LookupNumberStringCache(Register object, | 2276 void MacroAssembler::LookupNumberStringCache(Register object, |
| 2277 Register result, | 2277 Register result, |
| 2278 Register scratch1, | 2278 Register scratch1, |
| 2279 Register scratch2, | 2279 Register scratch2, |
| 2280 Register scratch3, | 2280 Register scratch3, |
| 2281 Label* not_found) { | 2281 Label* not_found) { |
| 2282 ASSERT(!AreAliased(object, result, scratch1, scratch2, scratch3)); | 2282 DCHECK(!AreAliased(object, result, scratch1, scratch2, scratch3)); |
| 2283 | 2283 |
| 2284 // Use of registers. Register result is used as a temporary. | 2284 // Use of registers. Register result is used as a temporary. |
| 2285 Register number_string_cache = result; | 2285 Register number_string_cache = result; |
| 2286 Register mask = scratch3; | 2286 Register mask = scratch3; |
| 2287 | 2287 |
| 2288 // Load the number string cache. | 2288 // Load the number string cache. |
| 2289 LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); | 2289 LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); |
| 2290 | 2290 |
| 2291 // Make the hash mask from the length of the number string cache. It | 2291 // Make the hash mask from the length of the number string cache. It |
| 2292 // contains two elements (number and string) for each cache entry. | 2292 // contains two elements (number and string) for each cache entry. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2378 | 2378 |
| 2379 void MacroAssembler::JumpIfMinusZero(DoubleRegister input, | 2379 void MacroAssembler::JumpIfMinusZero(DoubleRegister input, |
| 2380 Label* on_negative_zero) { | 2380 Label* on_negative_zero) { |
| 2381 TestForMinusZero(input); | 2381 TestForMinusZero(input); |
| 2382 B(vs, on_negative_zero); | 2382 B(vs, on_negative_zero); |
| 2383 } | 2383 } |
| 2384 | 2384 |
| 2385 | 2385 |
| 2386 void MacroAssembler::JumpIfMinusZero(Register input, | 2386 void MacroAssembler::JumpIfMinusZero(Register input, |
| 2387 Label* on_negative_zero) { | 2387 Label* on_negative_zero) { |
| 2388 ASSERT(input.Is64Bits()); | 2388 DCHECK(input.Is64Bits()); |
| 2389 // Floating point value is in an integer register. Detect -0.0 by subtracting | 2389 // Floating point value is in an integer register. Detect -0.0 by subtracting |
| 2390 // 1 (cmp), which will cause overflow. | 2390 // 1 (cmp), which will cause overflow. |
| 2391 Cmp(input, 1); | 2391 Cmp(input, 1); |
| 2392 B(vs, on_negative_zero); | 2392 B(vs, on_negative_zero); |
| 2393 } | 2393 } |
| 2394 | 2394 |
| 2395 | 2395 |
| 2396 void MacroAssembler::ClampInt32ToUint8(Register output, Register input) { | 2396 void MacroAssembler::ClampInt32ToUint8(Register output, Register input) { |
| 2397 // Clamp the value to [0..255]. | 2397 // Clamp the value to [0..255]. |
| 2398 Cmp(input.W(), Operand(input.W(), UXTB)); | 2398 Cmp(input.W(), Operand(input.W(), UXTB)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2431 void MacroAssembler::CopyFieldsLoopPairsHelper(Register dst, | 2431 void MacroAssembler::CopyFieldsLoopPairsHelper(Register dst, |
| 2432 Register src, | 2432 Register src, |
| 2433 unsigned count, | 2433 unsigned count, |
| 2434 Register scratch1, | 2434 Register scratch1, |
| 2435 Register scratch2, | 2435 Register scratch2, |
| 2436 Register scratch3, | 2436 Register scratch3, |
| 2437 Register scratch4, | 2437 Register scratch4, |
| 2438 Register scratch5) { | 2438 Register scratch5) { |
| 2439 // Untag src and dst into scratch registers. | 2439 // Untag src and dst into scratch registers. |
| 2440 // Copy src->dst in a tight loop. | 2440 // Copy src->dst in a tight loop. |
| 2441 ASSERT(!AreAliased(dst, src, | 2441 DCHECK(!AreAliased(dst, src, |
| 2442 scratch1, scratch2, scratch3, scratch4, scratch5)); | 2442 scratch1, scratch2, scratch3, scratch4, scratch5)); |
| 2443 ASSERT(count >= 2); | 2443 DCHECK(count >= 2); |
| 2444 | 2444 |
| 2445 const Register& remaining = scratch3; | 2445 const Register& remaining = scratch3; |
| 2446 Mov(remaining, count / 2); | 2446 Mov(remaining, count / 2); |
| 2447 | 2447 |
| 2448 const Register& dst_untagged = scratch1; | 2448 const Register& dst_untagged = scratch1; |
| 2449 const Register& src_untagged = scratch2; | 2449 const Register& src_untagged = scratch2; |
| 2450 Sub(dst_untagged, dst, kHeapObjectTag); | 2450 Sub(dst_untagged, dst, kHeapObjectTag); |
| 2451 Sub(src_untagged, src, kHeapObjectTag); | 2451 Sub(src_untagged, src, kHeapObjectTag); |
| 2452 | 2452 |
| 2453 // Copy fields in pairs. | 2453 // Copy fields in pairs. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 2470 | 2470 |
| 2471 void MacroAssembler::CopyFieldsUnrolledPairsHelper(Register dst, | 2471 void MacroAssembler::CopyFieldsUnrolledPairsHelper(Register dst, |
| 2472 Register src, | 2472 Register src, |
| 2473 unsigned count, | 2473 unsigned count, |
| 2474 Register scratch1, | 2474 Register scratch1, |
| 2475 Register scratch2, | 2475 Register scratch2, |
| 2476 Register scratch3, | 2476 Register scratch3, |
| 2477 Register scratch4) { | 2477 Register scratch4) { |
| 2478 // Untag src and dst into scratch registers. | 2478 // Untag src and dst into scratch registers. |
| 2479 // Copy src->dst in an unrolled loop. | 2479 // Copy src->dst in an unrolled loop. |
| 2480 ASSERT(!AreAliased(dst, src, scratch1, scratch2, scratch3, scratch4)); | 2480 DCHECK(!AreAliased(dst, src, scratch1, scratch2, scratch3, scratch4)); |
| 2481 | 2481 |
| 2482 const Register& dst_untagged = scratch1; | 2482 const Register& dst_untagged = scratch1; |
| 2483 const Register& src_untagged = scratch2; | 2483 const Register& src_untagged = scratch2; |
| 2484 sub(dst_untagged, dst, kHeapObjectTag); | 2484 sub(dst_untagged, dst, kHeapObjectTag); |
| 2485 sub(src_untagged, src, kHeapObjectTag); | 2485 sub(src_untagged, src, kHeapObjectTag); |
| 2486 | 2486 |
| 2487 // Copy fields in pairs. | 2487 // Copy fields in pairs. |
| 2488 for (unsigned i = 0; i < count / 2; i++) { | 2488 for (unsigned i = 0; i < count / 2; i++) { |
| 2489 Ldp(scratch3, scratch4, MemOperand(src_untagged, kXRegSize * 2, PostIndex)); | 2489 Ldp(scratch3, scratch4, MemOperand(src_untagged, kXRegSize * 2, PostIndex)); |
| 2490 Stp(scratch3, scratch4, MemOperand(dst_untagged, kXRegSize * 2, PostIndex)); | 2490 Stp(scratch3, scratch4, MemOperand(dst_untagged, kXRegSize * 2, PostIndex)); |
| 2491 } | 2491 } |
| 2492 | 2492 |
| 2493 // Handle the leftovers. | 2493 // Handle the leftovers. |
| 2494 if (count & 1) { | 2494 if (count & 1) { |
| 2495 Ldr(scratch3, MemOperand(src_untagged)); | 2495 Ldr(scratch3, MemOperand(src_untagged)); |
| 2496 Str(scratch3, MemOperand(dst_untagged)); | 2496 Str(scratch3, MemOperand(dst_untagged)); |
| 2497 } | 2497 } |
| 2498 } | 2498 } |
| 2499 | 2499 |
| 2500 | 2500 |
| 2501 void MacroAssembler::CopyFieldsUnrolledHelper(Register dst, | 2501 void MacroAssembler::CopyFieldsUnrolledHelper(Register dst, |
| 2502 Register src, | 2502 Register src, |
| 2503 unsigned count, | 2503 unsigned count, |
| 2504 Register scratch1, | 2504 Register scratch1, |
| 2505 Register scratch2, | 2505 Register scratch2, |
| 2506 Register scratch3) { | 2506 Register scratch3) { |
| 2507 // Untag src and dst into scratch registers. | 2507 // Untag src and dst into scratch registers. |
| 2508 // Copy src->dst in an unrolled loop. | 2508 // Copy src->dst in an unrolled loop. |
| 2509 ASSERT(!AreAliased(dst, src, scratch1, scratch2, scratch3)); | 2509 DCHECK(!AreAliased(dst, src, scratch1, scratch2, scratch3)); |
| 2510 | 2510 |
| 2511 const Register& dst_untagged = scratch1; | 2511 const Register& dst_untagged = scratch1; |
| 2512 const Register& src_untagged = scratch2; | 2512 const Register& src_untagged = scratch2; |
| 2513 Sub(dst_untagged, dst, kHeapObjectTag); | 2513 Sub(dst_untagged, dst, kHeapObjectTag); |
| 2514 Sub(src_untagged, src, kHeapObjectTag); | 2514 Sub(src_untagged, src, kHeapObjectTag); |
| 2515 | 2515 |
| 2516 // Copy fields one by one. | 2516 // Copy fields one by one. |
| 2517 for (unsigned i = 0; i < count; i++) { | 2517 for (unsigned i = 0; i < count; i++) { |
| 2518 Ldr(scratch3, MemOperand(src_untagged, kXRegSize, PostIndex)); | 2518 Ldr(scratch3, MemOperand(src_untagged, kXRegSize, PostIndex)); |
| 2519 Str(scratch3, MemOperand(dst_untagged, kXRegSize, PostIndex)); | 2519 Str(scratch3, MemOperand(dst_untagged, kXRegSize, PostIndex)); |
| 2520 } | 2520 } |
| 2521 } | 2521 } |
| 2522 | 2522 |
| 2523 | 2523 |
| 2524 void MacroAssembler::CopyFields(Register dst, Register src, CPURegList temps, | 2524 void MacroAssembler::CopyFields(Register dst, Register src, CPURegList temps, |
| 2525 unsigned count) { | 2525 unsigned count) { |
| 2526 // One of two methods is used: | 2526 // One of two methods is used: |
| 2527 // | 2527 // |
| 2528 // For high 'count' values where many scratch registers are available: | 2528 // For high 'count' values where many scratch registers are available: |
| 2529 // Untag src and dst into scratch registers. | 2529 // Untag src and dst into scratch registers. |
| 2530 // Copy src->dst in a tight loop. | 2530 // Copy src->dst in a tight loop. |
| 2531 // | 2531 // |
| 2532 // For low 'count' values or where few scratch registers are available: | 2532 // For low 'count' values or where few scratch registers are available: |
| 2533 // Untag src and dst into scratch registers. | 2533 // Untag src and dst into scratch registers. |
| 2534 // Copy src->dst in an unrolled loop. | 2534 // Copy src->dst in an unrolled loop. |
| 2535 // | 2535 // |
| 2536 // In both cases, fields are copied in pairs if possible, and left-overs are | 2536 // In both cases, fields are copied in pairs if possible, and left-overs are |
| 2537 // handled separately. | 2537 // handled separately. |
| 2538 ASSERT(!AreAliased(dst, src)); | 2538 DCHECK(!AreAliased(dst, src)); |
| 2539 ASSERT(!temps.IncludesAliasOf(dst)); | 2539 DCHECK(!temps.IncludesAliasOf(dst)); |
| 2540 ASSERT(!temps.IncludesAliasOf(src)); | 2540 DCHECK(!temps.IncludesAliasOf(src)); |
| 2541 ASSERT(!temps.IncludesAliasOf(xzr)); | 2541 DCHECK(!temps.IncludesAliasOf(xzr)); |
| 2542 | 2542 |
| 2543 if (emit_debug_code()) { | 2543 if (emit_debug_code()) { |
| 2544 Cmp(dst, src); | 2544 Cmp(dst, src); |
| 2545 Check(ne, kTheSourceAndDestinationAreTheSame); | 2545 Check(ne, kTheSourceAndDestinationAreTheSame); |
| 2546 } | 2546 } |
| 2547 | 2547 |
| 2548 // The value of 'count' at which a loop will be generated (if there are | 2548 // The value of 'count' at which a loop will be generated (if there are |
| 2549 // enough scratch registers). | 2549 // enough scratch registers). |
| 2550 static const unsigned kLoopThreshold = 8; | 2550 static const unsigned kLoopThreshold = 8; |
| 2551 | 2551 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 2575 | 2575 |
| 2576 | 2576 |
| 2577 void MacroAssembler::CopyBytes(Register dst, | 2577 void MacroAssembler::CopyBytes(Register dst, |
| 2578 Register src, | 2578 Register src, |
| 2579 Register length, | 2579 Register length, |
| 2580 Register scratch, | 2580 Register scratch, |
| 2581 CopyHint hint) { | 2581 CopyHint hint) { |
| 2582 UseScratchRegisterScope temps(this); | 2582 UseScratchRegisterScope temps(this); |
| 2583 Register tmp1 = temps.AcquireX(); | 2583 Register tmp1 = temps.AcquireX(); |
| 2584 Register tmp2 = temps.AcquireX(); | 2584 Register tmp2 = temps.AcquireX(); |
| 2585 ASSERT(!AreAliased(src, dst, length, scratch, tmp1, tmp2)); | 2585 DCHECK(!AreAliased(src, dst, length, scratch, tmp1, tmp2)); |
| 2586 ASSERT(!AreAliased(src, dst, csp)); | 2586 DCHECK(!AreAliased(src, dst, csp)); |
| 2587 | 2587 |
| 2588 if (emit_debug_code()) { | 2588 if (emit_debug_code()) { |
| 2589 // Check copy length. | 2589 // Check copy length. |
| 2590 Cmp(length, 0); | 2590 Cmp(length, 0); |
| 2591 Assert(ge, kUnexpectedNegativeValue); | 2591 Assert(ge, kUnexpectedNegativeValue); |
| 2592 | 2592 |
| 2593 // Check src and dst buffers don't overlap. | 2593 // Check src and dst buffers don't overlap. |
| 2594 Add(scratch, src, length); // Calculate end of src buffer. | 2594 Add(scratch, src, length); // Calculate end of src buffer. |
| 2595 Cmp(scratch, dst); | 2595 Cmp(scratch, dst); |
| 2596 Add(scratch, dst, length); // Calculate end of dst buffer. | 2596 Add(scratch, dst, length); // Calculate end of dst buffer. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2625 Cbnz(length, &short_loop); | 2625 Cbnz(length, &short_loop); |
| 2626 | 2626 |
| 2627 | 2627 |
| 2628 Bind(&done); | 2628 Bind(&done); |
| 2629 } | 2629 } |
| 2630 | 2630 |
| 2631 | 2631 |
| 2632 void MacroAssembler::FillFields(Register dst, | 2632 void MacroAssembler::FillFields(Register dst, |
| 2633 Register field_count, | 2633 Register field_count, |
| 2634 Register filler) { | 2634 Register filler) { |
| 2635 ASSERT(!dst.Is(csp)); | 2635 DCHECK(!dst.Is(csp)); |
| 2636 UseScratchRegisterScope temps(this); | 2636 UseScratchRegisterScope temps(this); |
| 2637 Register field_ptr = temps.AcquireX(); | 2637 Register field_ptr = temps.AcquireX(); |
| 2638 Register counter = temps.AcquireX(); | 2638 Register counter = temps.AcquireX(); |
| 2639 Label done; | 2639 Label done; |
| 2640 | 2640 |
| 2641 // Decrement count. If the result < zero, count was zero, and there's nothing | 2641 // Decrement count. If the result < zero, count was zero, and there's nothing |
| 2642 // to do. If count was one, flags are set to fail the gt condition at the end | 2642 // to do. If count was one, flags are set to fail the gt condition at the end |
| 2643 // of the pairs loop. | 2643 // of the pairs loop. |
| 2644 Subs(counter, field_count, 1); | 2644 Subs(counter, field_count, 1); |
| 2645 B(lt, &done); | 2645 B(lt, &done); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2670 Register first, | 2670 Register first, |
| 2671 Register second, | 2671 Register second, |
| 2672 Register scratch1, | 2672 Register scratch1, |
| 2673 Register scratch2, | 2673 Register scratch2, |
| 2674 Label* failure, | 2674 Label* failure, |
| 2675 SmiCheckType smi_check) { | 2675 SmiCheckType smi_check) { |
| 2676 | 2676 |
| 2677 if (smi_check == DO_SMI_CHECK) { | 2677 if (smi_check == DO_SMI_CHECK) { |
| 2678 JumpIfEitherSmi(first, second, failure); | 2678 JumpIfEitherSmi(first, second, failure); |
| 2679 } else if (emit_debug_code()) { | 2679 } else if (emit_debug_code()) { |
| 2680 ASSERT(smi_check == DONT_DO_SMI_CHECK); | 2680 DCHECK(smi_check == DONT_DO_SMI_CHECK); |
| 2681 Label not_smi; | 2681 Label not_smi; |
| 2682 JumpIfEitherSmi(first, second, NULL, ¬_smi); | 2682 JumpIfEitherSmi(first, second, NULL, ¬_smi); |
| 2683 | 2683 |
| 2684 // At least one input is a smi, but the flags indicated a smi check wasn't | 2684 // At least one input is a smi, but the flags indicated a smi check wasn't |
| 2685 // needed. | 2685 // needed. |
| 2686 Abort(kUnexpectedSmi); | 2686 Abort(kUnexpectedSmi); |
| 2687 | 2687 |
| 2688 Bind(¬_smi); | 2688 Bind(¬_smi); |
| 2689 } | 2689 } |
| 2690 | 2690 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2701 failure); | 2701 failure); |
| 2702 } | 2702 } |
| 2703 | 2703 |
| 2704 | 2704 |
| 2705 void MacroAssembler::JumpIfEitherInstanceTypeIsNotSequentialAscii( | 2705 void MacroAssembler::JumpIfEitherInstanceTypeIsNotSequentialAscii( |
| 2706 Register first, | 2706 Register first, |
| 2707 Register second, | 2707 Register second, |
| 2708 Register scratch1, | 2708 Register scratch1, |
| 2709 Register scratch2, | 2709 Register scratch2, |
| 2710 Label* failure) { | 2710 Label* failure) { |
| 2711 ASSERT(!AreAliased(scratch1, second)); | 2711 DCHECK(!AreAliased(scratch1, second)); |
| 2712 ASSERT(!AreAliased(scratch1, scratch2)); | 2712 DCHECK(!AreAliased(scratch1, scratch2)); |
| 2713 static const int kFlatAsciiStringMask = | 2713 static const int kFlatAsciiStringMask = |
| 2714 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | 2714 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; |
| 2715 static const int kFlatAsciiStringTag = ASCII_STRING_TYPE; | 2715 static const int kFlatAsciiStringTag = ASCII_STRING_TYPE; |
| 2716 And(scratch1, first, kFlatAsciiStringMask); | 2716 And(scratch1, first, kFlatAsciiStringMask); |
| 2717 And(scratch2, second, kFlatAsciiStringMask); | 2717 And(scratch2, second, kFlatAsciiStringMask); |
| 2718 Cmp(scratch1, kFlatAsciiStringTag); | 2718 Cmp(scratch1, kFlatAsciiStringTag); |
| 2719 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq); | 2719 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq); |
| 2720 B(ne, failure); | 2720 B(ne, failure); |
| 2721 } | 2721 } |
| 2722 | 2722 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2733 B(ne, failure); | 2733 B(ne, failure); |
| 2734 } | 2734 } |
| 2735 | 2735 |
| 2736 | 2736 |
| 2737 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( | 2737 void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialAscii( |
| 2738 Register first, | 2738 Register first, |
| 2739 Register second, | 2739 Register second, |
| 2740 Register scratch1, | 2740 Register scratch1, |
| 2741 Register scratch2, | 2741 Register scratch2, |
| 2742 Label* failure) { | 2742 Label* failure) { |
| 2743 ASSERT(!AreAliased(first, second, scratch1, scratch2)); | 2743 DCHECK(!AreAliased(first, second, scratch1, scratch2)); |
| 2744 const int kFlatAsciiStringMask = | 2744 const int kFlatAsciiStringMask = |
| 2745 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; | 2745 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask; |
| 2746 const int kFlatAsciiStringTag = | 2746 const int kFlatAsciiStringTag = |
| 2747 kStringTag | kOneByteStringTag | kSeqStringTag; | 2747 kStringTag | kOneByteStringTag | kSeqStringTag; |
| 2748 And(scratch1, first, kFlatAsciiStringMask); | 2748 And(scratch1, first, kFlatAsciiStringMask); |
| 2749 And(scratch2, second, kFlatAsciiStringMask); | 2749 And(scratch2, second, kFlatAsciiStringMask); |
| 2750 Cmp(scratch1, kFlatAsciiStringTag); | 2750 Cmp(scratch1, kFlatAsciiStringTag); |
| 2751 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq); | 2751 Ccmp(scratch2, kFlatAsciiStringTag, NoFlag, eq); |
| 2752 B(ne, failure); | 2752 B(ne, failure); |
| 2753 } | 2753 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2781 | 2781 |
| 2782 // Check whether the expected and actual arguments count match. If not, | 2782 // Check whether the expected and actual arguments count match. If not, |
| 2783 // setup registers according to contract with ArgumentsAdaptorTrampoline: | 2783 // setup registers according to contract with ArgumentsAdaptorTrampoline: |
| 2784 // x0: actual arguments count. | 2784 // x0: actual arguments count. |
| 2785 // x1: function (passed through to callee). | 2785 // x1: function (passed through to callee). |
| 2786 // x2: expected arguments count. | 2786 // x2: expected arguments count. |
| 2787 | 2787 |
| 2788 // The code below is made a lot easier because the calling code already sets | 2788 // The code below is made a lot easier because the calling code already sets |
| 2789 // up actual and expected registers according to the contract if values are | 2789 // up actual and expected registers according to the contract if values are |
| 2790 // passed in registers. | 2790 // passed in registers. |
| 2791 ASSERT(actual.is_immediate() || actual.reg().is(x0)); | 2791 DCHECK(actual.is_immediate() || actual.reg().is(x0)); |
| 2792 ASSERT(expected.is_immediate() || expected.reg().is(x2)); | 2792 DCHECK(expected.is_immediate() || expected.reg().is(x2)); |
| 2793 ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(x3)); | 2793 DCHECK((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(x3)); |
| 2794 | 2794 |
| 2795 if (expected.is_immediate()) { | 2795 if (expected.is_immediate()) { |
| 2796 ASSERT(actual.is_immediate()); | 2796 DCHECK(actual.is_immediate()); |
| 2797 if (expected.immediate() == actual.immediate()) { | 2797 if (expected.immediate() == actual.immediate()) { |
| 2798 definitely_matches = true; | 2798 definitely_matches = true; |
| 2799 | 2799 |
| 2800 } else { | 2800 } else { |
| 2801 Mov(x0, actual.immediate()); | 2801 Mov(x0, actual.immediate()); |
| 2802 if (expected.immediate() == | 2802 if (expected.immediate() == |
| 2803 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { | 2803 SharedFunctionInfo::kDontAdaptArgumentsSentinel) { |
| 2804 // Don't worry about adapting arguments for builtins that | 2804 // Don't worry about adapting arguments for builtins that |
| 2805 // don't want that done. Skip adaption code by making it look | 2805 // don't want that done. Skip adaption code by making it look |
| 2806 // like we have a match between expected and actual number of | 2806 // like we have a match between expected and actual number of |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2849 Bind(®ular_invoke); | 2849 Bind(®ular_invoke); |
| 2850 } | 2850 } |
| 2851 | 2851 |
| 2852 | 2852 |
| 2853 void MacroAssembler::InvokeCode(Register code, | 2853 void MacroAssembler::InvokeCode(Register code, |
| 2854 const ParameterCount& expected, | 2854 const ParameterCount& expected, |
| 2855 const ParameterCount& actual, | 2855 const ParameterCount& actual, |
| 2856 InvokeFlag flag, | 2856 InvokeFlag flag, |
| 2857 const CallWrapper& call_wrapper) { | 2857 const CallWrapper& call_wrapper) { |
| 2858 // You can't call a function without a valid frame. | 2858 // You can't call a function without a valid frame. |
| 2859 ASSERT(flag == JUMP_FUNCTION || has_frame()); | 2859 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 2860 | 2860 |
| 2861 Label done; | 2861 Label done; |
| 2862 | 2862 |
| 2863 bool definitely_mismatches = false; | 2863 bool definitely_mismatches = false; |
| 2864 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, | 2864 InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag, |
| 2865 &definitely_mismatches, call_wrapper); | 2865 &definitely_mismatches, call_wrapper); |
| 2866 | 2866 |
| 2867 // If we are certain that actual != expected, then we know InvokePrologue will | 2867 // If we are certain that actual != expected, then we know InvokePrologue will |
| 2868 // have handled the call through the argument adaptor mechanism. | 2868 // have handled the call through the argument adaptor mechanism. |
| 2869 // The called function expects the call kind in x5. | 2869 // The called function expects the call kind in x5. |
| 2870 if (!definitely_mismatches) { | 2870 if (!definitely_mismatches) { |
| 2871 if (flag == CALL_FUNCTION) { | 2871 if (flag == CALL_FUNCTION) { |
| 2872 call_wrapper.BeforeCall(CallSize(code)); | 2872 call_wrapper.BeforeCall(CallSize(code)); |
| 2873 Call(code); | 2873 Call(code); |
| 2874 call_wrapper.AfterCall(); | 2874 call_wrapper.AfterCall(); |
| 2875 } else { | 2875 } else { |
| 2876 ASSERT(flag == JUMP_FUNCTION); | 2876 DCHECK(flag == JUMP_FUNCTION); |
| 2877 Jump(code); | 2877 Jump(code); |
| 2878 } | 2878 } |
| 2879 } | 2879 } |
| 2880 | 2880 |
| 2881 // Continue here if InvokePrologue does handle the invocation due to | 2881 // Continue here if InvokePrologue does handle the invocation due to |
| 2882 // mismatched parameter counts. | 2882 // mismatched parameter counts. |
| 2883 Bind(&done); | 2883 Bind(&done); |
| 2884 } | 2884 } |
| 2885 | 2885 |
| 2886 | 2886 |
| 2887 void MacroAssembler::InvokeFunction(Register function, | 2887 void MacroAssembler::InvokeFunction(Register function, |
| 2888 const ParameterCount& actual, | 2888 const ParameterCount& actual, |
| 2889 InvokeFlag flag, | 2889 InvokeFlag flag, |
| 2890 const CallWrapper& call_wrapper) { | 2890 const CallWrapper& call_wrapper) { |
| 2891 // You can't call a function without a valid frame. | 2891 // You can't call a function without a valid frame. |
| 2892 ASSERT(flag == JUMP_FUNCTION || has_frame()); | 2892 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 2893 | 2893 |
| 2894 // Contract with called JS functions requires that function is passed in x1. | 2894 // Contract with called JS functions requires that function is passed in x1. |
| 2895 // (See FullCodeGenerator::Generate().) | 2895 // (See FullCodeGenerator::Generate().) |
| 2896 ASSERT(function.is(x1)); | 2896 DCHECK(function.is(x1)); |
| 2897 | 2897 |
| 2898 Register expected_reg = x2; | 2898 Register expected_reg = x2; |
| 2899 Register code_reg = x3; | 2899 Register code_reg = x3; |
| 2900 | 2900 |
| 2901 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset)); | 2901 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset)); |
| 2902 // The number of arguments is stored as an int32_t, and -1 is a marker | 2902 // The number of arguments is stored as an int32_t, and -1 is a marker |
| 2903 // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign | 2903 // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign |
| 2904 // extension to correctly handle it. | 2904 // extension to correctly handle it. |
| 2905 Ldr(expected_reg, FieldMemOperand(function, | 2905 Ldr(expected_reg, FieldMemOperand(function, |
| 2906 JSFunction::kSharedFunctionInfoOffset)); | 2906 JSFunction::kSharedFunctionInfoOffset)); |
| 2907 Ldrsw(expected_reg, | 2907 Ldrsw(expected_reg, |
| 2908 FieldMemOperand(expected_reg, | 2908 FieldMemOperand(expected_reg, |
| 2909 SharedFunctionInfo::kFormalParameterCountOffset)); | 2909 SharedFunctionInfo::kFormalParameterCountOffset)); |
| 2910 Ldr(code_reg, | 2910 Ldr(code_reg, |
| 2911 FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 2911 FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| 2912 | 2912 |
| 2913 ParameterCount expected(expected_reg); | 2913 ParameterCount expected(expected_reg); |
| 2914 InvokeCode(code_reg, expected, actual, flag, call_wrapper); | 2914 InvokeCode(code_reg, expected, actual, flag, call_wrapper); |
| 2915 } | 2915 } |
| 2916 | 2916 |
| 2917 | 2917 |
| 2918 void MacroAssembler::InvokeFunction(Register function, | 2918 void MacroAssembler::InvokeFunction(Register function, |
| 2919 const ParameterCount& expected, | 2919 const ParameterCount& expected, |
| 2920 const ParameterCount& actual, | 2920 const ParameterCount& actual, |
| 2921 InvokeFlag flag, | 2921 InvokeFlag flag, |
| 2922 const CallWrapper& call_wrapper) { | 2922 const CallWrapper& call_wrapper) { |
| 2923 // You can't call a function without a valid frame. | 2923 // You can't call a function without a valid frame. |
| 2924 ASSERT(flag == JUMP_FUNCTION || has_frame()); | 2924 DCHECK(flag == JUMP_FUNCTION || has_frame()); |
| 2925 | 2925 |
| 2926 // Contract with called JS functions requires that function is passed in x1. | 2926 // Contract with called JS functions requires that function is passed in x1. |
| 2927 // (See FullCodeGenerator::Generate().) | 2927 // (See FullCodeGenerator::Generate().) |
| 2928 ASSERT(function.Is(x1)); | 2928 DCHECK(function.Is(x1)); |
| 2929 | 2929 |
| 2930 Register code_reg = x3; | 2930 Register code_reg = x3; |
| 2931 | 2931 |
| 2932 // Set up the context. | 2932 // Set up the context. |
| 2933 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset)); | 2933 Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset)); |
| 2934 | 2934 |
| 2935 // We call indirectly through the code field in the function to | 2935 // We call indirectly through the code field in the function to |
| 2936 // allow recompilation to take effect without changing any of the | 2936 // allow recompilation to take effect without changing any of the |
| 2937 // call sites. | 2937 // call sites. |
| 2938 Ldr(code_reg, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | 2938 Ldr(code_reg, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2973 Cmp(result.X(), 1); | 2973 Cmp(result.X(), 1); |
| 2974 Ccmp(result.X(), -1, VFlag, vc); | 2974 Ccmp(result.X(), -1, VFlag, vc); |
| 2975 | 2975 |
| 2976 B(vc, done); | 2976 B(vc, done); |
| 2977 } | 2977 } |
| 2978 | 2978 |
| 2979 | 2979 |
| 2980 void MacroAssembler::TruncateDoubleToI(Register result, | 2980 void MacroAssembler::TruncateDoubleToI(Register result, |
| 2981 DoubleRegister double_input) { | 2981 DoubleRegister double_input) { |
| 2982 Label done; | 2982 Label done; |
| 2983 ASSERT(jssp.Is(StackPointer())); | 2983 DCHECK(jssp.Is(StackPointer())); |
| 2984 | 2984 |
| 2985 // Try to convert the double to an int64. If successful, the bottom 32 bits | 2985 // Try to convert the double to an int64. If successful, the bottom 32 bits |
| 2986 // contain our truncated int32 result. | 2986 // contain our truncated int32 result. |
| 2987 TryConvertDoubleToInt64(result, double_input, &done); | 2987 TryConvertDoubleToInt64(result, double_input, &done); |
| 2988 | 2988 |
| 2989 // If we fell through then inline version didn't succeed - call stub instead. | 2989 // If we fell through then inline version didn't succeed - call stub instead. |
| 2990 Push(lr, double_input); | 2990 Push(lr, double_input); |
| 2991 | 2991 |
| 2992 DoubleToIStub stub(isolate(), | 2992 DoubleToIStub stub(isolate(), |
| 2993 jssp, | 2993 jssp, |
| 2994 result, | 2994 result, |
| 2995 0, | 2995 0, |
| 2996 true, // is_truncating | 2996 true, // is_truncating |
| 2997 true); // skip_fastpath | 2997 true); // skip_fastpath |
| 2998 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber | 2998 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber |
| 2999 | 2999 |
| 3000 Drop(1, kDoubleSize); // Drop the double input on the stack. | 3000 Drop(1, kDoubleSize); // Drop the double input on the stack. |
| 3001 Pop(lr); | 3001 Pop(lr); |
| 3002 | 3002 |
| 3003 Bind(&done); | 3003 Bind(&done); |
| 3004 } | 3004 } |
| 3005 | 3005 |
| 3006 | 3006 |
| 3007 void MacroAssembler::TruncateHeapNumberToI(Register result, | 3007 void MacroAssembler::TruncateHeapNumberToI(Register result, |
| 3008 Register object) { | 3008 Register object) { |
| 3009 Label done; | 3009 Label done; |
| 3010 ASSERT(!result.is(object)); | 3010 DCHECK(!result.is(object)); |
| 3011 ASSERT(jssp.Is(StackPointer())); | 3011 DCHECK(jssp.Is(StackPointer())); |
| 3012 | 3012 |
| 3013 Ldr(fp_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); | 3013 Ldr(fp_scratch, FieldMemOperand(object, HeapNumber::kValueOffset)); |
| 3014 | 3014 |
| 3015 // Try to convert the double to an int64. If successful, the bottom 32 bits | 3015 // Try to convert the double to an int64. If successful, the bottom 32 bits |
| 3016 // contain our truncated int32 result. | 3016 // contain our truncated int32 result. |
| 3017 TryConvertDoubleToInt64(result, fp_scratch, &done); | 3017 TryConvertDoubleToInt64(result, fp_scratch, &done); |
| 3018 | 3018 |
| 3019 // If we fell through then inline version didn't succeed - call stub instead. | 3019 // If we fell through then inline version didn't succeed - call stub instead. |
| 3020 Push(lr); | 3020 Push(lr); |
| 3021 DoubleToIStub stub(isolate(), | 3021 DoubleToIStub stub(isolate(), |
| 3022 object, | 3022 object, |
| 3023 result, | 3023 result, |
| 3024 HeapNumber::kValueOffset - kHeapObjectTag, | 3024 HeapNumber::kValueOffset - kHeapObjectTag, |
| 3025 true, // is_truncating | 3025 true, // is_truncating |
| 3026 true); // skip_fastpath | 3026 true); // skip_fastpath |
| 3027 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber | 3027 CallStub(&stub); // DoubleToIStub preserves any registers it needs to clobber |
| 3028 Pop(lr); | 3028 Pop(lr); |
| 3029 | 3029 |
| 3030 Bind(&done); | 3030 Bind(&done); |
| 3031 } | 3031 } |
| 3032 | 3032 |
| 3033 | 3033 |
| 3034 void MacroAssembler::StubPrologue() { | 3034 void MacroAssembler::StubPrologue() { |
| 3035 ASSERT(StackPointer().Is(jssp)); | 3035 DCHECK(StackPointer().Is(jssp)); |
| 3036 UseScratchRegisterScope temps(this); | 3036 UseScratchRegisterScope temps(this); |
| 3037 Register temp = temps.AcquireX(); | 3037 Register temp = temps.AcquireX(); |
| 3038 __ Mov(temp, Smi::FromInt(StackFrame::STUB)); | 3038 __ Mov(temp, Smi::FromInt(StackFrame::STUB)); |
| 3039 // Compiled stubs don't age, and so they don't need the predictable code | 3039 // Compiled stubs don't age, and so they don't need the predictable code |
| 3040 // ageing sequence. | 3040 // ageing sequence. |
| 3041 __ Push(lr, fp, cp, temp); | 3041 __ Push(lr, fp, cp, temp); |
| 3042 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp); | 3042 __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp); |
| 3043 } | 3043 } |
| 3044 | 3044 |
| 3045 | 3045 |
| 3046 void MacroAssembler::Prologue(bool code_pre_aging) { | 3046 void MacroAssembler::Prologue(bool code_pre_aging) { |
| 3047 if (code_pre_aging) { | 3047 if (code_pre_aging) { |
| 3048 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); | 3048 Code* stub = Code::GetPreAgedCodeAgeStub(isolate()); |
| 3049 __ EmitCodeAgeSequence(stub); | 3049 __ EmitCodeAgeSequence(stub); |
| 3050 } else { | 3050 } else { |
| 3051 __ EmitFrameSetupForCodeAgePatching(); | 3051 __ EmitFrameSetupForCodeAgePatching(); |
| 3052 } | 3052 } |
| 3053 } | 3053 } |
| 3054 | 3054 |
| 3055 | 3055 |
| 3056 void MacroAssembler::EnterFrame(StackFrame::Type type) { | 3056 void MacroAssembler::EnterFrame(StackFrame::Type type) { |
| 3057 ASSERT(jssp.Is(StackPointer())); | 3057 DCHECK(jssp.Is(StackPointer())); |
| 3058 UseScratchRegisterScope temps(this); | 3058 UseScratchRegisterScope temps(this); |
| 3059 Register type_reg = temps.AcquireX(); | 3059 Register type_reg = temps.AcquireX(); |
| 3060 Register code_reg = temps.AcquireX(); | 3060 Register code_reg = temps.AcquireX(); |
| 3061 | 3061 |
| 3062 Push(lr, fp, cp); | 3062 Push(lr, fp, cp); |
| 3063 Mov(type_reg, Smi::FromInt(type)); | 3063 Mov(type_reg, Smi::FromInt(type)); |
| 3064 Mov(code_reg, Operand(CodeObject())); | 3064 Mov(code_reg, Operand(CodeObject())); |
| 3065 Push(type_reg, code_reg); | 3065 Push(type_reg, code_reg); |
| 3066 // jssp[4] : lr | 3066 // jssp[4] : lr |
| 3067 // jssp[3] : fp | 3067 // jssp[3] : fp |
| 3068 // jssp[2] : cp | 3068 // jssp[2] : cp |
| 3069 // jssp[1] : type | 3069 // jssp[1] : type |
| 3070 // jssp[0] : code object | 3070 // jssp[0] : code object |
| 3071 | 3071 |
| 3072 // Adjust FP to point to saved FP. | 3072 // Adjust FP to point to saved FP. |
| 3073 Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize); | 3073 Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize); |
| 3074 } | 3074 } |
| 3075 | 3075 |
| 3076 | 3076 |
| 3077 void MacroAssembler::LeaveFrame(StackFrame::Type type) { | 3077 void MacroAssembler::LeaveFrame(StackFrame::Type type) { |
| 3078 ASSERT(jssp.Is(StackPointer())); | 3078 DCHECK(jssp.Is(StackPointer())); |
| 3079 // Drop the execution stack down to the frame pointer and restore | 3079 // Drop the execution stack down to the frame pointer and restore |
| 3080 // the caller frame pointer and return address. | 3080 // the caller frame pointer and return address. |
| 3081 Mov(jssp, fp); | 3081 Mov(jssp, fp); |
| 3082 AssertStackConsistency(); | 3082 AssertStackConsistency(); |
| 3083 Pop(fp, lr); | 3083 Pop(fp, lr); |
| 3084 } | 3084 } |
| 3085 | 3085 |
| 3086 | 3086 |
| 3087 void MacroAssembler::ExitFramePreserveFPRegs() { | 3087 void MacroAssembler::ExitFramePreserveFPRegs() { |
| 3088 PushCPURegList(kCallerSavedFP); | 3088 PushCPURegList(kCallerSavedFP); |
| 3089 } | 3089 } |
| 3090 | 3090 |
| 3091 | 3091 |
| 3092 void MacroAssembler::ExitFrameRestoreFPRegs() { | 3092 void MacroAssembler::ExitFrameRestoreFPRegs() { |
| 3093 // Read the registers from the stack without popping them. The stack pointer | 3093 // Read the registers from the stack without popping them. The stack pointer |
| 3094 // will be reset as part of the unwinding process. | 3094 // will be reset as part of the unwinding process. |
| 3095 CPURegList saved_fp_regs = kCallerSavedFP; | 3095 CPURegList saved_fp_regs = kCallerSavedFP; |
| 3096 ASSERT(saved_fp_regs.Count() % 2 == 0); | 3096 DCHECK(saved_fp_regs.Count() % 2 == 0); |
| 3097 | 3097 |
| 3098 int offset = ExitFrameConstants::kLastExitFrameField; | 3098 int offset = ExitFrameConstants::kLastExitFrameField; |
| 3099 while (!saved_fp_regs.IsEmpty()) { | 3099 while (!saved_fp_regs.IsEmpty()) { |
| 3100 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); | 3100 const CPURegister& dst0 = saved_fp_regs.PopHighestIndex(); |
| 3101 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); | 3101 const CPURegister& dst1 = saved_fp_regs.PopHighestIndex(); |
| 3102 offset -= 2 * kDRegSize; | 3102 offset -= 2 * kDRegSize; |
| 3103 Ldp(dst1, dst0, MemOperand(fp, offset)); | 3103 Ldp(dst1, dst0, MemOperand(fp, offset)); |
| 3104 } | 3104 } |
| 3105 } | 3105 } |
| 3106 | 3106 |
| 3107 | 3107 |
| 3108 void MacroAssembler::EnterExitFrame(bool save_doubles, | 3108 void MacroAssembler::EnterExitFrame(bool save_doubles, |
| 3109 const Register& scratch, | 3109 const Register& scratch, |
| 3110 int extra_space) { | 3110 int extra_space) { |
| 3111 ASSERT(jssp.Is(StackPointer())); | 3111 DCHECK(jssp.Is(StackPointer())); |
| 3112 | 3112 |
| 3113 // Set up the new stack frame. | 3113 // Set up the new stack frame. |
| 3114 Mov(scratch, Operand(CodeObject())); | 3114 Mov(scratch, Operand(CodeObject())); |
| 3115 Push(lr, fp); | 3115 Push(lr, fp); |
| 3116 Mov(fp, StackPointer()); | 3116 Mov(fp, StackPointer()); |
| 3117 Push(xzr, scratch); | 3117 Push(xzr, scratch); |
| 3118 // fp[8]: CallerPC (lr) | 3118 // fp[8]: CallerPC (lr) |
| 3119 // fp -> fp[0]: CallerFP (old fp) | 3119 // fp -> fp[0]: CallerFP (old fp) |
| 3120 // fp[-8]: Space reserved for SPOffset. | 3120 // fp[-8]: Space reserved for SPOffset. |
| 3121 // jssp -> fp[-16]: CodeObject() | 3121 // jssp -> fp[-16]: CodeObject() |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3147 // fp[8]: CallerPC (lr) | 3147 // fp[8]: CallerPC (lr) |
| 3148 // fp -> fp[0]: CallerFP (old fp) | 3148 // fp -> fp[0]: CallerFP (old fp) |
| 3149 // fp[-8]: Space reserved for SPOffset. | 3149 // fp[-8]: Space reserved for SPOffset. |
| 3150 // fp[-16]: CodeObject() | 3150 // fp[-16]: CodeObject() |
| 3151 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true). | 3151 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true). |
| 3152 // jssp[8]: Extra space reserved for caller (if extra_space != 0). | 3152 // jssp[8]: Extra space reserved for caller (if extra_space != 0). |
| 3153 // jssp -> jssp[0]: Space reserved for the return address. | 3153 // jssp -> jssp[0]: Space reserved for the return address. |
| 3154 | 3154 |
| 3155 // Align and synchronize the system stack pointer with jssp. | 3155 // Align and synchronize the system stack pointer with jssp. |
| 3156 AlignAndSetCSPForFrame(); | 3156 AlignAndSetCSPForFrame(); |
| 3157 ASSERT(csp.Is(StackPointer())); | 3157 DCHECK(csp.Is(StackPointer())); |
| 3158 | 3158 |
| 3159 // fp[8]: CallerPC (lr) | 3159 // fp[8]: CallerPC (lr) |
| 3160 // fp -> fp[0]: CallerFP (old fp) | 3160 // fp -> fp[0]: CallerFP (old fp) |
| 3161 // fp[-8]: Space reserved for SPOffset. | 3161 // fp[-8]: Space reserved for SPOffset. |
| 3162 // fp[-16]: CodeObject() | 3162 // fp[-16]: CodeObject() |
| 3163 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true). | 3163 // fp[-16 - fp_size]: Saved doubles (if save_doubles is true). |
| 3164 // csp[8]: Memory reserved for the caller if extra_space != 0. | 3164 // csp[8]: Memory reserved for the caller if extra_space != 0. |
| 3165 // Alignment padding, if necessary. | 3165 // Alignment padding, if necessary. |
| 3166 // csp -> csp[0]: Space reserved for the return address. | 3166 // csp -> csp[0]: Space reserved for the return address. |
| 3167 | 3167 |
| 3168 // ExitFrame::GetStateForFramePointer expects to find the return address at | 3168 // ExitFrame::GetStateForFramePointer expects to find the return address at |
| 3169 // the memory address immediately below the pointer stored in SPOffset. | 3169 // the memory address immediately below the pointer stored in SPOffset. |
| 3170 // It is not safe to derive much else from SPOffset, because the size of the | 3170 // It is not safe to derive much else from SPOffset, because the size of the |
| 3171 // padding can vary. | 3171 // padding can vary. |
| 3172 Add(scratch, csp, kXRegSize); | 3172 Add(scratch, csp, kXRegSize); |
| 3173 Str(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset)); | 3173 Str(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset)); |
| 3174 } | 3174 } |
| 3175 | 3175 |
| 3176 | 3176 |
| 3177 // Leave the current exit frame. | 3177 // Leave the current exit frame. |
| 3178 void MacroAssembler::LeaveExitFrame(bool restore_doubles, | 3178 void MacroAssembler::LeaveExitFrame(bool restore_doubles, |
| 3179 const Register& scratch, | 3179 const Register& scratch, |
| 3180 bool restore_context) { | 3180 bool restore_context) { |
| 3181 ASSERT(csp.Is(StackPointer())); | 3181 DCHECK(csp.Is(StackPointer())); |
| 3182 | 3182 |
| 3183 if (restore_doubles) { | 3183 if (restore_doubles) { |
| 3184 ExitFrameRestoreFPRegs(); | 3184 ExitFrameRestoreFPRegs(); |
| 3185 } | 3185 } |
| 3186 | 3186 |
| 3187 // Restore the context pointer from the top frame. | 3187 // Restore the context pointer from the top frame. |
| 3188 if (restore_context) { | 3188 if (restore_context) { |
| 3189 Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress, | 3189 Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress, |
| 3190 isolate()))); | 3190 isolate()))); |
| 3191 Ldr(cp, MemOperand(scratch)); | 3191 Ldr(cp, MemOperand(scratch)); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3218 if (FLAG_native_code_counters && counter->Enabled()) { | 3218 if (FLAG_native_code_counters && counter->Enabled()) { |
| 3219 Mov(scratch1, value); | 3219 Mov(scratch1, value); |
| 3220 Mov(scratch2, ExternalReference(counter)); | 3220 Mov(scratch2, ExternalReference(counter)); |
| 3221 Str(scratch1, MemOperand(scratch2)); | 3221 Str(scratch1, MemOperand(scratch2)); |
| 3222 } | 3222 } |
| 3223 } | 3223 } |
| 3224 | 3224 |
| 3225 | 3225 |
| 3226 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, | 3226 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value, |
| 3227 Register scratch1, Register scratch2) { | 3227 Register scratch1, Register scratch2) { |
| 3228 ASSERT(value != 0); | 3228 DCHECK(value != 0); |
| 3229 if (FLAG_native_code_counters && counter->Enabled()) { | 3229 if (FLAG_native_code_counters && counter->Enabled()) { |
| 3230 Mov(scratch2, ExternalReference(counter)); | 3230 Mov(scratch2, ExternalReference(counter)); |
| 3231 Ldr(scratch1, MemOperand(scratch2)); | 3231 Ldr(scratch1, MemOperand(scratch2)); |
| 3232 Add(scratch1, scratch1, value); | 3232 Add(scratch1, scratch1, value); |
| 3233 Str(scratch1, MemOperand(scratch2)); | 3233 Str(scratch1, MemOperand(scratch2)); |
| 3234 } | 3234 } |
| 3235 } | 3235 } |
| 3236 | 3236 |
| 3237 | 3237 |
| 3238 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, | 3238 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3254 // cannot be allowed to destroy the context in cp). | 3254 // cannot be allowed to destroy the context in cp). |
| 3255 Mov(dst, cp); | 3255 Mov(dst, cp); |
| 3256 } | 3256 } |
| 3257 } | 3257 } |
| 3258 | 3258 |
| 3259 | 3259 |
| 3260 void MacroAssembler::DebugBreak() { | 3260 void MacroAssembler::DebugBreak() { |
| 3261 Mov(x0, 0); | 3261 Mov(x0, 0); |
| 3262 Mov(x1, ExternalReference(Runtime::kDebugBreak, isolate())); | 3262 Mov(x1, ExternalReference(Runtime::kDebugBreak, isolate())); |
| 3263 CEntryStub ces(isolate(), 1); | 3263 CEntryStub ces(isolate(), 1); |
| 3264 ASSERT(AllowThisStubCall(&ces)); | 3264 DCHECK(AllowThisStubCall(&ces)); |
| 3265 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); | 3265 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK); |
| 3266 } | 3266 } |
| 3267 | 3267 |
| 3268 | 3268 |
| 3269 void MacroAssembler::PushTryHandler(StackHandler::Kind kind, | 3269 void MacroAssembler::PushTryHandler(StackHandler::Kind kind, |
| 3270 int handler_index) { | 3270 int handler_index) { |
| 3271 ASSERT(jssp.Is(StackPointer())); | 3271 DCHECK(jssp.Is(StackPointer())); |
| 3272 // Adjust this code if the asserts don't hold. | 3272 // Adjust this code if the asserts don't hold. |
| 3273 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); | 3273 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize); |
| 3274 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); | 3274 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize); |
| 3275 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); | 3275 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize); |
| 3276 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); | 3276 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize); |
| 3277 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); | 3277 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize); |
| 3278 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); | 3278 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize); |
| 3279 | 3279 |
| 3280 // For the JSEntry handler, we must preserve the live registers x0-x4. | 3280 // For the JSEntry handler, we must preserve the live registers x0-x4. |
| 3281 // (See JSEntryStub::GenerateBody().) | 3281 // (See JSEntryStub::GenerateBody().) |
| 3282 | 3282 |
| 3283 unsigned state = | 3283 unsigned state = |
| 3284 StackHandler::IndexField::encode(handler_index) | | 3284 StackHandler::IndexField::encode(handler_index) | |
| 3285 StackHandler::KindField::encode(kind); | 3285 StackHandler::KindField::encode(kind); |
| 3286 | 3286 |
| 3287 // Set up the code object and the state for pushing. | 3287 // Set up the code object and the state for pushing. |
| 3288 Mov(x10, Operand(CodeObject())); | 3288 Mov(x10, Operand(CodeObject())); |
| 3289 Mov(x11, state); | 3289 Mov(x11, state); |
| 3290 | 3290 |
| 3291 // Push the frame pointer, context, state, and code object. | 3291 // Push the frame pointer, context, state, and code object. |
| 3292 if (kind == StackHandler::JS_ENTRY) { | 3292 if (kind == StackHandler::JS_ENTRY) { |
| 3293 ASSERT(Smi::FromInt(0) == 0); | 3293 DCHECK(Smi::FromInt(0) == 0); |
| 3294 Push(xzr, xzr, x11, x10); | 3294 Push(xzr, xzr, x11, x10); |
| 3295 } else { | 3295 } else { |
| 3296 Push(fp, cp, x11, x10); | 3296 Push(fp, cp, x11, x10); |
| 3297 } | 3297 } |
| 3298 | 3298 |
| 3299 // Link the current handler as the next handler. | 3299 // Link the current handler as the next handler. |
| 3300 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate())); | 3300 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate())); |
| 3301 Ldr(x10, MemOperand(x11)); | 3301 Ldr(x10, MemOperand(x11)); |
| 3302 Push(x10); | 3302 Push(x10); |
| 3303 // Set this new handler as the current one. | 3303 // Set this new handler as the current one. |
| 3304 Str(jssp, MemOperand(x11)); | 3304 Str(jssp, MemOperand(x11)); |
| 3305 } | 3305 } |
| 3306 | 3306 |
| 3307 | 3307 |
| 3308 void MacroAssembler::PopTryHandler() { | 3308 void MacroAssembler::PopTryHandler() { |
| 3309 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 3309 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
| 3310 Pop(x10); | 3310 Pop(x10); |
| 3311 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate())); | 3311 Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate())); |
| 3312 Drop(StackHandlerConstants::kSize - kXRegSize, kByteSizeInBytes); | 3312 Drop(StackHandlerConstants::kSize - kXRegSize, kByteSizeInBytes); |
| 3313 Str(x10, MemOperand(x11)); | 3313 Str(x10, MemOperand(x11)); |
| 3314 } | 3314 } |
| 3315 | 3315 |
| 3316 | 3316 |
| 3317 void MacroAssembler::Allocate(int object_size, | 3317 void MacroAssembler::Allocate(int object_size, |
| 3318 Register result, | 3318 Register result, |
| 3319 Register scratch1, | 3319 Register scratch1, |
| 3320 Register scratch2, | 3320 Register scratch2, |
| 3321 Label* gc_required, | 3321 Label* gc_required, |
| 3322 AllocationFlags flags) { | 3322 AllocationFlags flags) { |
| 3323 ASSERT(object_size <= Page::kMaxRegularHeapObjectSize); | 3323 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize); |
| 3324 if (!FLAG_inline_new) { | 3324 if (!FLAG_inline_new) { |
| 3325 if (emit_debug_code()) { | 3325 if (emit_debug_code()) { |
| 3326 // Trash the registers to simulate an allocation failure. | 3326 // Trash the registers to simulate an allocation failure. |
| 3327 // We apply salt to the original zap value to easily spot the values. | 3327 // We apply salt to the original zap value to easily spot the values. |
| 3328 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L); | 3328 Mov(result, (kDebugZapValue & ~0xffL) | 0x11L); |
| 3329 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L); | 3329 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L); |
| 3330 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L); | 3330 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L); |
| 3331 } | 3331 } |
| 3332 B(gc_required); | 3332 B(gc_required); |
| 3333 return; | 3333 return; |
| 3334 } | 3334 } |
| 3335 | 3335 |
| 3336 UseScratchRegisterScope temps(this); | 3336 UseScratchRegisterScope temps(this); |
| 3337 Register scratch3 = temps.AcquireX(); | 3337 Register scratch3 = temps.AcquireX(); |
| 3338 | 3338 |
| 3339 ASSERT(!AreAliased(result, scratch1, scratch2, scratch3)); | 3339 DCHECK(!AreAliased(result, scratch1, scratch2, scratch3)); |
| 3340 ASSERT(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits()); | 3340 DCHECK(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits()); |
| 3341 | 3341 |
| 3342 // Make object size into bytes. | 3342 // Make object size into bytes. |
| 3343 if ((flags & SIZE_IN_WORDS) != 0) { | 3343 if ((flags & SIZE_IN_WORDS) != 0) { |
| 3344 object_size *= kPointerSize; | 3344 object_size *= kPointerSize; |
| 3345 } | 3345 } |
| 3346 ASSERT(0 == (object_size & kObjectAlignmentMask)); | 3346 DCHECK(0 == (object_size & kObjectAlignmentMask)); |
| 3347 | 3347 |
| 3348 // Check relative positions of allocation top and limit addresses. | 3348 // Check relative positions of allocation top and limit addresses. |
| 3349 // The values must be adjacent in memory to allow the use of LDP. | 3349 // The values must be adjacent in memory to allow the use of LDP. |
| 3350 ExternalReference heap_allocation_top = | 3350 ExternalReference heap_allocation_top = |
| 3351 AllocationUtils::GetAllocationTopReference(isolate(), flags); | 3351 AllocationUtils::GetAllocationTopReference(isolate(), flags); |
| 3352 ExternalReference heap_allocation_limit = | 3352 ExternalReference heap_allocation_limit = |
| 3353 AllocationUtils::GetAllocationLimitReference(isolate(), flags); | 3353 AllocationUtils::GetAllocationLimitReference(isolate(), flags); |
| 3354 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); | 3354 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); |
| 3355 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); | 3355 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); |
| 3356 ASSERT((limit - top) == kPointerSize); | 3356 DCHECK((limit - top) == kPointerSize); |
| 3357 | 3357 |
| 3358 // Set up allocation top address and object size registers. | 3358 // Set up allocation top address and object size registers. |
| 3359 Register top_address = scratch1; | 3359 Register top_address = scratch1; |
| 3360 Register allocation_limit = scratch2; | 3360 Register allocation_limit = scratch2; |
| 3361 Mov(top_address, Operand(heap_allocation_top)); | 3361 Mov(top_address, Operand(heap_allocation_top)); |
| 3362 | 3362 |
| 3363 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 3363 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 3364 // Load allocation top into result and the allocation limit. | 3364 // Load allocation top into result and the allocation limit. |
| 3365 Ldp(result, allocation_limit, MemOperand(top_address)); | 3365 Ldp(result, allocation_limit, MemOperand(top_address)); |
| 3366 } else { | 3366 } else { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3405 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L); | 3405 Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L); |
| 3406 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L); | 3406 Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L); |
| 3407 } | 3407 } |
| 3408 B(gc_required); | 3408 B(gc_required); |
| 3409 return; | 3409 return; |
| 3410 } | 3410 } |
| 3411 | 3411 |
| 3412 UseScratchRegisterScope temps(this); | 3412 UseScratchRegisterScope temps(this); |
| 3413 Register scratch3 = temps.AcquireX(); | 3413 Register scratch3 = temps.AcquireX(); |
| 3414 | 3414 |
| 3415 ASSERT(!AreAliased(object_size, result, scratch1, scratch2, scratch3)); | 3415 DCHECK(!AreAliased(object_size, result, scratch1, scratch2, scratch3)); |
| 3416 ASSERT(object_size.Is64Bits() && result.Is64Bits() && | 3416 DCHECK(object_size.Is64Bits() && result.Is64Bits() && |
| 3417 scratch1.Is64Bits() && scratch2.Is64Bits()); | 3417 scratch1.Is64Bits() && scratch2.Is64Bits()); |
| 3418 | 3418 |
| 3419 // Check relative positions of allocation top and limit addresses. | 3419 // Check relative positions of allocation top and limit addresses. |
| 3420 // The values must be adjacent in memory to allow the use of LDP. | 3420 // The values must be adjacent in memory to allow the use of LDP. |
| 3421 ExternalReference heap_allocation_top = | 3421 ExternalReference heap_allocation_top = |
| 3422 AllocationUtils::GetAllocationTopReference(isolate(), flags); | 3422 AllocationUtils::GetAllocationTopReference(isolate(), flags); |
| 3423 ExternalReference heap_allocation_limit = | 3423 ExternalReference heap_allocation_limit = |
| 3424 AllocationUtils::GetAllocationLimitReference(isolate(), flags); | 3424 AllocationUtils::GetAllocationLimitReference(isolate(), flags); |
| 3425 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); | 3425 intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address()); |
| 3426 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); | 3426 intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address()); |
| 3427 ASSERT((limit - top) == kPointerSize); | 3427 DCHECK((limit - top) == kPointerSize); |
| 3428 | 3428 |
| 3429 // Set up allocation top address and object size registers. | 3429 // Set up allocation top address and object size registers. |
| 3430 Register top_address = scratch1; | 3430 Register top_address = scratch1; |
| 3431 Register allocation_limit = scratch2; | 3431 Register allocation_limit = scratch2; |
| 3432 Mov(top_address, heap_allocation_top); | 3432 Mov(top_address, heap_allocation_top); |
| 3433 | 3433 |
| 3434 if ((flags & RESULT_CONTAINS_TOP) == 0) { | 3434 if ((flags & RESULT_CONTAINS_TOP) == 0) { |
| 3435 // Load allocation top into result and the allocation limit. | 3435 // Load allocation top into result and the allocation limit. |
| 3436 Ldp(result, allocation_limit, MemOperand(top_address)); | 3436 Ldp(result, allocation_limit, MemOperand(top_address)); |
| 3437 } else { | 3437 } else { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3491 Str(object, MemOperand(scratch)); | 3491 Str(object, MemOperand(scratch)); |
| 3492 } | 3492 } |
| 3493 | 3493 |
| 3494 | 3494 |
| 3495 void MacroAssembler::AllocateTwoByteString(Register result, | 3495 void MacroAssembler::AllocateTwoByteString(Register result, |
| 3496 Register length, | 3496 Register length, |
| 3497 Register scratch1, | 3497 Register scratch1, |
| 3498 Register scratch2, | 3498 Register scratch2, |
| 3499 Register scratch3, | 3499 Register scratch3, |
| 3500 Label* gc_required) { | 3500 Label* gc_required) { |
| 3501 ASSERT(!AreAliased(result, length, scratch1, scratch2, scratch3)); | 3501 DCHECK(!AreAliased(result, length, scratch1, scratch2, scratch3)); |
| 3502 // Calculate the number of bytes needed for the characters in the string while | 3502 // Calculate the number of bytes needed for the characters in the string while |
| 3503 // observing object alignment. | 3503 // observing object alignment. |
| 3504 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 3504 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 3505 Add(scratch1, length, length); // Length in bytes, not chars. | 3505 Add(scratch1, length, length); // Length in bytes, not chars. |
| 3506 Add(scratch1, scratch1, kObjectAlignmentMask + SeqTwoByteString::kHeaderSize); | 3506 Add(scratch1, scratch1, kObjectAlignmentMask + SeqTwoByteString::kHeaderSize); |
| 3507 Bic(scratch1, scratch1, kObjectAlignmentMask); | 3507 Bic(scratch1, scratch1, kObjectAlignmentMask); |
| 3508 | 3508 |
| 3509 // Allocate two-byte string in new space. | 3509 // Allocate two-byte string in new space. |
| 3510 Allocate(scratch1, | 3510 Allocate(scratch1, |
| 3511 result, | 3511 result, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3522 scratch2); | 3522 scratch2); |
| 3523 } | 3523 } |
| 3524 | 3524 |
| 3525 | 3525 |
| 3526 void MacroAssembler::AllocateAsciiString(Register result, | 3526 void MacroAssembler::AllocateAsciiString(Register result, |
| 3527 Register length, | 3527 Register length, |
| 3528 Register scratch1, | 3528 Register scratch1, |
| 3529 Register scratch2, | 3529 Register scratch2, |
| 3530 Register scratch3, | 3530 Register scratch3, |
| 3531 Label* gc_required) { | 3531 Label* gc_required) { |
| 3532 ASSERT(!AreAliased(result, length, scratch1, scratch2, scratch3)); | 3532 DCHECK(!AreAliased(result, length, scratch1, scratch2, scratch3)); |
| 3533 // Calculate the number of bytes needed for the characters in the string while | 3533 // Calculate the number of bytes needed for the characters in the string while |
| 3534 // observing object alignment. | 3534 // observing object alignment. |
| 3535 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 3535 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 3536 STATIC_ASSERT(kCharSize == 1); | 3536 STATIC_ASSERT(kCharSize == 1); |
| 3537 Add(scratch1, length, kObjectAlignmentMask + SeqOneByteString::kHeaderSize); | 3537 Add(scratch1, length, kObjectAlignmentMask + SeqOneByteString::kHeaderSize); |
| 3538 Bic(scratch1, scratch1, kObjectAlignmentMask); | 3538 Bic(scratch1, scratch1, kObjectAlignmentMask); |
| 3539 | 3539 |
| 3540 // Allocate ASCII string in new space. | 3540 // Allocate ASCII string in new space. |
| 3541 Allocate(scratch1, | 3541 Allocate(scratch1, |
| 3542 result, | 3542 result, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3588 scratch1, | 3588 scratch1, |
| 3589 scratch2); | 3589 scratch2); |
| 3590 } | 3590 } |
| 3591 | 3591 |
| 3592 | 3592 |
| 3593 void MacroAssembler::AllocateTwoByteSlicedString(Register result, | 3593 void MacroAssembler::AllocateTwoByteSlicedString(Register result, |
| 3594 Register length, | 3594 Register length, |
| 3595 Register scratch1, | 3595 Register scratch1, |
| 3596 Register scratch2, | 3596 Register scratch2, |
| 3597 Label* gc_required) { | 3597 Label* gc_required) { |
| 3598 ASSERT(!AreAliased(result, length, scratch1, scratch2)); | 3598 DCHECK(!AreAliased(result, length, scratch1, scratch2)); |
| 3599 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, | 3599 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, |
| 3600 TAG_OBJECT); | 3600 TAG_OBJECT); |
| 3601 | 3601 |
| 3602 InitializeNewString(result, | 3602 InitializeNewString(result, |
| 3603 length, | 3603 length, |
| 3604 Heap::kSlicedStringMapRootIndex, | 3604 Heap::kSlicedStringMapRootIndex, |
| 3605 scratch1, | 3605 scratch1, |
| 3606 scratch2); | 3606 scratch2); |
| 3607 } | 3607 } |
| 3608 | 3608 |
| 3609 | 3609 |
| 3610 void MacroAssembler::AllocateAsciiSlicedString(Register result, | 3610 void MacroAssembler::AllocateAsciiSlicedString(Register result, |
| 3611 Register length, | 3611 Register length, |
| 3612 Register scratch1, | 3612 Register scratch1, |
| 3613 Register scratch2, | 3613 Register scratch2, |
| 3614 Label* gc_required) { | 3614 Label* gc_required) { |
| 3615 ASSERT(!AreAliased(result, length, scratch1, scratch2)); | 3615 DCHECK(!AreAliased(result, length, scratch1, scratch2)); |
| 3616 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, | 3616 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required, |
| 3617 TAG_OBJECT); | 3617 TAG_OBJECT); |
| 3618 | 3618 |
| 3619 InitializeNewString(result, | 3619 InitializeNewString(result, |
| 3620 length, | 3620 length, |
| 3621 Heap::kSlicedAsciiStringMapRootIndex, | 3621 Heap::kSlicedAsciiStringMapRootIndex, |
| 3622 scratch1, | 3622 scratch1, |
| 3623 scratch2); | 3623 scratch2); |
| 3624 } | 3624 } |
| 3625 | 3625 |
| 3626 | 3626 |
| 3627 // Allocates a heap number or jumps to the need_gc label if the young space | 3627 // Allocates a heap number or jumps to the need_gc label if the young space |
| 3628 // is full and a scavenge is needed. | 3628 // is full and a scavenge is needed. |
| 3629 void MacroAssembler::AllocateHeapNumber(Register result, | 3629 void MacroAssembler::AllocateHeapNumber(Register result, |
| 3630 Label* gc_required, | 3630 Label* gc_required, |
| 3631 Register scratch1, | 3631 Register scratch1, |
| 3632 Register scratch2, | 3632 Register scratch2, |
| 3633 CPURegister value, | 3633 CPURegister value, |
| 3634 CPURegister heap_number_map, | 3634 CPURegister heap_number_map, |
| 3635 MutableMode mode) { | 3635 MutableMode mode) { |
| 3636 ASSERT(!value.IsValid() || value.Is64Bits()); | 3636 DCHECK(!value.IsValid() || value.Is64Bits()); |
| 3637 UseScratchRegisterScope temps(this); | 3637 UseScratchRegisterScope temps(this); |
| 3638 | 3638 |
| 3639 // Allocate an object in the heap for the heap number and tag it as a heap | 3639 // Allocate an object in the heap for the heap number and tag it as a heap |
| 3640 // object. | 3640 // object. |
| 3641 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, | 3641 Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required, |
| 3642 NO_ALLOCATION_FLAGS); | 3642 NO_ALLOCATION_FLAGS); |
| 3643 | 3643 |
| 3644 Heap::RootListIndex map_index = mode == MUTABLE | 3644 Heap::RootListIndex map_index = mode == MUTABLE |
| 3645 ? Heap::kMutableHeapNumberMapRootIndex | 3645 ? Heap::kMutableHeapNumberMapRootIndex |
| 3646 : Heap::kHeapNumberMapRootIndex; | 3646 : Heap::kHeapNumberMapRootIndex; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 // Retrieve elements_kind from bit field 2. | 3807 // Retrieve elements_kind from bit field 2. |
| 3808 DecodeField<Map::ElementsKindBits>(result); | 3808 DecodeField<Map::ElementsKindBits>(result); |
| 3809 } | 3809 } |
| 3810 | 3810 |
| 3811 | 3811 |
| 3812 void MacroAssembler::TryGetFunctionPrototype(Register function, | 3812 void MacroAssembler::TryGetFunctionPrototype(Register function, |
| 3813 Register result, | 3813 Register result, |
| 3814 Register scratch, | 3814 Register scratch, |
| 3815 Label* miss, | 3815 Label* miss, |
| 3816 BoundFunctionAction action) { | 3816 BoundFunctionAction action) { |
| 3817 ASSERT(!AreAliased(function, result, scratch)); | 3817 DCHECK(!AreAliased(function, result, scratch)); |
| 3818 | 3818 |
| 3819 Label non_instance; | 3819 Label non_instance; |
| 3820 if (action == kMissOnBoundFunction) { | 3820 if (action == kMissOnBoundFunction) { |
| 3821 // Check that the receiver isn't a smi. | 3821 // Check that the receiver isn't a smi. |
| 3822 JumpIfSmi(function, miss); | 3822 JumpIfSmi(function, miss); |
| 3823 | 3823 |
| 3824 // Check that the function really is a function. Load map into result reg. | 3824 // Check that the function really is a function. Load map into result reg. |
| 3825 JumpIfNotObjectType(function, result, scratch, JS_FUNCTION_TYPE, miss); | 3825 JumpIfNotObjectType(function, result, scratch, JS_FUNCTION_TYPE, miss); |
| 3826 | 3826 |
| 3827 Register scratch_w = scratch.W(); | 3827 Register scratch_w = scratch.W(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3865 | 3865 |
| 3866 // All done. | 3866 // All done. |
| 3867 Bind(&done); | 3867 Bind(&done); |
| 3868 } | 3868 } |
| 3869 | 3869 |
| 3870 | 3870 |
| 3871 void MacroAssembler::CompareRoot(const Register& obj, | 3871 void MacroAssembler::CompareRoot(const Register& obj, |
| 3872 Heap::RootListIndex index) { | 3872 Heap::RootListIndex index) { |
| 3873 UseScratchRegisterScope temps(this); | 3873 UseScratchRegisterScope temps(this); |
| 3874 Register temp = temps.AcquireX(); | 3874 Register temp = temps.AcquireX(); |
| 3875 ASSERT(!AreAliased(obj, temp)); | 3875 DCHECK(!AreAliased(obj, temp)); |
| 3876 LoadRoot(temp, index); | 3876 LoadRoot(temp, index); |
| 3877 Cmp(obj, temp); | 3877 Cmp(obj, temp); |
| 3878 } | 3878 } |
| 3879 | 3879 |
| 3880 | 3880 |
| 3881 void MacroAssembler::JumpIfRoot(const Register& obj, | 3881 void MacroAssembler::JumpIfRoot(const Register& obj, |
| 3882 Heap::RootListIndex index, | 3882 Heap::RootListIndex index, |
| 3883 Label* if_equal) { | 3883 Label* if_equal) { |
| 3884 CompareRoot(obj, index); | 3884 CompareRoot(obj, index); |
| 3885 B(eq, if_equal); | 3885 B(eq, if_equal); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3966 | 3966 |
| 3967 // Note: The ARM version of this clobbers elements_reg, but this version does | 3967 // Note: The ARM version of this clobbers elements_reg, but this version does |
| 3968 // not. Some uses of this in ARM64 assume that elements_reg will be preserved. | 3968 // not. Some uses of this in ARM64 assume that elements_reg will be preserved. |
| 3969 void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, | 3969 void MacroAssembler::StoreNumberToDoubleElements(Register value_reg, |
| 3970 Register key_reg, | 3970 Register key_reg, |
| 3971 Register elements_reg, | 3971 Register elements_reg, |
| 3972 Register scratch1, | 3972 Register scratch1, |
| 3973 FPRegister fpscratch1, | 3973 FPRegister fpscratch1, |
| 3974 Label* fail, | 3974 Label* fail, |
| 3975 int elements_offset) { | 3975 int elements_offset) { |
| 3976 ASSERT(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); | 3976 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1)); |
| 3977 Label store_num; | 3977 Label store_num; |
| 3978 | 3978 |
| 3979 // Speculatively convert the smi to a double - all smis can be exactly | 3979 // Speculatively convert the smi to a double - all smis can be exactly |
| 3980 // represented as a double. | 3980 // represented as a double. |
| 3981 SmiUntagToDouble(fpscratch1, value_reg, kSpeculativeUntag); | 3981 SmiUntagToDouble(fpscratch1, value_reg, kSpeculativeUntag); |
| 3982 | 3982 |
| 3983 // If value_reg is a smi, we're done. | 3983 // If value_reg is a smi, we're done. |
| 3984 JumpIfSmi(value_reg, &store_num); | 3984 JumpIfSmi(value_reg, &store_num); |
| 3985 | 3985 |
| 3986 // Ensure that the object is a heap number. | 3986 // Ensure that the object is a heap number. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4005 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { | 4005 bool MacroAssembler::AllowThisStubCall(CodeStub* stub) { |
| 4006 return has_frame_ || !stub->SometimesSetsUpAFrame(); | 4006 return has_frame_ || !stub->SometimesSetsUpAFrame(); |
| 4007 } | 4007 } |
| 4008 | 4008 |
| 4009 | 4009 |
| 4010 void MacroAssembler::IndexFromHash(Register hash, Register index) { | 4010 void MacroAssembler::IndexFromHash(Register hash, Register index) { |
| 4011 // If the hash field contains an array index pick it out. The assert checks | 4011 // If the hash field contains an array index pick it out. The assert checks |
| 4012 // that the constants for the maximum number of digits for an array index | 4012 // that the constants for the maximum number of digits for an array index |
| 4013 // cached in the hash field and the number of bits reserved for it does not | 4013 // cached in the hash field and the number of bits reserved for it does not |
| 4014 // conflict. | 4014 // conflict. |
| 4015 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | 4015 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 4016 (1 << String::kArrayIndexValueBits)); | 4016 (1 << String::kArrayIndexValueBits)); |
| 4017 DecodeField<String::ArrayIndexValueBits>(index, hash); | 4017 DecodeField<String::ArrayIndexValueBits>(index, hash); |
| 4018 SmiTag(index, index); | 4018 SmiTag(index, index); |
| 4019 } | 4019 } |
| 4020 | 4020 |
| 4021 | 4021 |
| 4022 void MacroAssembler::EmitSeqStringSetCharCheck( | 4022 void MacroAssembler::EmitSeqStringSetCharCheck( |
| 4023 Register string, | 4023 Register string, |
| 4024 Register index, | 4024 Register index, |
| 4025 SeqStringSetCharCheckIndexType index_type, | 4025 SeqStringSetCharCheckIndexType index_type, |
| 4026 Register scratch, | 4026 Register scratch, |
| 4027 uint32_t encoding_mask) { | 4027 uint32_t encoding_mask) { |
| 4028 ASSERT(!AreAliased(string, index, scratch)); | 4028 DCHECK(!AreAliased(string, index, scratch)); |
| 4029 | 4029 |
| 4030 if (index_type == kIndexIsSmi) { | 4030 if (index_type == kIndexIsSmi) { |
| 4031 AssertSmi(index); | 4031 AssertSmi(index); |
| 4032 } | 4032 } |
| 4033 | 4033 |
| 4034 // Check that string is an object. | 4034 // Check that string is an object. |
| 4035 AssertNotSmi(string, kNonObject); | 4035 AssertNotSmi(string, kNonObject); |
| 4036 | 4036 |
| 4037 // Check that string has an appropriate map. | 4037 // Check that string has an appropriate map. |
| 4038 Ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); | 4038 Ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset)); |
| 4039 Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 4039 Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 4040 | 4040 |
| 4041 And(scratch, scratch, kStringRepresentationMask | kStringEncodingMask); | 4041 And(scratch, scratch, kStringRepresentationMask | kStringEncodingMask); |
| 4042 Cmp(scratch, encoding_mask); | 4042 Cmp(scratch, encoding_mask); |
| 4043 Check(eq, kUnexpectedStringType); | 4043 Check(eq, kUnexpectedStringType); |
| 4044 | 4044 |
| 4045 Ldr(scratch, FieldMemOperand(string, String::kLengthOffset)); | 4045 Ldr(scratch, FieldMemOperand(string, String::kLengthOffset)); |
| 4046 Cmp(index, index_type == kIndexIsSmi ? scratch : Operand::UntagSmi(scratch)); | 4046 Cmp(index, index_type == kIndexIsSmi ? scratch : Operand::UntagSmi(scratch)); |
| 4047 Check(lt, kIndexIsTooLarge); | 4047 Check(lt, kIndexIsTooLarge); |
| 4048 | 4048 |
| 4049 ASSERT_EQ(0, Smi::FromInt(0)); | 4049 DCHECK_EQ(0, Smi::FromInt(0)); |
| 4050 Cmp(index, 0); | 4050 Cmp(index, 0); |
| 4051 Check(ge, kIndexIsNegative); | 4051 Check(ge, kIndexIsNegative); |
| 4052 } | 4052 } |
| 4053 | 4053 |
| 4054 | 4054 |
| 4055 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, | 4055 void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
| 4056 Register scratch1, | 4056 Register scratch1, |
| 4057 Register scratch2, | 4057 Register scratch2, |
| 4058 Label* miss) { | 4058 Label* miss) { |
| 4059 ASSERT(!AreAliased(holder_reg, scratch1, scratch2)); | 4059 DCHECK(!AreAliased(holder_reg, scratch1, scratch2)); |
| 4060 Label same_contexts; | 4060 Label same_contexts; |
| 4061 | 4061 |
| 4062 // Load current lexical context from the stack frame. | 4062 // Load current lexical context from the stack frame. |
| 4063 Ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4063 Ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4064 // In debug mode, make sure the lexical context is set. | 4064 // In debug mode, make sure the lexical context is set. |
| 4065 #ifdef DEBUG | 4065 #ifdef DEBUG |
| 4066 Cmp(scratch1, 0); | 4066 Cmp(scratch1, 0); |
| 4067 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); | 4067 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext); |
| 4068 #endif | 4068 #endif |
| 4069 | 4069 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4114 B(miss, ne); | 4114 B(miss, ne); |
| 4115 | 4115 |
| 4116 Bind(&same_contexts); | 4116 Bind(&same_contexts); |
| 4117 } | 4117 } |
| 4118 | 4118 |
| 4119 | 4119 |
| 4120 // Compute the hash code from the untagged key. This must be kept in sync with | 4120 // Compute the hash code from the untagged key. This must be kept in sync with |
| 4121 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in | 4121 // ComputeIntegerHash in utils.h and KeyedLoadGenericStub in |
| 4122 // code-stub-hydrogen.cc | 4122 // code-stub-hydrogen.cc |
| 4123 void MacroAssembler::GetNumberHash(Register key, Register scratch) { | 4123 void MacroAssembler::GetNumberHash(Register key, Register scratch) { |
| 4124 ASSERT(!AreAliased(key, scratch)); | 4124 DCHECK(!AreAliased(key, scratch)); |
| 4125 | 4125 |
| 4126 // Xor original key with a seed. | 4126 // Xor original key with a seed. |
| 4127 LoadRoot(scratch, Heap::kHashSeedRootIndex); | 4127 LoadRoot(scratch, Heap::kHashSeedRootIndex); |
| 4128 Eor(key, key, Operand::UntagSmi(scratch)); | 4128 Eor(key, key, Operand::UntagSmi(scratch)); |
| 4129 | 4129 |
| 4130 // The algorithm uses 32-bit integer values. | 4130 // The algorithm uses 32-bit integer values. |
| 4131 key = key.W(); | 4131 key = key.W(); |
| 4132 scratch = scratch.W(); | 4132 scratch = scratch.W(); |
| 4133 | 4133 |
| 4134 // Compute the hash code from the untagged key. This must be kept in sync | 4134 // Compute the hash code from the untagged key. This must be kept in sync |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4153 | 4153 |
| 4154 | 4154 |
| 4155 void MacroAssembler::LoadFromNumberDictionary(Label* miss, | 4155 void MacroAssembler::LoadFromNumberDictionary(Label* miss, |
| 4156 Register elements, | 4156 Register elements, |
| 4157 Register key, | 4157 Register key, |
| 4158 Register result, | 4158 Register result, |
| 4159 Register scratch0, | 4159 Register scratch0, |
| 4160 Register scratch1, | 4160 Register scratch1, |
| 4161 Register scratch2, | 4161 Register scratch2, |
| 4162 Register scratch3) { | 4162 Register scratch3) { |
| 4163 ASSERT(!AreAliased(elements, key, scratch0, scratch1, scratch2, scratch3)); | 4163 DCHECK(!AreAliased(elements, key, scratch0, scratch1, scratch2, scratch3)); |
| 4164 | 4164 |
| 4165 Label done; | 4165 Label done; |
| 4166 | 4166 |
| 4167 SmiUntag(scratch0, key); | 4167 SmiUntag(scratch0, key); |
| 4168 GetNumberHash(scratch0, scratch1); | 4168 GetNumberHash(scratch0, scratch1); |
| 4169 | 4169 |
| 4170 // Compute the capacity mask. | 4170 // Compute the capacity mask. |
| 4171 Ldrsw(scratch1, | 4171 Ldrsw(scratch1, |
| 4172 UntagSmiFieldMemOperand(elements, | 4172 UntagSmiFieldMemOperand(elements, |
| 4173 SeededNumberDictionary::kCapacityOffset)); | 4173 SeededNumberDictionary::kCapacityOffset)); |
| 4174 Sub(scratch1, scratch1, 1); | 4174 Sub(scratch1, scratch1, 1); |
| 4175 | 4175 |
| 4176 // Generate an unrolled loop that performs a few probes before giving up. | 4176 // Generate an unrolled loop that performs a few probes before giving up. |
| 4177 for (int i = 0; i < kNumberDictionaryProbes; i++) { | 4177 for (int i = 0; i < kNumberDictionaryProbes; i++) { |
| 4178 // Compute the masked index: (hash + i + i * i) & mask. | 4178 // Compute the masked index: (hash + i + i * i) & mask. |
| 4179 if (i > 0) { | 4179 if (i > 0) { |
| 4180 Add(scratch2, scratch0, SeededNumberDictionary::GetProbeOffset(i)); | 4180 Add(scratch2, scratch0, SeededNumberDictionary::GetProbeOffset(i)); |
| 4181 } else { | 4181 } else { |
| 4182 Mov(scratch2, scratch0); | 4182 Mov(scratch2, scratch0); |
| 4183 } | 4183 } |
| 4184 And(scratch2, scratch2, scratch1); | 4184 And(scratch2, scratch2, scratch1); |
| 4185 | 4185 |
| 4186 // Scale the index by multiplying by the element size. | 4186 // Scale the index by multiplying by the element size. |
| 4187 ASSERT(SeededNumberDictionary::kEntrySize == 3); | 4187 DCHECK(SeededNumberDictionary::kEntrySize == 3); |
| 4188 Add(scratch2, scratch2, Operand(scratch2, LSL, 1)); | 4188 Add(scratch2, scratch2, Operand(scratch2, LSL, 1)); |
| 4189 | 4189 |
| 4190 // Check if the key is identical to the name. | 4190 // Check if the key is identical to the name. |
| 4191 Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2)); | 4191 Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2)); |
| 4192 Ldr(scratch3, | 4192 Ldr(scratch3, |
| 4193 FieldMemOperand(scratch2, | 4193 FieldMemOperand(scratch2, |
| 4194 SeededNumberDictionary::kElementsStartOffset)); | 4194 SeededNumberDictionary::kElementsStartOffset)); |
| 4195 Cmp(key, scratch3); | 4195 Cmp(key, scratch3); |
| 4196 if (i != (kNumberDictionaryProbes - 1)) { | 4196 if (i != (kNumberDictionaryProbes - 1)) { |
| 4197 B(eq, &done); | 4197 B(eq, &done); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4212 SeededNumberDictionary::kElementsStartOffset + kPointerSize; | 4212 SeededNumberDictionary::kElementsStartOffset + kPointerSize; |
| 4213 Ldr(result, FieldMemOperand(scratch2, kValueOffset)); | 4213 Ldr(result, FieldMemOperand(scratch2, kValueOffset)); |
| 4214 } | 4214 } |
| 4215 | 4215 |
| 4216 | 4216 |
| 4217 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. | 4217 void MacroAssembler::RememberedSetHelper(Register object, // For debug tests. |
| 4218 Register address, | 4218 Register address, |
| 4219 Register scratch1, | 4219 Register scratch1, |
| 4220 SaveFPRegsMode fp_mode, | 4220 SaveFPRegsMode fp_mode, |
| 4221 RememberedSetFinalAction and_then) { | 4221 RememberedSetFinalAction and_then) { |
| 4222 ASSERT(!AreAliased(object, address, scratch1)); | 4222 DCHECK(!AreAliased(object, address, scratch1)); |
| 4223 Label done, store_buffer_overflow; | 4223 Label done, store_buffer_overflow; |
| 4224 if (emit_debug_code()) { | 4224 if (emit_debug_code()) { |
| 4225 Label ok; | 4225 Label ok; |
| 4226 JumpIfNotInNewSpace(object, &ok); | 4226 JumpIfNotInNewSpace(object, &ok); |
| 4227 Abort(kRememberedSetPointerInNewSpace); | 4227 Abort(kRememberedSetPointerInNewSpace); |
| 4228 bind(&ok); | 4228 bind(&ok); |
| 4229 } | 4229 } |
| 4230 UseScratchRegisterScope temps(this); | 4230 UseScratchRegisterScope temps(this); |
| 4231 Register scratch2 = temps.AcquireX(); | 4231 Register scratch2 = temps.AcquireX(); |
| 4232 | 4232 |
| 4233 // Load store buffer top. | 4233 // Load store buffer top. |
| 4234 Mov(scratch2, ExternalReference::store_buffer_top(isolate())); | 4234 Mov(scratch2, ExternalReference::store_buffer_top(isolate())); |
| 4235 Ldr(scratch1, MemOperand(scratch2)); | 4235 Ldr(scratch1, MemOperand(scratch2)); |
| 4236 // Store pointer to buffer and increment buffer top. | 4236 // Store pointer to buffer and increment buffer top. |
| 4237 Str(address, MemOperand(scratch1, kPointerSize, PostIndex)); | 4237 Str(address, MemOperand(scratch1, kPointerSize, PostIndex)); |
| 4238 // Write back new top of buffer. | 4238 // Write back new top of buffer. |
| 4239 Str(scratch1, MemOperand(scratch2)); | 4239 Str(scratch1, MemOperand(scratch2)); |
| 4240 // Call stub on end of buffer. | 4240 // Call stub on end of buffer. |
| 4241 // Check for end of buffer. | 4241 // Check for end of buffer. |
| 4242 ASSERT(StoreBuffer::kStoreBufferOverflowBit == | 4242 DCHECK(StoreBuffer::kStoreBufferOverflowBit == |
| 4243 (1 << (14 + kPointerSizeLog2))); | 4243 (1 << (14 + kPointerSizeLog2))); |
| 4244 if (and_then == kFallThroughAtEnd) { | 4244 if (and_then == kFallThroughAtEnd) { |
| 4245 Tbz(scratch1, (14 + kPointerSizeLog2), &done); | 4245 Tbz(scratch1, (14 + kPointerSizeLog2), &done); |
| 4246 } else { | 4246 } else { |
| 4247 ASSERT(and_then == kReturnAtEnd); | 4247 DCHECK(and_then == kReturnAtEnd); |
| 4248 Tbnz(scratch1, (14 + kPointerSizeLog2), &store_buffer_overflow); | 4248 Tbnz(scratch1, (14 + kPointerSizeLog2), &store_buffer_overflow); |
| 4249 Ret(); | 4249 Ret(); |
| 4250 } | 4250 } |
| 4251 | 4251 |
| 4252 Bind(&store_buffer_overflow); | 4252 Bind(&store_buffer_overflow); |
| 4253 Push(lr); | 4253 Push(lr); |
| 4254 StoreBufferOverflowStub store_buffer_overflow_stub = | 4254 StoreBufferOverflowStub store_buffer_overflow_stub = |
| 4255 StoreBufferOverflowStub(isolate(), fp_mode); | 4255 StoreBufferOverflowStub(isolate(), fp_mode); |
| 4256 CallStub(&store_buffer_overflow_stub); | 4256 CallStub(&store_buffer_overflow_stub); |
| 4257 Pop(lr); | 4257 Pop(lr); |
| 4258 | 4258 |
| 4259 Bind(&done); | 4259 Bind(&done); |
| 4260 if (and_then == kReturnAtEnd) { | 4260 if (and_then == kReturnAtEnd) { |
| 4261 Ret(); | 4261 Ret(); |
| 4262 } | 4262 } |
| 4263 } | 4263 } |
| 4264 | 4264 |
| 4265 | 4265 |
| 4266 void MacroAssembler::PopSafepointRegisters() { | 4266 void MacroAssembler::PopSafepointRegisters() { |
| 4267 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 4267 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
| 4268 PopXRegList(kSafepointSavedRegisters); | 4268 PopXRegList(kSafepointSavedRegisters); |
| 4269 Drop(num_unsaved); | 4269 Drop(num_unsaved); |
| 4270 } | 4270 } |
| 4271 | 4271 |
| 4272 | 4272 |
| 4273 void MacroAssembler::PushSafepointRegisters() { | 4273 void MacroAssembler::PushSafepointRegisters() { |
| 4274 // Safepoints expect a block of kNumSafepointRegisters values on the stack, so | 4274 // Safepoints expect a block of kNumSafepointRegisters values on the stack, so |
| 4275 // adjust the stack for unsaved registers. | 4275 // adjust the stack for unsaved registers. |
| 4276 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; | 4276 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters; |
| 4277 ASSERT(num_unsaved >= 0); | 4277 DCHECK(num_unsaved >= 0); |
| 4278 Claim(num_unsaved); | 4278 Claim(num_unsaved); |
| 4279 PushXRegList(kSafepointSavedRegisters); | 4279 PushXRegList(kSafepointSavedRegisters); |
| 4280 } | 4280 } |
| 4281 | 4281 |
| 4282 | 4282 |
| 4283 void MacroAssembler::PushSafepointRegistersAndDoubles() { | 4283 void MacroAssembler::PushSafepointRegistersAndDoubles() { |
| 4284 PushSafepointRegisters(); | 4284 PushSafepointRegisters(); |
| 4285 PushCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, | 4285 PushCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, |
| 4286 FPRegister::kAllocatableFPRegisters)); | 4286 FPRegister::kAllocatableFPRegisters)); |
| 4287 } | 4287 } |
| 4288 | 4288 |
| 4289 | 4289 |
| 4290 void MacroAssembler::PopSafepointRegistersAndDoubles() { | 4290 void MacroAssembler::PopSafepointRegistersAndDoubles() { |
| 4291 PopCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, | 4291 PopCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, |
| 4292 FPRegister::kAllocatableFPRegisters)); | 4292 FPRegister::kAllocatableFPRegisters)); |
| 4293 PopSafepointRegisters(); | 4293 PopSafepointRegisters(); |
| 4294 } | 4294 } |
| 4295 | 4295 |
| 4296 | 4296 |
| 4297 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { | 4297 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) { |
| 4298 // Make sure the safepoint registers list is what we expect. | 4298 // Make sure the safepoint registers list is what we expect. |
| 4299 ASSERT(CPURegList::GetSafepointSavedRegisters().list() == 0x6ffcffff); | 4299 DCHECK(CPURegList::GetSafepointSavedRegisters().list() == 0x6ffcffff); |
| 4300 | 4300 |
| 4301 // Safepoint registers are stored contiguously on the stack, but not all the | 4301 // Safepoint registers are stored contiguously on the stack, but not all the |
| 4302 // registers are saved. The following registers are excluded: | 4302 // registers are saved. The following registers are excluded: |
| 4303 // - x16 and x17 (ip0 and ip1) because they shouldn't be preserved outside of | 4303 // - x16 and x17 (ip0 and ip1) because they shouldn't be preserved outside of |
| 4304 // the macro assembler. | 4304 // the macro assembler. |
| 4305 // - x28 (jssp) because JS stack pointer doesn't need to be included in | 4305 // - x28 (jssp) because JS stack pointer doesn't need to be included in |
| 4306 // safepoint registers. | 4306 // safepoint registers. |
| 4307 // - x31 (csp) because the system stack pointer doesn't need to be included | 4307 // - x31 (csp) because the system stack pointer doesn't need to be included |
| 4308 // in safepoint registers. | 4308 // in safepoint registers. |
| 4309 // | 4309 // |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4359 // catch stores of Smis. | 4359 // catch stores of Smis. |
| 4360 Label done; | 4360 Label done; |
| 4361 | 4361 |
| 4362 // Skip the barrier if writing a smi. | 4362 // Skip the barrier if writing a smi. |
| 4363 if (smi_check == INLINE_SMI_CHECK) { | 4363 if (smi_check == INLINE_SMI_CHECK) { |
| 4364 JumpIfSmi(value, &done); | 4364 JumpIfSmi(value, &done); |
| 4365 } | 4365 } |
| 4366 | 4366 |
| 4367 // Although the object register is tagged, the offset is relative to the start | 4367 // Although the object register is tagged, the offset is relative to the start |
| 4368 // of the object, so offset must be a multiple of kPointerSize. | 4368 // of the object, so offset must be a multiple of kPointerSize. |
| 4369 ASSERT(IsAligned(offset, kPointerSize)); | 4369 DCHECK(IsAligned(offset, kPointerSize)); |
| 4370 | 4370 |
| 4371 Add(scratch, object, offset - kHeapObjectTag); | 4371 Add(scratch, object, offset - kHeapObjectTag); |
| 4372 if (emit_debug_code()) { | 4372 if (emit_debug_code()) { |
| 4373 Label ok; | 4373 Label ok; |
| 4374 Tst(scratch, (1 << kPointerSizeLog2) - 1); | 4374 Tst(scratch, (1 << kPointerSizeLog2) - 1); |
| 4375 B(eq, &ok); | 4375 B(eq, &ok); |
| 4376 Abort(kUnalignedCellInWriteBarrier); | 4376 Abort(kUnalignedCellInWriteBarrier); |
| 4377 Bind(&ok); | 4377 Bind(&ok); |
| 4378 } | 4378 } |
| 4379 | 4379 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 4398 | 4398 |
| 4399 | 4399 |
| 4400 // Will clobber: object, map, dst. | 4400 // Will clobber: object, map, dst. |
| 4401 // If lr_status is kLRHasBeenSaved, lr will also be clobbered. | 4401 // If lr_status is kLRHasBeenSaved, lr will also be clobbered. |
| 4402 void MacroAssembler::RecordWriteForMap(Register object, | 4402 void MacroAssembler::RecordWriteForMap(Register object, |
| 4403 Register map, | 4403 Register map, |
| 4404 Register dst, | 4404 Register dst, |
| 4405 LinkRegisterStatus lr_status, | 4405 LinkRegisterStatus lr_status, |
| 4406 SaveFPRegsMode fp_mode) { | 4406 SaveFPRegsMode fp_mode) { |
| 4407 ASM_LOCATION("MacroAssembler::RecordWrite"); | 4407 ASM_LOCATION("MacroAssembler::RecordWrite"); |
| 4408 ASSERT(!AreAliased(object, map)); | 4408 DCHECK(!AreAliased(object, map)); |
| 4409 | 4409 |
| 4410 if (emit_debug_code()) { | 4410 if (emit_debug_code()) { |
| 4411 UseScratchRegisterScope temps(this); | 4411 UseScratchRegisterScope temps(this); |
| 4412 Register temp = temps.AcquireX(); | 4412 Register temp = temps.AcquireX(); |
| 4413 | 4413 |
| 4414 CompareMap(map, temp, isolate()->factory()->meta_map()); | 4414 CompareMap(map, temp, isolate()->factory()->meta_map()); |
| 4415 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 4415 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 4416 } | 4416 } |
| 4417 | 4417 |
| 4418 if (!FLAG_incremental_marking) { | 4418 if (!FLAG_incremental_marking) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4477 void MacroAssembler::RecordWrite( | 4477 void MacroAssembler::RecordWrite( |
| 4478 Register object, | 4478 Register object, |
| 4479 Register address, | 4479 Register address, |
| 4480 Register value, | 4480 Register value, |
| 4481 LinkRegisterStatus lr_status, | 4481 LinkRegisterStatus lr_status, |
| 4482 SaveFPRegsMode fp_mode, | 4482 SaveFPRegsMode fp_mode, |
| 4483 RememberedSetAction remembered_set_action, | 4483 RememberedSetAction remembered_set_action, |
| 4484 SmiCheck smi_check, | 4484 SmiCheck smi_check, |
| 4485 PointersToHereCheck pointers_to_here_check_for_value) { | 4485 PointersToHereCheck pointers_to_here_check_for_value) { |
| 4486 ASM_LOCATION("MacroAssembler::RecordWrite"); | 4486 ASM_LOCATION("MacroAssembler::RecordWrite"); |
| 4487 ASSERT(!AreAliased(object, value)); | 4487 DCHECK(!AreAliased(object, value)); |
| 4488 | 4488 |
| 4489 if (emit_debug_code()) { | 4489 if (emit_debug_code()) { |
| 4490 UseScratchRegisterScope temps(this); | 4490 UseScratchRegisterScope temps(this); |
| 4491 Register temp = temps.AcquireX(); | 4491 Register temp = temps.AcquireX(); |
| 4492 | 4492 |
| 4493 Ldr(temp, MemOperand(address)); | 4493 Ldr(temp, MemOperand(address)); |
| 4494 Cmp(temp, value); | 4494 Cmp(temp, value); |
| 4495 Check(eq, kWrongAddressOrValuePassedToRecordWrite); | 4495 Check(eq, kWrongAddressOrValuePassedToRecordWrite); |
| 4496 } | 4496 } |
| 4497 | 4497 |
| 4498 // First, check if a write barrier is even needed. The tests below | 4498 // First, check if a write barrier is even needed. The tests below |
| 4499 // catch stores of smis and stores into the young generation. | 4499 // catch stores of smis and stores into the young generation. |
| 4500 Label done; | 4500 Label done; |
| 4501 | 4501 |
| 4502 if (smi_check == INLINE_SMI_CHECK) { | 4502 if (smi_check == INLINE_SMI_CHECK) { |
| 4503 ASSERT_EQ(0, kSmiTag); | 4503 DCHECK_EQ(0, kSmiTag); |
| 4504 JumpIfSmi(value, &done); | 4504 JumpIfSmi(value, &done); |
| 4505 } | 4505 } |
| 4506 | 4506 |
| 4507 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { | 4507 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) { |
| 4508 CheckPageFlagClear(value, | 4508 CheckPageFlagClear(value, |
| 4509 value, // Used as scratch. | 4509 value, // Used as scratch. |
| 4510 MemoryChunk::kPointersToHereAreInterestingMask, | 4510 MemoryChunk::kPointersToHereAreInterestingMask, |
| 4511 &done); | 4511 &done); |
| 4512 } | 4512 } |
| 4513 CheckPageFlagClear(object, | 4513 CheckPageFlagClear(object, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 4539 Mov(address, Operand(BitCast<int64_t>(kZapValue + 12))); | 4539 Mov(address, Operand(BitCast<int64_t>(kZapValue + 12))); |
| 4540 Mov(value, Operand(BitCast<int64_t>(kZapValue + 16))); | 4540 Mov(value, Operand(BitCast<int64_t>(kZapValue + 16))); |
| 4541 } | 4541 } |
| 4542 } | 4542 } |
| 4543 | 4543 |
| 4544 | 4544 |
| 4545 void MacroAssembler::AssertHasValidColor(const Register& reg) { | 4545 void MacroAssembler::AssertHasValidColor(const Register& reg) { |
| 4546 if (emit_debug_code()) { | 4546 if (emit_debug_code()) { |
| 4547 // The bit sequence is backward. The first character in the string | 4547 // The bit sequence is backward. The first character in the string |
| 4548 // represents the least significant bit. | 4548 // represents the least significant bit. |
| 4549 ASSERT(strcmp(Marking::kImpossibleBitPattern, "01") == 0); | 4549 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0); |
| 4550 | 4550 |
| 4551 Label color_is_valid; | 4551 Label color_is_valid; |
| 4552 Tbnz(reg, 0, &color_is_valid); | 4552 Tbnz(reg, 0, &color_is_valid); |
| 4553 Tbz(reg, 1, &color_is_valid); | 4553 Tbz(reg, 1, &color_is_valid); |
| 4554 Abort(kUnexpectedColorFound); | 4554 Abort(kUnexpectedColorFound); |
| 4555 Bind(&color_is_valid); | 4555 Bind(&color_is_valid); |
| 4556 } | 4556 } |
| 4557 } | 4557 } |
| 4558 | 4558 |
| 4559 | 4559 |
| 4560 void MacroAssembler::GetMarkBits(Register addr_reg, | 4560 void MacroAssembler::GetMarkBits(Register addr_reg, |
| 4561 Register bitmap_reg, | 4561 Register bitmap_reg, |
| 4562 Register shift_reg) { | 4562 Register shift_reg) { |
| 4563 ASSERT(!AreAliased(addr_reg, bitmap_reg, shift_reg)); | 4563 DCHECK(!AreAliased(addr_reg, bitmap_reg, shift_reg)); |
| 4564 ASSERT(addr_reg.Is64Bits() && bitmap_reg.Is64Bits() && shift_reg.Is64Bits()); | 4564 DCHECK(addr_reg.Is64Bits() && bitmap_reg.Is64Bits() && shift_reg.Is64Bits()); |
| 4565 // addr_reg is divided into fields: | 4565 // addr_reg is divided into fields: |
| 4566 // |63 page base 20|19 high 8|7 shift 3|2 0| | 4566 // |63 page base 20|19 high 8|7 shift 3|2 0| |
| 4567 // 'high' gives the index of the cell holding color bits for the object. | 4567 // 'high' gives the index of the cell holding color bits for the object. |
| 4568 // 'shift' gives the offset in the cell for this object's color. | 4568 // 'shift' gives the offset in the cell for this object's color. |
| 4569 const int kShiftBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; | 4569 const int kShiftBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2; |
| 4570 UseScratchRegisterScope temps(this); | 4570 UseScratchRegisterScope temps(this); |
| 4571 Register temp = temps.AcquireX(); | 4571 Register temp = temps.AcquireX(); |
| 4572 Ubfx(temp, addr_reg, kShiftBits, kPageSizeBits - kShiftBits); | 4572 Ubfx(temp, addr_reg, kShiftBits, kPageSizeBits - kShiftBits); |
| 4573 Bic(bitmap_reg, addr_reg, Page::kPageAlignmentMask); | 4573 Bic(bitmap_reg, addr_reg, Page::kPageAlignmentMask); |
| 4574 Add(bitmap_reg, bitmap_reg, Operand(temp, LSL, Bitmap::kBytesPerCellLog2)); | 4574 Add(bitmap_reg, bitmap_reg, Operand(temp, LSL, Bitmap::kBytesPerCellLog2)); |
| 4575 // bitmap_reg: | 4575 // bitmap_reg: |
| 4576 // |63 page base 20|19 zeros 15|14 high 3|2 0| | 4576 // |63 page base 20|19 zeros 15|14 high 3|2 0| |
| 4577 Ubfx(shift_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2); | 4577 Ubfx(shift_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2); |
| 4578 } | 4578 } |
| 4579 | 4579 |
| 4580 | 4580 |
| 4581 void MacroAssembler::HasColor(Register object, | 4581 void MacroAssembler::HasColor(Register object, |
| 4582 Register bitmap_scratch, | 4582 Register bitmap_scratch, |
| 4583 Register shift_scratch, | 4583 Register shift_scratch, |
| 4584 Label* has_color, | 4584 Label* has_color, |
| 4585 int first_bit, | 4585 int first_bit, |
| 4586 int second_bit) { | 4586 int second_bit) { |
| 4587 // See mark-compact.h for color definitions. | 4587 // See mark-compact.h for color definitions. |
| 4588 ASSERT(!AreAliased(object, bitmap_scratch, shift_scratch)); | 4588 DCHECK(!AreAliased(object, bitmap_scratch, shift_scratch)); |
| 4589 | 4589 |
| 4590 GetMarkBits(object, bitmap_scratch, shift_scratch); | 4590 GetMarkBits(object, bitmap_scratch, shift_scratch); |
| 4591 Ldr(bitmap_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); | 4591 Ldr(bitmap_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
| 4592 // Shift the bitmap down to get the color of the object in bits [1:0]. | 4592 // Shift the bitmap down to get the color of the object in bits [1:0]. |
| 4593 Lsr(bitmap_scratch, bitmap_scratch, shift_scratch); | 4593 Lsr(bitmap_scratch, bitmap_scratch, shift_scratch); |
| 4594 | 4594 |
| 4595 AssertHasValidColor(bitmap_scratch); | 4595 AssertHasValidColor(bitmap_scratch); |
| 4596 | 4596 |
| 4597 // These bit sequences are backwards. The first character in the string | 4597 // These bit sequences are backwards. The first character in the string |
| 4598 // represents the least significant bit. | 4598 // represents the least significant bit. |
| 4599 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); | 4599 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 4600 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); | 4600 DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0); |
| 4601 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); | 4601 DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0); |
| 4602 | 4602 |
| 4603 // Check for the color. | 4603 // Check for the color. |
| 4604 if (first_bit == 0) { | 4604 if (first_bit == 0) { |
| 4605 // Checking for white. | 4605 // Checking for white. |
| 4606 ASSERT(second_bit == 0); | 4606 DCHECK(second_bit == 0); |
| 4607 // We only need to test the first bit. | 4607 // We only need to test the first bit. |
| 4608 Tbz(bitmap_scratch, 0, has_color); | 4608 Tbz(bitmap_scratch, 0, has_color); |
| 4609 } else { | 4609 } else { |
| 4610 Label other_color; | 4610 Label other_color; |
| 4611 // Checking for grey or black. | 4611 // Checking for grey or black. |
| 4612 Tbz(bitmap_scratch, 0, &other_color); | 4612 Tbz(bitmap_scratch, 0, &other_color); |
| 4613 if (second_bit == 0) { | 4613 if (second_bit == 0) { |
| 4614 Tbz(bitmap_scratch, 1, has_color); | 4614 Tbz(bitmap_scratch, 1, has_color); |
| 4615 } else { | 4615 } else { |
| 4616 Tbnz(bitmap_scratch, 1, has_color); | 4616 Tbnz(bitmap_scratch, 1, has_color); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4630 Ldrsw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset)); | 4630 Ldrsw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset)); |
| 4631 TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, if_deprecated); | 4631 TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, if_deprecated); |
| 4632 } | 4632 } |
| 4633 } | 4633 } |
| 4634 | 4634 |
| 4635 | 4635 |
| 4636 void MacroAssembler::JumpIfBlack(Register object, | 4636 void MacroAssembler::JumpIfBlack(Register object, |
| 4637 Register scratch0, | 4637 Register scratch0, |
| 4638 Register scratch1, | 4638 Register scratch1, |
| 4639 Label* on_black) { | 4639 Label* on_black) { |
| 4640 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); | 4640 DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0); |
| 4641 HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern. | 4641 HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern. |
| 4642 } | 4642 } |
| 4643 | 4643 |
| 4644 | 4644 |
| 4645 void MacroAssembler::JumpIfDictionaryInPrototypeChain( | 4645 void MacroAssembler::JumpIfDictionaryInPrototypeChain( |
| 4646 Register object, | 4646 Register object, |
| 4647 Register scratch0, | 4647 Register scratch0, |
| 4648 Register scratch1, | 4648 Register scratch1, |
| 4649 Label* found) { | 4649 Label* found) { |
| 4650 ASSERT(!AreAliased(object, scratch0, scratch1)); | 4650 DCHECK(!AreAliased(object, scratch0, scratch1)); |
| 4651 Factory* factory = isolate()->factory(); | 4651 Factory* factory = isolate()->factory(); |
| 4652 Register current = scratch0; | 4652 Register current = scratch0; |
| 4653 Label loop_again; | 4653 Label loop_again; |
| 4654 | 4654 |
| 4655 // Scratch contains elements pointer. | 4655 // Scratch contains elements pointer. |
| 4656 Mov(current, object); | 4656 Mov(current, object); |
| 4657 | 4657 |
| 4658 // Loop based on the map going up the prototype chain. | 4658 // Loop based on the map going up the prototype chain. |
| 4659 Bind(&loop_again); | 4659 Bind(&loop_again); |
| 4660 Ldr(current, FieldMemOperand(current, HeapObject::kMapOffset)); | 4660 Ldr(current, FieldMemOperand(current, HeapObject::kMapOffset)); |
| 4661 Ldrb(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); | 4661 Ldrb(scratch1, FieldMemOperand(current, Map::kBitField2Offset)); |
| 4662 DecodeField<Map::ElementsKindBits>(scratch1); | 4662 DecodeField<Map::ElementsKindBits>(scratch1); |
| 4663 CompareAndBranch(scratch1, DICTIONARY_ELEMENTS, eq, found); | 4663 CompareAndBranch(scratch1, DICTIONARY_ELEMENTS, eq, found); |
| 4664 Ldr(current, FieldMemOperand(current, Map::kPrototypeOffset)); | 4664 Ldr(current, FieldMemOperand(current, Map::kPrototypeOffset)); |
| 4665 CompareAndBranch(current, Operand(factory->null_value()), ne, &loop_again); | 4665 CompareAndBranch(current, Operand(factory->null_value()), ne, &loop_again); |
| 4666 } | 4666 } |
| 4667 | 4667 |
| 4668 | 4668 |
| 4669 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, | 4669 void MacroAssembler::GetRelocatedValueLocation(Register ldr_location, |
| 4670 Register result) { | 4670 Register result) { |
| 4671 ASSERT(!result.Is(ldr_location)); | 4671 DCHECK(!result.Is(ldr_location)); |
| 4672 const uint32_t kLdrLitOffset_lsb = 5; | 4672 const uint32_t kLdrLitOffset_lsb = 5; |
| 4673 const uint32_t kLdrLitOffset_width = 19; | 4673 const uint32_t kLdrLitOffset_width = 19; |
| 4674 Ldr(result, MemOperand(ldr_location)); | 4674 Ldr(result, MemOperand(ldr_location)); |
| 4675 if (emit_debug_code()) { | 4675 if (emit_debug_code()) { |
| 4676 And(result, result, LoadLiteralFMask); | 4676 And(result, result, LoadLiteralFMask); |
| 4677 Cmp(result, LoadLiteralFixed); | 4677 Cmp(result, LoadLiteralFixed); |
| 4678 Check(eq, kTheInstructionToPatchShouldBeAnLdrLiteral); | 4678 Check(eq, kTheInstructionToPatchShouldBeAnLdrLiteral); |
| 4679 // The instruction was clobbered. Reload it. | 4679 // The instruction was clobbered. Reload it. |
| 4680 Ldr(result, MemOperand(ldr_location)); | 4680 Ldr(result, MemOperand(ldr_location)); |
| 4681 } | 4681 } |
| 4682 Sbfx(result, result, kLdrLitOffset_lsb, kLdrLitOffset_width); | 4682 Sbfx(result, result, kLdrLitOffset_lsb, kLdrLitOffset_width); |
| 4683 Add(result, ldr_location, Operand(result, LSL, kWordSizeInBytesLog2)); | 4683 Add(result, ldr_location, Operand(result, LSL, kWordSizeInBytesLog2)); |
| 4684 } | 4684 } |
| 4685 | 4685 |
| 4686 | 4686 |
| 4687 void MacroAssembler::EnsureNotWhite( | 4687 void MacroAssembler::EnsureNotWhite( |
| 4688 Register value, | 4688 Register value, |
| 4689 Register bitmap_scratch, | 4689 Register bitmap_scratch, |
| 4690 Register shift_scratch, | 4690 Register shift_scratch, |
| 4691 Register load_scratch, | 4691 Register load_scratch, |
| 4692 Register length_scratch, | 4692 Register length_scratch, |
| 4693 Label* value_is_white_and_not_data) { | 4693 Label* value_is_white_and_not_data) { |
| 4694 ASSERT(!AreAliased( | 4694 DCHECK(!AreAliased( |
| 4695 value, bitmap_scratch, shift_scratch, load_scratch, length_scratch)); | 4695 value, bitmap_scratch, shift_scratch, load_scratch, length_scratch)); |
| 4696 | 4696 |
| 4697 // These bit sequences are backwards. The first character in the string | 4697 // These bit sequences are backwards. The first character in the string |
| 4698 // represents the least significant bit. | 4698 // represents the least significant bit. |
| 4699 ASSERT(strcmp(Marking::kWhiteBitPattern, "00") == 0); | 4699 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0); |
| 4700 ASSERT(strcmp(Marking::kBlackBitPattern, "10") == 0); | 4700 DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0); |
| 4701 ASSERT(strcmp(Marking::kGreyBitPattern, "11") == 0); | 4701 DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0); |
| 4702 | 4702 |
| 4703 GetMarkBits(value, bitmap_scratch, shift_scratch); | 4703 GetMarkBits(value, bitmap_scratch, shift_scratch); |
| 4704 Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); | 4704 Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize)); |
| 4705 Lsr(load_scratch, load_scratch, shift_scratch); | 4705 Lsr(load_scratch, load_scratch, shift_scratch); |
| 4706 | 4706 |
| 4707 AssertHasValidColor(load_scratch); | 4707 AssertHasValidColor(load_scratch); |
| 4708 | 4708 |
| 4709 // If the value is black or grey we don't need to do anything. | 4709 // If the value is black or grey we don't need to do anything. |
| 4710 // Since both black and grey have a 1 in the first position and white does | 4710 // Since both black and grey have a 1 in the first position and white does |
| 4711 // not have a 1 there we only need to check one bit. | 4711 // not have a 1 there we only need to check one bit. |
| 4712 Label done; | 4712 Label done; |
| 4713 Tbnz(load_scratch, 0, &done); | 4713 Tbnz(load_scratch, 0, &done); |
| 4714 | 4714 |
| 4715 // Value is white. We check whether it is data that doesn't need scanning. | 4715 // Value is white. We check whether it is data that doesn't need scanning. |
| 4716 Register map = load_scratch; // Holds map while checking type. | 4716 Register map = load_scratch; // Holds map while checking type. |
| 4717 Label is_data_object; | 4717 Label is_data_object; |
| 4718 | 4718 |
| 4719 // Check for heap-number. | 4719 // Check for heap-number. |
| 4720 Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset)); | 4720 Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset)); |
| 4721 Mov(length_scratch, HeapNumber::kSize); | 4721 Mov(length_scratch, HeapNumber::kSize); |
| 4722 JumpIfRoot(map, Heap::kHeapNumberMapRootIndex, &is_data_object); | 4722 JumpIfRoot(map, Heap::kHeapNumberMapRootIndex, &is_data_object); |
| 4723 | 4723 |
| 4724 // Check for strings. | 4724 // Check for strings. |
| 4725 ASSERT(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1); | 4725 DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1); |
| 4726 ASSERT(kNotStringTag == 0x80 && kIsNotStringMask == 0x80); | 4726 DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80); |
| 4727 // If it's a string and it's not a cons string then it's an object containing | 4727 // If it's a string and it's not a cons string then it's an object containing |
| 4728 // no GC pointers. | 4728 // no GC pointers. |
| 4729 Register instance_type = load_scratch; | 4729 Register instance_type = load_scratch; |
| 4730 Ldrb(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 4730 Ldrb(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
| 4731 TestAndBranchIfAnySet(instance_type, | 4731 TestAndBranchIfAnySet(instance_type, |
| 4732 kIsIndirectStringMask | kIsNotStringMask, | 4732 kIsIndirectStringMask | kIsNotStringMask, |
| 4733 value_is_white_and_not_data); | 4733 value_is_white_and_not_data); |
| 4734 | 4734 |
| 4735 // It's a non-indirect (non-cons and non-slice) string. | 4735 // It's a non-indirect (non-cons and non-slice) string. |
| 4736 // If it's external, the length is just ExternalString::kSize. | 4736 // If it's external, the length is just ExternalString::kSize. |
| 4737 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2). | 4737 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2). |
| 4738 // External strings are the only ones with the kExternalStringTag bit | 4738 // External strings are the only ones with the kExternalStringTag bit |
| 4739 // set. | 4739 // set. |
| 4740 ASSERT_EQ(0, kSeqStringTag & kExternalStringTag); | 4740 DCHECK_EQ(0, kSeqStringTag & kExternalStringTag); |
| 4741 ASSERT_EQ(0, kConsStringTag & kExternalStringTag); | 4741 DCHECK_EQ(0, kConsStringTag & kExternalStringTag); |
| 4742 Mov(length_scratch, ExternalString::kSize); | 4742 Mov(length_scratch, ExternalString::kSize); |
| 4743 TestAndBranchIfAnySet(instance_type, kExternalStringTag, &is_data_object); | 4743 TestAndBranchIfAnySet(instance_type, kExternalStringTag, &is_data_object); |
| 4744 | 4744 |
| 4745 // Sequential string, either ASCII or UC16. | 4745 // Sequential string, either ASCII or UC16. |
| 4746 // For ASCII (char-size of 1) we shift the smi tag away to get the length. | 4746 // For ASCII (char-size of 1) we shift the smi tag away to get the length. |
| 4747 // For UC16 (char-size of 2) we just leave the smi tag in place, thereby | 4747 // For UC16 (char-size of 2) we just leave the smi tag in place, thereby |
| 4748 // getting the length multiplied by 2. | 4748 // getting the length multiplied by 2. |
| 4749 ASSERT(kOneByteStringTag == 4 && kStringEncodingMask == 4); | 4749 DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4); |
| 4750 Ldrsw(length_scratch, UntagSmiFieldMemOperand(value, | 4750 Ldrsw(length_scratch, UntagSmiFieldMemOperand(value, |
| 4751 String::kLengthOffset)); | 4751 String::kLengthOffset)); |
| 4752 Tst(instance_type, kStringEncodingMask); | 4752 Tst(instance_type, kStringEncodingMask); |
| 4753 Cset(load_scratch, eq); | 4753 Cset(load_scratch, eq); |
| 4754 Lsl(length_scratch, length_scratch, load_scratch); | 4754 Lsl(length_scratch, length_scratch, load_scratch); |
| 4755 Add(length_scratch, | 4755 Add(length_scratch, |
| 4756 length_scratch, | 4756 length_scratch, |
| 4757 SeqString::kHeaderSize + kObjectAlignmentMask); | 4757 SeqString::kHeaderSize + kObjectAlignmentMask); |
| 4758 Bic(length_scratch, length_scratch, kObjectAlignmentMask); | 4758 Bic(length_scratch, length_scratch, kObjectAlignmentMask); |
| 4759 | 4759 |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4965 | 4965 |
| 4966 // This is the main Printf implementation. All other Printf variants call | 4966 // This is the main Printf implementation. All other Printf variants call |
| 4967 // PrintfNoPreserve after setting up one or more PreserveRegisterScopes. | 4967 // PrintfNoPreserve after setting up one or more PreserveRegisterScopes. |
| 4968 void MacroAssembler::PrintfNoPreserve(const char * format, | 4968 void MacroAssembler::PrintfNoPreserve(const char * format, |
| 4969 const CPURegister& arg0, | 4969 const CPURegister& arg0, |
| 4970 const CPURegister& arg1, | 4970 const CPURegister& arg1, |
| 4971 const CPURegister& arg2, | 4971 const CPURegister& arg2, |
| 4972 const CPURegister& arg3) { | 4972 const CPURegister& arg3) { |
| 4973 // We cannot handle a caller-saved stack pointer. It doesn't make much sense | 4973 // We cannot handle a caller-saved stack pointer. It doesn't make much sense |
| 4974 // in most cases anyway, so this restriction shouldn't be too serious. | 4974 // in most cases anyway, so this restriction shouldn't be too serious. |
| 4975 ASSERT(!kCallerSaved.IncludesAliasOf(__ StackPointer())); | 4975 DCHECK(!kCallerSaved.IncludesAliasOf(__ StackPointer())); |
| 4976 | 4976 |
| 4977 // The provided arguments, and their proper procedure-call standard registers. | 4977 // The provided arguments, and their proper procedure-call standard registers. |
| 4978 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; | 4978 CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3}; |
| 4979 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; | 4979 CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg}; |
| 4980 | 4980 |
| 4981 int arg_count = kPrintfMaxArgCount; | 4981 int arg_count = kPrintfMaxArgCount; |
| 4982 | 4982 |
| 4983 // The PCS varargs registers for printf. Note that x0 is used for the printf | 4983 // The PCS varargs registers for printf. Note that x0 is used for the printf |
| 4984 // format string. | 4984 // format string. |
| 4985 static const CPURegList kPCSVarargs = | 4985 static const CPURegList kPCSVarargs = |
| (...skipping 30 matching lines...) Expand all Loading... |
| 5016 // Work out the proper PCS register for this argument. | 5016 // Work out the proper PCS register for this argument. |
| 5017 if (args[i].IsRegister()) { | 5017 if (args[i].IsRegister()) { |
| 5018 pcs[i] = pcs_varargs.PopLowestIndex().X(); | 5018 pcs[i] = pcs_varargs.PopLowestIndex().X(); |
| 5019 // We might only need a W register here. We need to know the size of the | 5019 // We might only need a W register here. We need to know the size of the |
| 5020 // argument so we can properly encode it for the simulator call. | 5020 // argument so we can properly encode it for the simulator call. |
| 5021 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); | 5021 if (args[i].Is32Bits()) pcs[i] = pcs[i].W(); |
| 5022 } else if (args[i].IsFPRegister()) { | 5022 } else if (args[i].IsFPRegister()) { |
| 5023 // In C, floats are always cast to doubles for varargs calls. | 5023 // In C, floats are always cast to doubles for varargs calls. |
| 5024 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); | 5024 pcs[i] = pcs_varargs_fp.PopLowestIndex().D(); |
| 5025 } else { | 5025 } else { |
| 5026 ASSERT(args[i].IsNone()); | 5026 DCHECK(args[i].IsNone()); |
| 5027 arg_count = i; | 5027 arg_count = i; |
| 5028 break; | 5028 break; |
| 5029 } | 5029 } |
| 5030 | 5030 |
| 5031 // If the argument is already in the right place, leave it where it is. | 5031 // If the argument is already in the right place, leave it where it is. |
| 5032 if (args[i].Aliases(pcs[i])) continue; | 5032 if (args[i].Aliases(pcs[i])) continue; |
| 5033 | 5033 |
| 5034 // Otherwise, if the argument is in a PCS argument register, allocate an | 5034 // Otherwise, if the argument is in a PCS argument register, allocate an |
| 5035 // appropriate scratch register and then move it out of the way. | 5035 // appropriate scratch register and then move it out of the way. |
| 5036 if (kPCSVarargs.IncludesAliasOf(args[i]) || | 5036 if (kPCSVarargs.IncludesAliasOf(args[i]) || |
| 5037 kPCSVarargsFP.IncludesAliasOf(args[i])) { | 5037 kPCSVarargsFP.IncludesAliasOf(args[i])) { |
| 5038 if (args[i].IsRegister()) { | 5038 if (args[i].IsRegister()) { |
| 5039 Register old_arg = Register(args[i]); | 5039 Register old_arg = Register(args[i]); |
| 5040 Register new_arg = temps.AcquireSameSizeAs(old_arg); | 5040 Register new_arg = temps.AcquireSameSizeAs(old_arg); |
| 5041 Mov(new_arg, old_arg); | 5041 Mov(new_arg, old_arg); |
| 5042 args[i] = new_arg; | 5042 args[i] = new_arg; |
| 5043 } else { | 5043 } else { |
| 5044 FPRegister old_arg = FPRegister(args[i]); | 5044 FPRegister old_arg = FPRegister(args[i]); |
| 5045 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); | 5045 FPRegister new_arg = temps.AcquireSameSizeAs(old_arg); |
| 5046 Fmov(new_arg, old_arg); | 5046 Fmov(new_arg, old_arg); |
| 5047 args[i] = new_arg; | 5047 args[i] = new_arg; |
| 5048 } | 5048 } |
| 5049 } | 5049 } |
| 5050 } | 5050 } |
| 5051 | 5051 |
| 5052 // Do a second pass to move values into their final positions and perform any | 5052 // Do a second pass to move values into their final positions and perform any |
| 5053 // conversions that may be required. | 5053 // conversions that may be required. |
| 5054 for (int i = 0; i < arg_count; i++) { | 5054 for (int i = 0; i < arg_count; i++) { |
| 5055 ASSERT(pcs[i].type() == args[i].type()); | 5055 DCHECK(pcs[i].type() == args[i].type()); |
| 5056 if (pcs[i].IsRegister()) { | 5056 if (pcs[i].IsRegister()) { |
| 5057 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); | 5057 Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg); |
| 5058 } else { | 5058 } else { |
| 5059 ASSERT(pcs[i].IsFPRegister()); | 5059 DCHECK(pcs[i].IsFPRegister()); |
| 5060 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { | 5060 if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) { |
| 5061 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); | 5061 Fmov(FPRegister(pcs[i]), FPRegister(args[i])); |
| 5062 } else { | 5062 } else { |
| 5063 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); | 5063 Fcvt(FPRegister(pcs[i]), FPRegister(args[i])); |
| 5064 } | 5064 } |
| 5065 } | 5065 } |
| 5066 } | 5066 } |
| 5067 | 5067 |
| 5068 // Load the format string into x0, as per the procedure-call standard. | 5068 // Load the format string into x0, as per the procedure-call standard. |
| 5069 // | 5069 // |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5103 hlt(kImmExceptionIsPrintf); | 5103 hlt(kImmExceptionIsPrintf); |
| 5104 dc32(arg_count); // kPrintfArgCountOffset | 5104 dc32(arg_count); // kPrintfArgCountOffset |
| 5105 | 5105 |
| 5106 // Determine the argument pattern. | 5106 // Determine the argument pattern. |
| 5107 uint32_t arg_pattern_list = 0; | 5107 uint32_t arg_pattern_list = 0; |
| 5108 for (int i = 0; i < arg_count; i++) { | 5108 for (int i = 0; i < arg_count; i++) { |
| 5109 uint32_t arg_pattern; | 5109 uint32_t arg_pattern; |
| 5110 if (args[i].IsRegister()) { | 5110 if (args[i].IsRegister()) { |
| 5111 arg_pattern = args[i].Is32Bits() ? kPrintfArgW : kPrintfArgX; | 5111 arg_pattern = args[i].Is32Bits() ? kPrintfArgW : kPrintfArgX; |
| 5112 } else { | 5112 } else { |
| 5113 ASSERT(args[i].Is64Bits()); | 5113 DCHECK(args[i].Is64Bits()); |
| 5114 arg_pattern = kPrintfArgD; | 5114 arg_pattern = kPrintfArgD; |
| 5115 } | 5115 } |
| 5116 ASSERT(arg_pattern < (1 << kPrintfArgPatternBits)); | 5116 DCHECK(arg_pattern < (1 << kPrintfArgPatternBits)); |
| 5117 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i)); | 5117 arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i)); |
| 5118 } | 5118 } |
| 5119 dc32(arg_pattern_list); // kPrintfArgPatternListOffset | 5119 dc32(arg_pattern_list); // kPrintfArgPatternListOffset |
| 5120 } | 5120 } |
| 5121 #else | 5121 #else |
| 5122 Call(FUNCTION_ADDR(printf), RelocInfo::EXTERNAL_REFERENCE); | 5122 Call(FUNCTION_ADDR(printf), RelocInfo::EXTERNAL_REFERENCE); |
| 5123 #endif | 5123 #endif |
| 5124 } | 5124 } |
| 5125 | 5125 |
| 5126 | 5126 |
| 5127 void MacroAssembler::Printf(const char * format, | 5127 void MacroAssembler::Printf(const char * format, |
| 5128 CPURegister arg0, | 5128 CPURegister arg0, |
| 5129 CPURegister arg1, | 5129 CPURegister arg1, |
| 5130 CPURegister arg2, | 5130 CPURegister arg2, |
| 5131 CPURegister arg3) { | 5131 CPURegister arg3) { |
| 5132 // We can only print sp if it is the current stack pointer. | 5132 // We can only print sp if it is the current stack pointer. |
| 5133 if (!csp.Is(StackPointer())) { | 5133 if (!csp.Is(StackPointer())) { |
| 5134 ASSERT(!csp.Aliases(arg0)); | 5134 DCHECK(!csp.Aliases(arg0)); |
| 5135 ASSERT(!csp.Aliases(arg1)); | 5135 DCHECK(!csp.Aliases(arg1)); |
| 5136 ASSERT(!csp.Aliases(arg2)); | 5136 DCHECK(!csp.Aliases(arg2)); |
| 5137 ASSERT(!csp.Aliases(arg3)); | 5137 DCHECK(!csp.Aliases(arg3)); |
| 5138 } | 5138 } |
| 5139 | 5139 |
| 5140 // Printf is expected to preserve all registers, so make sure that none are | 5140 // Printf is expected to preserve all registers, so make sure that none are |
| 5141 // available as scratch registers until we've preserved them. | 5141 // available as scratch registers until we've preserved them. |
| 5142 RegList old_tmp_list = TmpList()->list(); | 5142 RegList old_tmp_list = TmpList()->list(); |
| 5143 RegList old_fp_tmp_list = FPTmpList()->list(); | 5143 RegList old_fp_tmp_list = FPTmpList()->list(); |
| 5144 TmpList()->set_list(0); | 5144 TmpList()->set_list(0); |
| 5145 FPTmpList()->set_list(0); | 5145 FPTmpList()->set_list(0); |
| 5146 | 5146 |
| 5147 // Preserve all caller-saved registers as well as NZCV. | 5147 // Preserve all caller-saved registers as well as NZCV. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5202 FPTmpList()->set_list(old_fp_tmp_list); | 5202 FPTmpList()->set_list(old_fp_tmp_list); |
| 5203 } | 5203 } |
| 5204 | 5204 |
| 5205 | 5205 |
| 5206 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { | 5206 void MacroAssembler::EmitFrameSetupForCodeAgePatching() { |
| 5207 // TODO(jbramley): Other architectures use the internal memcpy to copy the | 5207 // TODO(jbramley): Other architectures use the internal memcpy to copy the |
| 5208 // sequence. If this is a performance bottleneck, we should consider caching | 5208 // sequence. If this is a performance bottleneck, we should consider caching |
| 5209 // the sequence and copying it in the same way. | 5209 // the sequence and copying it in the same way. |
| 5210 InstructionAccurateScope scope(this, | 5210 InstructionAccurateScope scope(this, |
| 5211 kNoCodeAgeSequenceLength / kInstructionSize); | 5211 kNoCodeAgeSequenceLength / kInstructionSize); |
| 5212 ASSERT(jssp.Is(StackPointer())); | 5212 DCHECK(jssp.Is(StackPointer())); |
| 5213 EmitFrameSetupForCodeAgePatching(this); | 5213 EmitFrameSetupForCodeAgePatching(this); |
| 5214 } | 5214 } |
| 5215 | 5215 |
| 5216 | 5216 |
| 5217 | 5217 |
| 5218 void MacroAssembler::EmitCodeAgeSequence(Code* stub) { | 5218 void MacroAssembler::EmitCodeAgeSequence(Code* stub) { |
| 5219 InstructionAccurateScope scope(this, | 5219 InstructionAccurateScope scope(this, |
| 5220 kNoCodeAgeSequenceLength / kInstructionSize); | 5220 kNoCodeAgeSequenceLength / kInstructionSize); |
| 5221 ASSERT(jssp.Is(StackPointer())); | 5221 DCHECK(jssp.Is(StackPointer())); |
| 5222 EmitCodeAgeSequence(this, stub); | 5222 EmitCodeAgeSequence(this, stub); |
| 5223 } | 5223 } |
| 5224 | 5224 |
| 5225 | 5225 |
| 5226 #undef __ | 5226 #undef __ |
| 5227 #define __ assm-> | 5227 #define __ assm-> |
| 5228 | 5228 |
| 5229 | 5229 |
| 5230 void MacroAssembler::EmitFrameSetupForCodeAgePatching(Assembler * assm) { | 5230 void MacroAssembler::EmitFrameSetupForCodeAgePatching(Assembler * assm) { |
| 5231 Label start; | 5231 Label start; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5264 __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeStubEntryOffset); | 5264 __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeStubEntryOffset); |
| 5265 if (stub) { | 5265 if (stub) { |
| 5266 __ dc64(reinterpret_cast<uint64_t>(stub->instruction_start())); | 5266 __ dc64(reinterpret_cast<uint64_t>(stub->instruction_start())); |
| 5267 __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength); | 5267 __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength); |
| 5268 } | 5268 } |
| 5269 } | 5269 } |
| 5270 | 5270 |
| 5271 | 5271 |
| 5272 bool MacroAssembler::IsYoungSequence(Isolate* isolate, byte* sequence) { | 5272 bool MacroAssembler::IsYoungSequence(Isolate* isolate, byte* sequence) { |
| 5273 bool is_young = isolate->code_aging_helper()->IsYoung(sequence); | 5273 bool is_young = isolate->code_aging_helper()->IsYoung(sequence); |
| 5274 ASSERT(is_young || | 5274 DCHECK(is_young || |
| 5275 isolate->code_aging_helper()->IsOld(sequence)); | 5275 isolate->code_aging_helper()->IsOld(sequence)); |
| 5276 return is_young; | 5276 return is_young; |
| 5277 } | 5277 } |
| 5278 | 5278 |
| 5279 | 5279 |
| 5280 void MacroAssembler::TruncatingDiv(Register result, | 5280 void MacroAssembler::TruncatingDiv(Register result, |
| 5281 Register dividend, | 5281 Register dividend, |
| 5282 int32_t divisor) { | 5282 int32_t divisor) { |
| 5283 ASSERT(!AreAliased(result, dividend)); | 5283 DCHECK(!AreAliased(result, dividend)); |
| 5284 ASSERT(result.Is32Bits() && dividend.Is32Bits()); | 5284 DCHECK(result.Is32Bits() && dividend.Is32Bits()); |
| 5285 MultiplierAndShift ms(divisor); | 5285 MultiplierAndShift ms(divisor); |
| 5286 Mov(result, ms.multiplier()); | 5286 Mov(result, ms.multiplier()); |
| 5287 Smull(result.X(), dividend, result); | 5287 Smull(result.X(), dividend, result); |
| 5288 Asr(result.X(), result.X(), 32); | 5288 Asr(result.X(), result.X(), 32); |
| 5289 if (divisor > 0 && ms.multiplier() < 0) Add(result, result, dividend); | 5289 if (divisor > 0 && ms.multiplier() < 0) Add(result, result, dividend); |
| 5290 if (divisor < 0 && ms.multiplier() > 0) Sub(result, result, dividend); | 5290 if (divisor < 0 && ms.multiplier() > 0) Sub(result, result, dividend); |
| 5291 if (ms.shift() > 0) Asr(result, result, ms.shift()); | 5291 if (ms.shift() > 0) Asr(result, result, ms.shift()); |
| 5292 Add(result, result, Operand(dividend, LSR, 31)); | 5292 Add(result, result, Operand(dividend, LSR, 31)); |
| 5293 } | 5293 } |
| 5294 | 5294 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 5311 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) { | 5311 FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) { |
| 5312 int code = AcquireNextAvailable(availablefp_).code(); | 5312 int code = AcquireNextAvailable(availablefp_).code(); |
| 5313 return FPRegister::Create(code, reg.SizeInBits()); | 5313 return FPRegister::Create(code, reg.SizeInBits()); |
| 5314 } | 5314 } |
| 5315 | 5315 |
| 5316 | 5316 |
| 5317 CPURegister UseScratchRegisterScope::AcquireNextAvailable( | 5317 CPURegister UseScratchRegisterScope::AcquireNextAvailable( |
| 5318 CPURegList* available) { | 5318 CPURegList* available) { |
| 5319 CHECK(!available->IsEmpty()); | 5319 CHECK(!available->IsEmpty()); |
| 5320 CPURegister result = available->PopLowestIndex(); | 5320 CPURegister result = available->PopLowestIndex(); |
| 5321 ASSERT(!AreAliased(result, xzr, csp)); | 5321 DCHECK(!AreAliased(result, xzr, csp)); |
| 5322 return result; | 5322 return result; |
| 5323 } | 5323 } |
| 5324 | 5324 |
| 5325 | 5325 |
| 5326 CPURegister UseScratchRegisterScope::UnsafeAcquire(CPURegList* available, | 5326 CPURegister UseScratchRegisterScope::UnsafeAcquire(CPURegList* available, |
| 5327 const CPURegister& reg) { | 5327 const CPURegister& reg) { |
| 5328 ASSERT(available->IncludesAliasOf(reg)); | 5328 DCHECK(available->IncludesAliasOf(reg)); |
| 5329 available->Remove(reg); | 5329 available->Remove(reg); |
| 5330 return reg; | 5330 return reg; |
| 5331 } | 5331 } |
| 5332 | 5332 |
| 5333 | 5333 |
| 5334 #define __ masm-> | 5334 #define __ masm-> |
| 5335 | 5335 |
| 5336 | 5336 |
| 5337 void InlineSmiCheckInfo::Emit(MacroAssembler* masm, const Register& reg, | 5337 void InlineSmiCheckInfo::Emit(MacroAssembler* masm, const Register& reg, |
| 5338 const Label* smi_check) { | 5338 const Label* smi_check) { |
| 5339 Assembler::BlockPoolsScope scope(masm); | 5339 Assembler::BlockPoolsScope scope(masm); |
| 5340 if (reg.IsValid()) { | 5340 if (reg.IsValid()) { |
| 5341 ASSERT(smi_check->is_bound()); | 5341 DCHECK(smi_check->is_bound()); |
| 5342 ASSERT(reg.Is64Bits()); | 5342 DCHECK(reg.Is64Bits()); |
| 5343 | 5343 |
| 5344 // Encode the register (x0-x30) in the lowest 5 bits, then the offset to | 5344 // Encode the register (x0-x30) in the lowest 5 bits, then the offset to |
| 5345 // 'check' in the other bits. The possible offset is limited in that we | 5345 // 'check' in the other bits. The possible offset is limited in that we |
| 5346 // use BitField to pack the data, and the underlying data type is a | 5346 // use BitField to pack the data, and the underlying data type is a |
| 5347 // uint32_t. | 5347 // uint32_t. |
| 5348 uint32_t delta = __ InstructionsGeneratedSince(smi_check); | 5348 uint32_t delta = __ InstructionsGeneratedSince(smi_check); |
| 5349 __ InlineData(RegisterBits::encode(reg.code()) | DeltaBits::encode(delta)); | 5349 __ InlineData(RegisterBits::encode(reg.code()) | DeltaBits::encode(delta)); |
| 5350 } else { | 5350 } else { |
| 5351 ASSERT(!smi_check->is_bound()); | 5351 DCHECK(!smi_check->is_bound()); |
| 5352 | 5352 |
| 5353 // An offset of 0 indicates that there is no patch site. | 5353 // An offset of 0 indicates that there is no patch site. |
| 5354 __ InlineData(0); | 5354 __ InlineData(0); |
| 5355 } | 5355 } |
| 5356 } | 5356 } |
| 5357 | 5357 |
| 5358 | 5358 |
| 5359 InlineSmiCheckInfo::InlineSmiCheckInfo(Address info) | 5359 InlineSmiCheckInfo::InlineSmiCheckInfo(Address info) |
| 5360 : reg_(NoReg), smi_check_(NULL) { | 5360 : reg_(NoReg), smi_check_(NULL) { |
| 5361 InstructionSequence* inline_data = InstructionSequence::At(info); | 5361 InstructionSequence* inline_data = InstructionSequence::At(info); |
| 5362 ASSERT(inline_data->IsInlineData()); | 5362 DCHECK(inline_data->IsInlineData()); |
| 5363 if (inline_data->IsInlineData()) { | 5363 if (inline_data->IsInlineData()) { |
| 5364 uint64_t payload = inline_data->InlineData(); | 5364 uint64_t payload = inline_data->InlineData(); |
| 5365 // We use BitField to decode the payload, and BitField can only handle | 5365 // We use BitField to decode the payload, and BitField can only handle |
| 5366 // 32-bit values. | 5366 // 32-bit values. |
| 5367 ASSERT(is_uint32(payload)); | 5367 DCHECK(is_uint32(payload)); |
| 5368 if (payload != 0) { | 5368 if (payload != 0) { |
| 5369 int reg_code = RegisterBits::decode(payload); | 5369 int reg_code = RegisterBits::decode(payload); |
| 5370 reg_ = Register::XRegFromCode(reg_code); | 5370 reg_ = Register::XRegFromCode(reg_code); |
| 5371 uint64_t smi_check_delta = DeltaBits::decode(payload); | 5371 uint64_t smi_check_delta = DeltaBits::decode(payload); |
| 5372 ASSERT(smi_check_delta != 0); | 5372 DCHECK(smi_check_delta != 0); |
| 5373 smi_check_ = inline_data->preceding(smi_check_delta); | 5373 smi_check_ = inline_data->preceding(smi_check_delta); |
| 5374 } | 5374 } |
| 5375 } | 5375 } |
| 5376 } | 5376 } |
| 5377 | 5377 |
| 5378 | 5378 |
| 5379 #undef __ | 5379 #undef __ |
| 5380 | 5380 |
| 5381 | 5381 |
| 5382 } } // namespace v8::internal | 5382 } } // namespace v8::internal |
| 5383 | 5383 |
| 5384 #endif // V8_TARGET_ARCH_ARM64 | 5384 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |