1/* 2 * Copyright (C) 2009, 2010, 2014 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 University of Szeged 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#ifndef MacroAssemblerARMv7_h 28#define MacroAssemblerARMv7_h 29 30#if ENABLE(ASSEMBLER) 31 32#include "ARMv7Assembler.h" 33#include "AbstractMacroAssembler.h" 34 35namespace JSC { 36 37class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { 38 static const RegisterID dataTempRegister = ARMRegisters::ip; 39 static const RegisterID addressTempRegister = ARMRegisters::r6; 40 41 static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7; 42 inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); } 43 44public: 45 MacroAssemblerARMv7() 46 : m_makeJumpPatchable(false) 47 { 48 } 49 50 typedef ARMv7Assembler::LinkRecord LinkRecord; 51 typedef ARMv7Assembler::JumpType JumpType; 52 typedef ARMv7Assembler::JumpLinkType JumpLinkType; 53 typedef ARMv7Assembler::Condition Condition; 54 55 static const ARMv7Assembler::Condition DefaultCondition = ARMv7Assembler::ConditionInvalid; 56 static const ARMv7Assembler::JumpType DefaultJump = ARMv7Assembler::JumpNoConditionFixedSize; 57 58 static bool isCompactPtrAlignedAddressOffset(ptrdiff_t value) 59 { 60 return value >= -255 && value <= 255; 61 } 62 63 Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink() { return m_assembler.jumpsToLink(); } 64 void* unlinkedCode() { return m_assembler.unlinkedCode(); } 65 static bool canCompact(JumpType jumpType) { return ARMv7Assembler::canCompact(jumpType); } 66 static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(jumpType, from, to); } 67 static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARMv7Assembler::computeJumpType(record, from, to); } 68 static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARMv7Assembler::jumpSizeDelta(jumpType, jumpLinkType); } 69 static void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return ARMv7Assembler::link(record, from, to); } 70 71 struct ArmAddress { 72 enum AddressType { 73 HasOffset, 74 HasIndex, 75 } type; 76 RegisterID base; 77 union { 78 int32_t offset; 79 struct { 80 RegisterID index; 81 Scale scale; 82 }; 83 } u; 84 85 explicit ArmAddress(RegisterID base, int32_t offset = 0) 86 : type(HasOffset) 87 , base(base) 88 { 89 u.offset = offset; 90 } 91 92 explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne) 93 : type(HasIndex) 94 , base(base) 95 { 96 u.index = index; 97 u.scale = scale; 98 } 99 }; 100 101public: 102 static const Scale ScalePtr = TimesFour; 103 104 enum RelationalCondition { 105 Equal = ARMv7Assembler::ConditionEQ, 106 NotEqual = ARMv7Assembler::ConditionNE, 107 Above = ARMv7Assembler::ConditionHI, 108 AboveOrEqual = ARMv7Assembler::ConditionHS, 109 Below = ARMv7Assembler::ConditionLO, 110 BelowOrEqual = ARMv7Assembler::ConditionLS, 111 GreaterThan = ARMv7Assembler::ConditionGT, 112 GreaterThanOrEqual = ARMv7Assembler::ConditionGE, 113 LessThan = ARMv7Assembler::ConditionLT, 114 LessThanOrEqual = ARMv7Assembler::ConditionLE 115 }; 116 117 enum ResultCondition { 118 Overflow = ARMv7Assembler::ConditionVS, 119 Signed = ARMv7Assembler::ConditionMI, 120 PositiveOrZero = ARMv7Assembler::ConditionPL, 121 Zero = ARMv7Assembler::ConditionEQ, 122 NonZero = ARMv7Assembler::ConditionNE 123 }; 124 125 enum DoubleCondition { 126 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. 127 DoubleEqual = ARMv7Assembler::ConditionEQ, 128 DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently. 129 DoubleGreaterThan = ARMv7Assembler::ConditionGT, 130 DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, 131 DoubleLessThan = ARMv7Assembler::ConditionLO, 132 DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, 133 // If either operand is NaN, these conditions always evaluate to true. 134 DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently. 135 DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE, 136 DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI, 137 DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS, 138 DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT, 139 DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE, 140 }; 141 142 static const RegisterID stackPointerRegister = ARMRegisters::sp; 143 static const RegisterID framePointerRegister = ARMRegisters::fp; 144 static const RegisterID linkRegister = ARMRegisters::lr; 145 146 // Integer arithmetic operations: 147 // 148 // Operations are typically two operand - operation(source, srcDst) 149 // For many operations the source may be an TrustedImm32, the srcDst operand 150 // may often be a memory location (explictly described using an Address 151 // object). 152 153 void add32(RegisterID src, RegisterID dest) 154 { 155 m_assembler.add(dest, dest, src); 156 } 157 158 void add32(TrustedImm32 imm, RegisterID dest) 159 { 160 add32(imm, dest, dest); 161 } 162 163 void add32(AbsoluteAddress src, RegisterID dest) 164 { 165 load32(src.m_ptr, dataTempRegister); 166 add32(dataTempRegister, dest); 167 } 168 169 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) 170 { 171 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 172 173 // For adds with stack pointer destination, moving the src first to sp is 174 // needed to avoid unpredictable instruction 175 if (dest == ARMRegisters::sp && src != dest) { 176 move(src, ARMRegisters::sp); 177 src = ARMRegisters::sp; 178 } 179 180 if (armImm.isValid()) 181 m_assembler.add(dest, src, armImm); 182 else { 183 move(imm, dataTempRegister); 184 m_assembler.add(dest, src, dataTempRegister); 185 } 186 } 187 188 void add32(TrustedImm32 imm, Address address) 189 { 190 load32(address, dataTempRegister); 191 192 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 193 if (armImm.isValid()) 194 m_assembler.add(dataTempRegister, dataTempRegister, armImm); 195 else { 196 // Hrrrm, since dataTempRegister holds the data loaded, 197 // use addressTempRegister to hold the immediate. 198 move(imm, addressTempRegister); 199 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); 200 } 201 202 store32(dataTempRegister, address); 203 } 204 205 void add32(Address src, RegisterID dest) 206 { 207 load32(src, dataTempRegister); 208 add32(dataTempRegister, dest); 209 } 210 211 void add32(TrustedImm32 imm, AbsoluteAddress address) 212 { 213 load32(address.m_ptr, dataTempRegister); 214 215 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 216 if (armImm.isValid()) 217 m_assembler.add(dataTempRegister, dataTempRegister, armImm); 218 else { 219 // Hrrrm, since dataTempRegister holds the data loaded, 220 // use addressTempRegister to hold the immediate. 221 move(imm, addressTempRegister); 222 m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); 223 } 224 225 store32(dataTempRegister, address.m_ptr); 226 } 227 228 void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest) 229 { 230 add32(imm, srcDest); 231 } 232 233 void add64(TrustedImm32 imm, AbsoluteAddress address) 234 { 235 move(TrustedImmPtr(address.m_ptr), addressTempRegister); 236 237 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0)); 238 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 239 if (armImm.isValid()) 240 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm); 241 else { 242 move(imm, addressTempRegister); 243 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister); 244 move(TrustedImmPtr(address.m_ptr), addressTempRegister); 245 } 246 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(0)); 247 248 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4)); 249 m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31)); 250 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4)); 251 } 252 253 void and32(RegisterID op1, RegisterID op2, RegisterID dest) 254 { 255 m_assembler.ARM_and(dest, op1, op2); 256 } 257 258 void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) 259 { 260 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 261 if (armImm.isValid()) 262 m_assembler.ARM_and(dest, src, armImm); 263 else { 264 move(imm, dataTempRegister); 265 m_assembler.ARM_and(dest, src, dataTempRegister); 266 } 267 } 268 269 void and32(RegisterID src, RegisterID dest) 270 { 271 and32(dest, src, dest); 272 } 273 274 void and32(TrustedImm32 imm, RegisterID dest) 275 { 276 and32(imm, dest, dest); 277 } 278 279 void and32(Address src, RegisterID dest) 280 { 281 load32(src, dataTempRegister); 282 and32(dataTempRegister, dest); 283 } 284 285 void countLeadingZeros32(RegisterID src, RegisterID dest) 286 { 287 m_assembler.clz(dest, src); 288 } 289 290 void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 291 { 292 // Clamp the shift to the range 0..31 293 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); 294 ASSERT(armImm.isValid()); 295 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm); 296 297 m_assembler.lsl(dest, src, dataTempRegister); 298 } 299 300 void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 301 { 302 m_assembler.lsl(dest, src, imm.m_value & 0x1f); 303 } 304 305 void lshift32(RegisterID shiftAmount, RegisterID dest) 306 { 307 lshift32(dest, shiftAmount, dest); 308 } 309 310 void lshift32(TrustedImm32 imm, RegisterID dest) 311 { 312 lshift32(dest, imm, dest); 313 } 314 315 void mul32(RegisterID src, RegisterID dest) 316 { 317 m_assembler.smull(dest, dataTempRegister, dest, src); 318 } 319 320 void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) 321 { 322 move(imm, dataTempRegister); 323 m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); 324 } 325 326 void neg32(RegisterID srcDest) 327 { 328 m_assembler.neg(srcDest, srcDest); 329 } 330 331 void or32(RegisterID src, RegisterID dest) 332 { 333 m_assembler.orr(dest, dest, src); 334 } 335 336 void or32(RegisterID src, AbsoluteAddress dest) 337 { 338 move(TrustedImmPtr(dest.m_ptr), addressTempRegister); 339 load32(addressTempRegister, dataTempRegister); 340 or32(src, dataTempRegister); 341 store32(dataTempRegister, addressTempRegister); 342 } 343 344 void or32(TrustedImm32 imm, Address address) 345 { 346 load32(address, dataTempRegister); 347 or32(imm, dataTempRegister, dataTempRegister); 348 store32(dataTempRegister, address); 349 } 350 351 void or32(TrustedImm32 imm, RegisterID dest) 352 { 353 or32(imm, dest, dest); 354 } 355 356 void or32(RegisterID op1, RegisterID op2, RegisterID dest) 357 { 358 m_assembler.orr(dest, op1, op2); 359 } 360 361 void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) 362 { 363 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 364 if (armImm.isValid()) 365 m_assembler.orr(dest, src, armImm); 366 else { 367 move(imm, dataTempRegister); 368 m_assembler.orr(dest, src, dataTempRegister); 369 } 370 } 371 372 void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 373 { 374 // Clamp the shift to the range 0..31 375 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); 376 ASSERT(armImm.isValid()); 377 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm); 378 379 m_assembler.asr(dest, src, dataTempRegister); 380 } 381 382 void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 383 { 384 m_assembler.asr(dest, src, imm.m_value & 0x1f); 385 } 386 387 void rshift32(RegisterID shiftAmount, RegisterID dest) 388 { 389 rshift32(dest, shiftAmount, dest); 390 } 391 392 void rshift32(TrustedImm32 imm, RegisterID dest) 393 { 394 rshift32(dest, imm, dest); 395 } 396 397 void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest) 398 { 399 // Clamp the shift to the range 0..31 400 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); 401 ASSERT(armImm.isValid()); 402 m_assembler.ARM_and(dataTempRegister, shiftAmount, armImm); 403 404 m_assembler.lsr(dest, src, dataTempRegister); 405 } 406 407 void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) 408 { 409 m_assembler.lsr(dest, src, imm.m_value & 0x1f); 410 } 411 412 void urshift32(RegisterID shiftAmount, RegisterID dest) 413 { 414 urshift32(dest, shiftAmount, dest); 415 } 416 417 void urshift32(TrustedImm32 imm, RegisterID dest) 418 { 419 urshift32(dest, imm, dest); 420 } 421 422 void sub32(RegisterID src, RegisterID dest) 423 { 424 m_assembler.sub(dest, dest, src); 425 } 426 427 void sub32(TrustedImm32 imm, RegisterID dest) 428 { 429 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 430 if (armImm.isValid()) 431 m_assembler.sub(dest, dest, armImm); 432 else { 433 move(imm, dataTempRegister); 434 m_assembler.sub(dest, dest, dataTempRegister); 435 } 436 } 437 438 void sub32(TrustedImm32 imm, Address address) 439 { 440 load32(address, dataTempRegister); 441 442 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 443 if (armImm.isValid()) 444 m_assembler.sub(dataTempRegister, dataTempRegister, armImm); 445 else { 446 // Hrrrm, since dataTempRegister holds the data loaded, 447 // use addressTempRegister to hold the immediate. 448 move(imm, addressTempRegister); 449 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); 450 } 451 452 store32(dataTempRegister, address); 453 } 454 455 void sub32(Address src, RegisterID dest) 456 { 457 load32(src, dataTempRegister); 458 sub32(dataTempRegister, dest); 459 } 460 461 void sub32(TrustedImm32 imm, AbsoluteAddress address) 462 { 463 load32(address.m_ptr, dataTempRegister); 464 465 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); 466 if (armImm.isValid()) 467 m_assembler.sub(dataTempRegister, dataTempRegister, armImm); 468 else { 469 // Hrrrm, since dataTempRegister holds the data loaded, 470 // use addressTempRegister to hold the immediate. 471 move(imm, addressTempRegister); 472 m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); 473 } 474 475 store32(dataTempRegister, address.m_ptr); 476 } 477 478 void xor32(RegisterID op1, RegisterID op2, RegisterID dest) 479 { 480 m_assembler.eor(dest, op1, op2); 481 } 482 483 void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) 484 { 485 if (imm.m_value == -1) { 486 m_assembler.mvn(dest, src); 487 return; 488 } 489 490 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 491 if (armImm.isValid()) 492 m_assembler.eor(dest, src, armImm); 493 else { 494 move(imm, dataTempRegister); 495 m_assembler.eor(dest, src, dataTempRegister); 496 } 497 } 498 499 void xor32(RegisterID src, RegisterID dest) 500 { 501 xor32(dest, src, dest); 502 } 503 504 void xor32(TrustedImm32 imm, RegisterID dest) 505 { 506 if (imm.m_value == -1) 507 m_assembler.mvn(dest, dest); 508 else 509 xor32(imm, dest, dest); 510 } 511 512 513 // Memory access operations: 514 // 515 // Loads are of the form load(address, destination) and stores of the form 516 // store(source, address). The source for a store may be an TrustedImm32. Address 517 // operand objects to loads and store will be implicitly constructed if a 518 // register is passed. 519 520private: 521 void load32(ArmAddress address, RegisterID dest) 522 { 523 if (address.type == ArmAddress::HasIndex) 524 m_assembler.ldr(dest, address.base, address.u.index, address.u.scale); 525 else if (address.u.offset >= 0) { 526 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 527 ASSERT(armImm.isValid()); 528 m_assembler.ldr(dest, address.base, armImm); 529 } else { 530 ASSERT(address.u.offset >= -255); 531 m_assembler.ldr(dest, address.base, address.u.offset, true, false); 532 } 533 } 534 535 void load16(ArmAddress address, RegisterID dest) 536 { 537 if (address.type == ArmAddress::HasIndex) 538 m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale); 539 else if (address.u.offset >= 0) { 540 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 541 ASSERT(armImm.isValid()); 542 m_assembler.ldrh(dest, address.base, armImm); 543 } else { 544 ASSERT(address.u.offset >= -255); 545 m_assembler.ldrh(dest, address.base, address.u.offset, true, false); 546 } 547 } 548 549 void load16Signed(ArmAddress address, RegisterID dest) 550 { 551 ASSERT(address.type == ArmAddress::HasIndex); 552 m_assembler.ldrsh(dest, address.base, address.u.index, address.u.scale); 553 } 554 555 void load8(ArmAddress address, RegisterID dest) 556 { 557 if (address.type == ArmAddress::HasIndex) 558 m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); 559 else if (address.u.offset >= 0) { 560 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 561 ASSERT(armImm.isValid()); 562 m_assembler.ldrb(dest, address.base, armImm); 563 } else { 564 ASSERT(address.u.offset >= -255); 565 m_assembler.ldrb(dest, address.base, address.u.offset, true, false); 566 } 567 } 568 569 void load8Signed(ArmAddress address, RegisterID dest) 570 { 571 ASSERT(address.type == ArmAddress::HasIndex); 572 m_assembler.ldrsb(dest, address.base, address.u.index, address.u.scale); 573 } 574 575protected: 576 void store32(RegisterID src, ArmAddress address) 577 { 578 if (address.type == ArmAddress::HasIndex) 579 m_assembler.str(src, address.base, address.u.index, address.u.scale); 580 else if (address.u.offset >= 0) { 581 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 582 ASSERT(armImm.isValid()); 583 m_assembler.str(src, address.base, armImm); 584 } else { 585 ASSERT(address.u.offset >= -255); 586 m_assembler.str(src, address.base, address.u.offset, true, false); 587 } 588 } 589 590private: 591 void store8(RegisterID src, ArmAddress address) 592 { 593 if (address.type == ArmAddress::HasIndex) 594 m_assembler.strb(src, address.base, address.u.index, address.u.scale); 595 else if (address.u.offset >= 0) { 596 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 597 ASSERT(armImm.isValid()); 598 m_assembler.strb(src, address.base, armImm); 599 } else { 600 ASSERT(address.u.offset >= -255); 601 m_assembler.strb(src, address.base, address.u.offset, true, false); 602 } 603 } 604 605 void store16(RegisterID src, ArmAddress address) 606 { 607 if (address.type == ArmAddress::HasIndex) 608 m_assembler.strh(src, address.base, address.u.index, address.u.scale); 609 else if (address.u.offset >= 0) { 610 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); 611 ASSERT(armImm.isValid()); 612 m_assembler.strh(src, address.base, armImm); 613 } else { 614 ASSERT(address.u.offset >= -255); 615 m_assembler.strh(src, address.base, address.u.offset, true, false); 616 } 617 } 618 619public: 620 void load32(ImplicitAddress address, RegisterID dest) 621 { 622 load32(setupArmAddress(address), dest); 623 } 624 625 void load32(BaseIndex address, RegisterID dest) 626 { 627 load32(setupArmAddress(address), dest); 628 } 629 630 void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) 631 { 632 load32(setupArmAddress(address), dest); 633 } 634 635 void load16Unaligned(BaseIndex address, RegisterID dest) 636 { 637 load16(setupArmAddress(address), dest); 638 } 639 640 void load32(const void* address, RegisterID dest) 641 { 642 move(TrustedImmPtr(address), addressTempRegister); 643 m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 644 } 645 646 void abortWithReason(AbortReason reason) 647 { 648 move(TrustedImm32(reason), dataTempRegister); 649 breakpoint(); 650 } 651 652 void abortWithReason(AbortReason reason, intptr_t misc) 653 { 654 move(TrustedImm32(misc), addressTempRegister); 655 abortWithReason(reason); 656 } 657 658 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) 659 { 660 ConvertibleLoadLabel result(this); 661 ASSERT(address.offset >= 0 && address.offset <= 255); 662 m_assembler.ldrWide8BitImmediate(dest, address.base, address.offset); 663 return result; 664 } 665 666 void load8(ImplicitAddress address, RegisterID dest) 667 { 668 load8(setupArmAddress(address), dest); 669 } 670 671 void load8Signed(ImplicitAddress, RegisterID) 672 { 673 UNREACHABLE_FOR_PLATFORM(); 674 } 675 676 void load8(BaseIndex address, RegisterID dest) 677 { 678 load8(setupArmAddress(address), dest); 679 } 680 681 void load8Signed(BaseIndex address, RegisterID dest) 682 { 683 load8Signed(setupArmAddress(address), dest); 684 } 685 686 void load8(const void* address, RegisterID dest) 687 { 688 move(TrustedImmPtr(address), dest); 689 load8(dest, dest); 690 } 691 692 DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) 693 { 694 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister); 695 load32(ArmAddress(address.base, dataTempRegister), dest); 696 return label; 697 } 698 699 DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest) 700 { 701 padBeforePatch(); 702 703 RegisterID base = address.base; 704 705 DataLabelCompact label(this); 706 ASSERT(isCompactPtrAlignedAddressOffset(address.offset)); 707 708 m_assembler.ldr(dest, base, address.offset, true, false); 709 return label; 710 } 711 712 void load16(BaseIndex address, RegisterID dest) 713 { 714 m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); 715 } 716 717 void load16Signed(BaseIndex address, RegisterID dest) 718 { 719 load16Signed(setupArmAddress(address), dest); 720 } 721 722 void load16(ImplicitAddress address, RegisterID dest) 723 { 724 ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset); 725 if (armImm.isValid()) 726 m_assembler.ldrh(dest, address.base, armImm); 727 else { 728 move(TrustedImm32(address.offset), dataTempRegister); 729 m_assembler.ldrh(dest, address.base, dataTempRegister); 730 } 731 } 732 733 void load16Signed(ImplicitAddress, RegisterID) 734 { 735 UNREACHABLE_FOR_PLATFORM(); 736 } 737 738 DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) 739 { 740 DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister); 741 store32(src, ArmAddress(address.base, dataTempRegister)); 742 return label; 743 } 744 745 void store32(RegisterID src, ImplicitAddress address) 746 { 747 store32(src, setupArmAddress(address)); 748 } 749 750 void store32(RegisterID src, BaseIndex address) 751 { 752 store32(src, setupArmAddress(address)); 753 } 754 755 void store32(TrustedImm32 imm, ImplicitAddress address) 756 { 757 move(imm, dataTempRegister); 758 store32(dataTempRegister, setupArmAddress(address)); 759 } 760 761 void store32(TrustedImm32 imm, BaseIndex address) 762 { 763 move(imm, dataTempRegister); 764 store32(dataTempRegister, setupArmAddress(address)); 765 } 766 767 void store32(RegisterID src, const void* address) 768 { 769 move(TrustedImmPtr(address), addressTempRegister); 770 m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 771 } 772 773 void store32(TrustedImm32 imm, const void* address) 774 { 775 move(imm, dataTempRegister); 776 store32(dataTempRegister, address); 777 } 778 779 void store8(RegisterID src, Address address) 780 { 781 store8(src, setupArmAddress(address)); 782 } 783 784 void store8(RegisterID src, BaseIndex address) 785 { 786 store8(src, setupArmAddress(address)); 787 } 788 789 void store8(RegisterID src, void* address) 790 { 791 move(TrustedImmPtr(address), addressTempRegister); 792 store8(src, ArmAddress(addressTempRegister, 0)); 793 } 794 795 void store8(TrustedImm32 imm, void* address) 796 { 797 move(imm, dataTempRegister); 798 store8(dataTempRegister, address); 799 } 800 801 void store8(TrustedImm32 imm, Address address) 802 { 803 move(imm, dataTempRegister); 804 store8(dataTempRegister, address); 805 } 806 807 void store16(RegisterID src, BaseIndex address) 808 { 809 store16(src, setupArmAddress(address)); 810 } 811 812 // Possibly clobbers src, but not on this architecture. 813 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2) 814 { 815 m_assembler.vmov(dest1, dest2, src); 816 } 817 818 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch) 819 { 820 UNUSED_PARAM(scratch); 821 m_assembler.vmov(dest, src1, src2); 822 } 823 824 static bool shouldBlindForSpecificArch(uint32_t value) 825 { 826 ARMThumbImmediate immediate = ARMThumbImmediate::makeEncodedImm(value); 827 828 // Couldn't be encoded as an immediate, so assume it's untrusted. 829 if (!immediate.isValid()) 830 return true; 831 832 // If we can encode the immediate, we have less than 16 attacker 833 // controlled bits. 834 if (immediate.isEncodedImm()) 835 return false; 836 837 // Don't let any more than 12 bits of an instruction word 838 // be controlled by an attacker. 839 return !immediate.isUInt12(); 840 } 841 842 // Floating-point operations: 843 844 static bool supportsFloatingPoint() { return true; } 845 static bool supportsFloatingPointTruncate() { return true; } 846 static bool supportsFloatingPointSqrt() { return true; } 847 static bool supportsFloatingPointAbs() { return true; } 848 849 void loadDouble(ImplicitAddress address, FPRegisterID dest) 850 { 851 RegisterID base = address.base; 852 int32_t offset = address.offset; 853 854 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 855 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 856 add32(TrustedImm32(offset), base, addressTempRegister); 857 base = addressTempRegister; 858 offset = 0; 859 } 860 861 m_assembler.vldr(dest, base, offset); 862 } 863 864 void loadFloat(ImplicitAddress address, FPRegisterID dest) 865 { 866 RegisterID base = address.base; 867 int32_t offset = address.offset; 868 869 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 870 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 871 add32(TrustedImm32(offset), base, addressTempRegister); 872 base = addressTempRegister; 873 offset = 0; 874 } 875 876 m_assembler.flds(ARMRegisters::asSingle(dest), base, offset); 877 } 878 879 void loadDouble(BaseIndex address, FPRegisterID dest) 880 { 881 move(address.index, addressTempRegister); 882 lshift32(TrustedImm32(address.scale), addressTempRegister); 883 add32(address.base, addressTempRegister); 884 loadDouble(Address(addressTempRegister, address.offset), dest); 885 } 886 887 void loadFloat(BaseIndex address, FPRegisterID dest) 888 { 889 move(address.index, addressTempRegister); 890 lshift32(TrustedImm32(address.scale), addressTempRegister); 891 add32(address.base, addressTempRegister); 892 loadFloat(Address(addressTempRegister, address.offset), dest); 893 } 894 895 void moveDouble(FPRegisterID src, FPRegisterID dest) 896 { 897 if (src != dest) 898 m_assembler.vmov(dest, src); 899 } 900 901 void loadDouble(TrustedImmPtr address, FPRegisterID dest) 902 { 903 move(address, addressTempRegister); 904 m_assembler.vldr(dest, addressTempRegister, 0); 905 } 906 907 void storeDouble(FPRegisterID src, ImplicitAddress address) 908 { 909 RegisterID base = address.base; 910 int32_t offset = address.offset; 911 912 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 913 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 914 add32(TrustedImm32(offset), base, addressTempRegister); 915 base = addressTempRegister; 916 offset = 0; 917 } 918 919 m_assembler.vstr(src, base, offset); 920 } 921 922 void storeFloat(FPRegisterID src, ImplicitAddress address) 923 { 924 RegisterID base = address.base; 925 int32_t offset = address.offset; 926 927 // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. 928 if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { 929 add32(TrustedImm32(offset), base, addressTempRegister); 930 base = addressTempRegister; 931 offset = 0; 932 } 933 934 m_assembler.fsts(ARMRegisters::asSingle(src), base, offset); 935 } 936 937 void storeDouble(FPRegisterID src, TrustedImmPtr address) 938 { 939 move(address, addressTempRegister); 940 storeDouble(src, addressTempRegister); 941 } 942 943 void storeDouble(FPRegisterID src, BaseIndex address) 944 { 945 move(address.index, addressTempRegister); 946 lshift32(TrustedImm32(address.scale), addressTempRegister); 947 add32(address.base, addressTempRegister); 948 storeDouble(src, Address(addressTempRegister, address.offset)); 949 } 950 951 void storeFloat(FPRegisterID src, BaseIndex address) 952 { 953 move(address.index, addressTempRegister); 954 lshift32(TrustedImm32(address.scale), addressTempRegister); 955 add32(address.base, addressTempRegister); 956 storeFloat(src, Address(addressTempRegister, address.offset)); 957 } 958 959 void addDouble(FPRegisterID src, FPRegisterID dest) 960 { 961 m_assembler.vadd(dest, dest, src); 962 } 963 964 void addDouble(Address src, FPRegisterID dest) 965 { 966 loadDouble(src, fpTempRegister); 967 addDouble(fpTempRegister, dest); 968 } 969 970 void addDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 971 { 972 m_assembler.vadd(dest, op1, op2); 973 } 974 975 void addDouble(AbsoluteAddress address, FPRegisterID dest) 976 { 977 loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister); 978 m_assembler.vadd(dest, dest, fpTempRegister); 979 } 980 981 void divDouble(FPRegisterID src, FPRegisterID dest) 982 { 983 m_assembler.vdiv(dest, dest, src); 984 } 985 986 void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 987 { 988 m_assembler.vdiv(dest, op1, op2); 989 } 990 991 void subDouble(FPRegisterID src, FPRegisterID dest) 992 { 993 m_assembler.vsub(dest, dest, src); 994 } 995 996 void subDouble(Address src, FPRegisterID dest) 997 { 998 loadDouble(src, fpTempRegister); 999 subDouble(fpTempRegister, dest); 1000 } 1001 1002 void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 1003 { 1004 m_assembler.vsub(dest, op1, op2); 1005 } 1006 1007 void mulDouble(FPRegisterID src, FPRegisterID dest) 1008 { 1009 m_assembler.vmul(dest, dest, src); 1010 } 1011 1012 void mulDouble(Address src, FPRegisterID dest) 1013 { 1014 loadDouble(src, fpTempRegister); 1015 mulDouble(fpTempRegister, dest); 1016 } 1017 1018 void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest) 1019 { 1020 m_assembler.vmul(dest, op1, op2); 1021 } 1022 1023 void sqrtDouble(FPRegisterID src, FPRegisterID dest) 1024 { 1025 m_assembler.vsqrt(dest, src); 1026 } 1027 1028 void absDouble(FPRegisterID src, FPRegisterID dest) 1029 { 1030 m_assembler.vabs(dest, src); 1031 } 1032 1033 void negateDouble(FPRegisterID src, FPRegisterID dest) 1034 { 1035 m_assembler.vneg(dest, src); 1036 } 1037 1038 void convertInt32ToDouble(RegisterID src, FPRegisterID dest) 1039 { 1040 m_assembler.vmov(fpTempRegister, src, src); 1041 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle()); 1042 } 1043 1044 void convertInt32ToDouble(Address address, FPRegisterID dest) 1045 { 1046 // Fixme: load directly into the fpr! 1047 load32(address, dataTempRegister); 1048 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister); 1049 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle()); 1050 } 1051 1052 void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest) 1053 { 1054 // Fixme: load directly into the fpr! 1055 load32(address.m_ptr, dataTempRegister); 1056 m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister); 1057 m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle()); 1058 } 1059 1060 void convertFloatToDouble(FPRegisterID src, FPRegisterID dst) 1061 { 1062 m_assembler.vcvtds(dst, ARMRegisters::asSingle(src)); 1063 } 1064 1065 void convertDoubleToFloat(FPRegisterID src, FPRegisterID dst) 1066 { 1067 m_assembler.vcvtsd(ARMRegisters::asSingle(dst), src); 1068 } 1069 1070 Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) 1071 { 1072 m_assembler.vcmp(left, right); 1073 m_assembler.vmrs(); 1074 1075 if (cond == DoubleNotEqual) { 1076 // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. 1077 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); 1078 Jump result = makeBranch(ARMv7Assembler::ConditionNE); 1079 unordered.link(this); 1080 return result; 1081 } 1082 if (cond == DoubleEqualOrUnordered) { 1083 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); 1084 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); 1085 unordered.link(this); 1086 // We get here if either unordered or equal. 1087 Jump result = jump(); 1088 notEqual.link(this); 1089 return result; 1090 } 1091 return makeBranch(cond); 1092 } 1093 1094 enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful }; 1095 Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) 1096 { 1097 // Convert into dest. 1098 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src); 1099 m_assembler.vmov(dest, fpTempRegisterAsSingle()); 1100 1101 // Calculate 2x dest. If the value potentially underflowed, it will have 1102 // clamped to 0x80000000, so 2x dest is zero in this case. In the case of 1103 // overflow the result will be equal to -2. 1104 Jump underflow = branchAdd32(Zero, dest, dest, dataTempRegister); 1105 Jump noOverflow = branch32(NotEqual, dataTempRegister, TrustedImm32(-2)); 1106 1107 // For BranchIfTruncateSuccessful, we branch if 'noOverflow' jumps. 1108 underflow.link(this); 1109 if (branchType == BranchIfTruncateSuccessful) 1110 return noOverflow; 1111 1112 // We'll reach the current point in the code on failure, so plant a 1113 // jump here & link the success case. 1114 Jump failure = jump(); 1115 noOverflow.link(this); 1116 return failure; 1117 } 1118 1119 // Result is undefined if the value is outside of the integer range. 1120 void truncateDoubleToInt32(FPRegisterID src, RegisterID dest) 1121 { 1122 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src); 1123 m_assembler.vmov(dest, fpTempRegisterAsSingle()); 1124 } 1125 1126 void truncateDoubleToUint32(FPRegisterID src, RegisterID dest) 1127 { 1128 m_assembler.vcvt_floatingPointToUnsigned(fpTempRegisterAsSingle(), src); 1129 m_assembler.vmov(dest, fpTempRegisterAsSingle()); 1130 } 1131 1132 // Convert 'src' to an integer, and places the resulting 'dest'. 1133 // If the result is not representable as a 32 bit value, branch. 1134 // May also branch for some values that are representable in 32 bits 1135 // (specifically, in this case, 0). 1136 void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID, bool negZeroCheck = true) 1137 { 1138 m_assembler.vcvt_floatingPointToSigned(fpTempRegisterAsSingle(), src); 1139 m_assembler.vmov(dest, fpTempRegisterAsSingle()); 1140 1141 // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. 1142 m_assembler.vcvt_signedToFloatingPoint(fpTempRegister, fpTempRegisterAsSingle()); 1143 failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister)); 1144 1145 // If the result is zero, it might have been -0.0, and the double comparison won't catch this! 1146 if (negZeroCheck) 1147 failureCases.append(branchTest32(Zero, dest)); 1148 } 1149 1150 Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID) 1151 { 1152 m_assembler.vcmpz(reg); 1153 m_assembler.vmrs(); 1154 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); 1155 Jump result = makeBranch(ARMv7Assembler::ConditionNE); 1156 unordered.link(this); 1157 return result; 1158 } 1159 1160 Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID) 1161 { 1162 m_assembler.vcmpz(reg); 1163 m_assembler.vmrs(); 1164 Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); 1165 Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); 1166 unordered.link(this); 1167 // We get here if either unordered or equal. 1168 Jump result = jump(); 1169 notEqual.link(this); 1170 return result; 1171 } 1172 1173 // Stack manipulation operations: 1174 // 1175 // The ABI is assumed to provide a stack abstraction to memory, 1176 // containing machine word sized units of data. Push and pop 1177 // operations add and remove a single register sized unit of data 1178 // to or from the stack. Peek and poke operations read or write 1179 // values on the stack, without moving the current stack position. 1180 1181 void pop(RegisterID dest) 1182 { 1183 m_assembler.pop(dest); 1184 } 1185 1186 void push(RegisterID src) 1187 { 1188 m_assembler.push(src); 1189 } 1190 1191 void push(Address address) 1192 { 1193 load32(address, dataTempRegister); 1194 push(dataTempRegister); 1195 } 1196 1197 void push(TrustedImm32 imm) 1198 { 1199 move(imm, dataTempRegister); 1200 push(dataTempRegister); 1201 } 1202 1203 void popPair(RegisterID dest1, RegisterID dest2) 1204 { 1205 m_assembler.pop(1 << dest1 | 1 << dest2); 1206 } 1207 1208 void pushPair(RegisterID src1, RegisterID src2) 1209 { 1210 m_assembler.push(1 << src1 | 1 << src2); 1211 } 1212 1213 // Register move operations: 1214 // 1215 // Move values in registers. 1216 1217 void move(TrustedImm32 imm, RegisterID dest) 1218 { 1219 uint32_t value = imm.m_value; 1220 1221 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value); 1222 1223 if (armImm.isValid()) 1224 m_assembler.mov(dest, armImm); 1225 else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid()) 1226 m_assembler.mvn(dest, armImm); 1227 else { 1228 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value)); 1229 if (value & 0xffff0000) 1230 m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16)); 1231 } 1232 } 1233 1234 void move(RegisterID src, RegisterID dest) 1235 { 1236 if (src != dest) 1237 m_assembler.mov(dest, src); 1238 } 1239 1240 void move(TrustedImmPtr imm, RegisterID dest) 1241 { 1242 move(TrustedImm32(imm), dest); 1243 } 1244 1245 void swap(RegisterID reg1, RegisterID reg2) 1246 { 1247 move(reg1, dataTempRegister); 1248 move(reg2, reg1); 1249 move(dataTempRegister, reg2); 1250 } 1251 1252 void signExtend32ToPtr(RegisterID src, RegisterID dest) 1253 { 1254 move(src, dest); 1255 } 1256 1257 void zeroExtend32ToPtr(RegisterID src, RegisterID dest) 1258 { 1259 move(src, dest); 1260 } 1261 1262 // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc. 1263 static RelationalCondition invert(RelationalCondition cond) 1264 { 1265 return static_cast<RelationalCondition>(cond ^ 1); 1266 } 1267 1268 void nop() 1269 { 1270 m_assembler.nop(); 1271 } 1272 1273 void memoryFence() 1274 { 1275 m_assembler.dmbSY(); 1276 } 1277 1278 static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination) 1279 { 1280 ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation()); 1281 } 1282 1283 static ptrdiff_t maxJumpReplacementSize() 1284 { 1285 return ARMv7Assembler::maxJumpReplacementSize(); 1286 } 1287 1288 // Forwards / external control flow operations: 1289 // 1290 // This set of jump and conditional branch operations return a Jump 1291 // object which may linked at a later point, allow forwards jump, 1292 // or jumps that will require external linkage (after the code has been 1293 // relocated). 1294 // 1295 // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge 1296 // respecitvely, for unsigned comparisons the names b, a, be, and ae are 1297 // used (representing the names 'below' and 'above'). 1298 // 1299 // Operands to the comparision are provided in the expected order, e.g. 1300 // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when 1301 // treated as a signed 32bit value, is less than or equal to 5. 1302 // 1303 // jz and jnz test whether the first operand is equal to zero, and take 1304 // an optional second operand of a mask under which to perform the test. 1305private: 1306 1307 // Should we be using TEQ for equal/not-equal? 1308 void compare32(RegisterID left, TrustedImm32 right) 1309 { 1310 int32_t imm = right.m_value; 1311 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); 1312 if (armImm.isValid()) 1313 m_assembler.cmp(left, armImm); 1314 else if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid()) 1315 m_assembler.cmn(left, armImm); 1316 else { 1317 move(TrustedImm32(imm), dataTempRegister); 1318 m_assembler.cmp(left, dataTempRegister); 1319 } 1320 } 1321 1322 void test32(RegisterID reg, TrustedImm32 mask) 1323 { 1324 int32_t imm = mask.m_value; 1325 1326 if (imm == -1) 1327 m_assembler.tst(reg, reg); 1328 else { 1329 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); 1330 if (armImm.isValid()) { 1331 if (reg == ARMRegisters::sp) { 1332 move(reg, addressTempRegister); 1333 m_assembler.tst(addressTempRegister, armImm); 1334 } else 1335 m_assembler.tst(reg, armImm); 1336 } else { 1337 move(mask, dataTempRegister); 1338 if (reg == ARMRegisters::sp) { 1339 move(reg, addressTempRegister); 1340 m_assembler.tst(addressTempRegister, dataTempRegister); 1341 } else 1342 m_assembler.tst(reg, dataTempRegister); 1343 } 1344 } 1345 } 1346 1347public: 1348 void test32(ResultCondition, RegisterID reg, TrustedImm32 mask) 1349 { 1350 test32(reg, mask); 1351 } 1352 1353 Jump branch(ResultCondition cond) 1354 { 1355 return Jump(makeBranch(cond)); 1356 } 1357 1358 Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right) 1359 { 1360 m_assembler.cmp(left, right); 1361 return Jump(makeBranch(cond)); 1362 } 1363 1364 Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right) 1365 { 1366 compare32(left, right); 1367 return Jump(makeBranch(cond)); 1368 } 1369 1370 Jump branch32(RelationalCondition cond, RegisterID left, Address right) 1371 { 1372 load32(right, dataTempRegister); 1373 return branch32(cond, left, dataTempRegister); 1374 } 1375 1376 Jump branch32(RelationalCondition cond, Address left, RegisterID right) 1377 { 1378 load32(left, dataTempRegister); 1379 return branch32(cond, dataTempRegister, right); 1380 } 1381 1382 Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right) 1383 { 1384 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 1385 load32(left, addressTempRegister); 1386 return branch32(cond, addressTempRegister, right); 1387 } 1388 1389 Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1390 { 1391 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 1392 load32(left, addressTempRegister); 1393 return branch32(cond, addressTempRegister, right); 1394 } 1395 1396 Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1397 { 1398 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 1399 load32WithUnalignedHalfWords(left, addressTempRegister); 1400 return branch32(cond, addressTempRegister, right); 1401 } 1402 1403 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) 1404 { 1405 load32(left.m_ptr, dataTempRegister); 1406 return branch32(cond, dataTempRegister, right); 1407 } 1408 1409 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) 1410 { 1411 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 1412 load32(left.m_ptr, addressTempRegister); 1413 return branch32(cond, addressTempRegister, right); 1414 } 1415 1416 Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right) 1417 { 1418 load32(left, dataTempRegister); 1419 return branch32(cond, dataTempRegister, right); 1420 } 1421 1422 Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right) 1423 { 1424 compare32(left, right); 1425 return Jump(makeBranch(cond)); 1426 } 1427 1428 Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right) 1429 { 1430 ASSERT(!(0xffffff00 & right.m_value)); 1431 // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ 1432 load8(left, addressTempRegister); 1433 return branch8(cond, addressTempRegister, right); 1434 } 1435 1436 Jump branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right) 1437 { 1438 ASSERT(!(0xffffff00 & right.m_value)); 1439 // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ 1440 load8(left, addressTempRegister); 1441 return branch32(cond, addressTempRegister, right); 1442 } 1443 1444 Jump branch8(RelationalCondition cond, AbsoluteAddress address, TrustedImm32 right) 1445 { 1446 // Use addressTempRegister instead of dataTempRegister, since branch32 uses dataTempRegister. 1447 move(TrustedImmPtr(address.m_ptr), addressTempRegister); 1448 load8(Address(addressTempRegister), addressTempRegister); 1449 return branch32(cond, addressTempRegister, right); 1450 } 1451 1452 Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) 1453 { 1454 m_assembler.tst(reg, mask); 1455 return Jump(makeBranch(cond)); 1456 } 1457 1458 Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) 1459 { 1460 test32(reg, mask); 1461 return Jump(makeBranch(cond)); 1462 } 1463 1464 Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 1465 { 1466 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ 1467 load32(address, addressTempRegister); 1468 return branchTest32(cond, addressTempRegister, mask); 1469 } 1470 1471 Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) 1472 { 1473 // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ 1474 load32(address, addressTempRegister); 1475 return branchTest32(cond, addressTempRegister, mask); 1476 } 1477 1478 Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) 1479 { 1480 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ 1481 load8(address, addressTempRegister); 1482 return branchTest32(cond, addressTempRegister, mask); 1483 } 1484 1485 Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) 1486 { 1487 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ 1488 load8(address, addressTempRegister); 1489 return branchTest32(cond, addressTempRegister, mask); 1490 } 1491 1492 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 1493 { 1494 // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ 1495 move(TrustedImmPtr(address.m_ptr), addressTempRegister); 1496 load8(Address(addressTempRegister), addressTempRegister); 1497 return branchTest32(cond, addressTempRegister, mask); 1498 } 1499 1500 void jump(RegisterID target) 1501 { 1502 m_assembler.bx(target); 1503 } 1504 1505 // Address is a memory location containing the address to jump to 1506 void jump(Address address) 1507 { 1508 load32(address, dataTempRegister); 1509 m_assembler.bx(dataTempRegister); 1510 } 1511 1512 void jump(AbsoluteAddress address) 1513 { 1514 move(TrustedImmPtr(address.m_ptr), dataTempRegister); 1515 load32(Address(dataTempRegister), dataTempRegister); 1516 m_assembler.bx(dataTempRegister); 1517 } 1518 1519 1520 // Arithmetic control flow operations: 1521 // 1522 // This set of conditional branch operations branch based 1523 // on the result of an arithmetic operation. The operation 1524 // is performed as normal, storing the result. 1525 // 1526 // * jz operations branch if the result is zero. 1527 // * jo operations branch if the (signed) arithmetic 1528 // operation caused an overflow to occur. 1529 1530 Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) 1531 { 1532 m_assembler.add_S(dest, op1, op2); 1533 return Jump(makeBranch(cond)); 1534 } 1535 1536 Jump branchAdd32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest) 1537 { 1538 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 1539 if (armImm.isValid()) 1540 m_assembler.add_S(dest, op1, armImm); 1541 else { 1542 move(imm, dataTempRegister); 1543 m_assembler.add_S(dest, op1, dataTempRegister); 1544 } 1545 return Jump(makeBranch(cond)); 1546 } 1547 1548 Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) 1549 { 1550 return branchAdd32(cond, dest, src, dest); 1551 } 1552 1553 Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) 1554 { 1555 load32(src, dataTempRegister); 1556 return branchAdd32(cond, dest, dataTempRegister, dest); 1557 } 1558 1559 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) 1560 { 1561 return branchAdd32(cond, dest, imm, dest); 1562 } 1563 1564 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest) 1565 { 1566 // Move the high bits of the address into addressTempRegister, 1567 // and load the value into dataTempRegister. 1568 move(TrustedImmPtr(dest.m_ptr), addressTempRegister); 1569 m_assembler.ldr(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 1570 1571 // Do the add. 1572 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 1573 if (armImm.isValid()) 1574 m_assembler.add_S(dataTempRegister, dataTempRegister, armImm); 1575 else { 1576 // If the operand does not fit into an immediate then load it temporarily 1577 // into addressTempRegister; since we're overwriting addressTempRegister 1578 // we'll need to reload it with the high bits of the address afterwards. 1579 move(imm, addressTempRegister); 1580 m_assembler.add_S(dataTempRegister, dataTempRegister, addressTempRegister); 1581 move(TrustedImmPtr(dest.m_ptr), addressTempRegister); 1582 } 1583 1584 // Store the result. 1585 m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); 1586 1587 return Jump(makeBranch(cond)); 1588 } 1589 1590 Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) 1591 { 1592 m_assembler.smull(dest, dataTempRegister, src1, src2); 1593 1594 if (cond == Overflow) { 1595 m_assembler.asr(addressTempRegister, dest, 31); 1596 return branch32(NotEqual, addressTempRegister, dataTempRegister); 1597 } 1598 1599 return branchTest32(cond, dest); 1600 } 1601 1602 Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest) 1603 { 1604 return branchMul32(cond, src, dest, dest); 1605 } 1606 1607 Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest) 1608 { 1609 move(imm, dataTempRegister); 1610 return branchMul32(cond, dataTempRegister, src, dest); 1611 } 1612 1613 Jump branchNeg32(ResultCondition cond, RegisterID srcDest) 1614 { 1615 ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0); 1616 m_assembler.sub_S(srcDest, zero, srcDest); 1617 return Jump(makeBranch(cond)); 1618 } 1619 1620 Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest) 1621 { 1622 m_assembler.orr_S(dest, dest, src); 1623 return Jump(makeBranch(cond)); 1624 } 1625 1626 Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) 1627 { 1628 m_assembler.sub_S(dest, op1, op2); 1629 return Jump(makeBranch(cond)); 1630 } 1631 1632 Jump branchSub32(ResultCondition cond, RegisterID op1, TrustedImm32 imm, RegisterID dest) 1633 { 1634 ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); 1635 if (armImm.isValid()) 1636 m_assembler.sub_S(dest, op1, armImm); 1637 else { 1638 move(imm, dataTempRegister); 1639 m_assembler.sub_S(dest, op1, dataTempRegister); 1640 } 1641 return Jump(makeBranch(cond)); 1642 } 1643 1644 Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest) 1645 { 1646 return branchSub32(cond, dest, src, dest); 1647 } 1648 1649 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) 1650 { 1651 return branchSub32(cond, dest, imm, dest); 1652 } 1653 1654 void relativeTableJump(RegisterID index, int scale) 1655 { 1656 ASSERT(scale >= 0 && scale <= 31); 1657 1658 // dataTempRegister will point after the jump if index register contains zero 1659 move(ARMRegisters::pc, dataTempRegister); 1660 m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9)); 1661 1662 ShiftTypeAndAmount shift(SRType_LSL, scale); 1663 m_assembler.add(dataTempRegister, dataTempRegister, index, shift); 1664 jump(dataTempRegister); 1665 } 1666 1667 // Miscellaneous operations: 1668 1669 void breakpoint(uint8_t imm = 0) 1670 { 1671 m_assembler.bkpt(imm); 1672 } 1673 1674 ALWAYS_INLINE Call nearCall() 1675 { 1676 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); 1677 return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear); 1678 } 1679 1680 ALWAYS_INLINE Call call() 1681 { 1682 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); 1683 return Call(m_assembler.blx(dataTempRegister), Call::Linkable); 1684 } 1685 1686 ALWAYS_INLINE Call call(RegisterID target) 1687 { 1688 return Call(m_assembler.blx(target), Call::None); 1689 } 1690 1691 ALWAYS_INLINE Call call(Address address) 1692 { 1693 load32(address, dataTempRegister); 1694 return Call(m_assembler.blx(dataTempRegister), Call::None); 1695 } 1696 1697 ALWAYS_INLINE void ret() 1698 { 1699 m_assembler.bx(linkRegister); 1700 } 1701 1702 void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest) 1703 { 1704 m_assembler.cmp(left, right); 1705 m_assembler.it(armV7Condition(cond), false); 1706 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 1707 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 1708 } 1709 1710 void compare32(RelationalCondition cond, Address left, RegisterID right, RegisterID dest) 1711 { 1712 load32(left, dataTempRegister); 1713 compare32(cond, dataTempRegister, right, dest); 1714 } 1715 1716 void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest) 1717 { 1718 load8(left, addressTempRegister); 1719 compare32(cond, addressTempRegister, right, dest); 1720 } 1721 1722 void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest) 1723 { 1724 compare32(left, right); 1725 m_assembler.it(armV7Condition(cond), false); 1726 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 1727 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 1728 } 1729 1730 // FIXME: 1731 // The mask should be optional... paerhaps the argument order should be 1732 // dest-src, operations always have a dest? ... possibly not true, considering 1733 // asm ops like test, or pseudo ops like pop(). 1734 void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) 1735 { 1736 load32(address, dataTempRegister); 1737 test32(dataTempRegister, mask); 1738 m_assembler.it(armV7Condition(cond), false); 1739 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 1740 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 1741 } 1742 1743 void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) 1744 { 1745 load8(address, dataTempRegister); 1746 test32(dataTempRegister, mask); 1747 m_assembler.it(armV7Condition(cond), false); 1748 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); 1749 m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); 1750 } 1751 1752 ALWAYS_INLINE DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dst) 1753 { 1754 padBeforePatch(); 1755 moveFixedWidthEncoding(imm, dst); 1756 return DataLabel32(this); 1757 } 1758 1759 ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst) 1760 { 1761 padBeforePatch(); 1762 moveFixedWidthEncoding(TrustedImm32(imm), dst); 1763 return DataLabelPtr(this); 1764 } 1765 1766 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 1767 { 1768 dataLabel = moveWithPatch(initialRightValue, dataTempRegister); 1769 return branch32(cond, left, dataTempRegister); 1770 } 1771 1772 ALWAYS_INLINE Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 1773 { 1774 load32(left, addressTempRegister); 1775 dataLabel = moveWithPatch(initialRightValue, dataTempRegister); 1776 return branch32(cond, addressTempRegister, dataTempRegister); 1777 } 1778 1779 ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) 1780 { 1781 load32(left, addressTempRegister); 1782 dataLabel = moveWithPatch(initialRightValue, dataTempRegister); 1783 return branch32(cond, addressTempRegister, dataTempRegister); 1784 } 1785 1786 PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0)) 1787 { 1788 m_makeJumpPatchable = true; 1789 Jump result = branch32(cond, left, TrustedImm32(right)); 1790 m_makeJumpPatchable = false; 1791 return PatchableJump(result); 1792 } 1793 1794 PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) 1795 { 1796 m_makeJumpPatchable = true; 1797 Jump result = branchTest32(cond, reg, mask); 1798 m_makeJumpPatchable = false; 1799 return PatchableJump(result); 1800 } 1801 1802 PatchableJump patchableBranch32(RelationalCondition cond, RegisterID reg, TrustedImm32 imm) 1803 { 1804 m_makeJumpPatchable = true; 1805 Jump result = branch32(cond, reg, imm); 1806 m_makeJumpPatchable = false; 1807 return PatchableJump(result); 1808 } 1809 1810 PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 1811 { 1812 m_makeJumpPatchable = true; 1813 Jump result = branchPtrWithPatch(cond, left, dataLabel, initialRightValue); 1814 m_makeJumpPatchable = false; 1815 return PatchableJump(result); 1816 } 1817 1818 PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) 1819 { 1820 m_makeJumpPatchable = true; 1821 Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue); 1822 m_makeJumpPatchable = false; 1823 return PatchableJump(result); 1824 } 1825 1826 PatchableJump patchableJump() 1827 { 1828 padBeforePatch(); 1829 m_makeJumpPatchable = true; 1830 Jump result = jump(); 1831 m_makeJumpPatchable = false; 1832 return PatchableJump(result); 1833 } 1834 1835 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) 1836 { 1837 DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); 1838 store32(dataTempRegister, address); 1839 return label; 1840 } 1841 ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); } 1842 1843 1844 ALWAYS_INLINE Call tailRecursiveCall() 1845 { 1846 // Like a normal call, but don't link. 1847 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); 1848 return Call(m_assembler.bx(dataTempRegister), Call::Linkable); 1849 } 1850 1851 ALWAYS_INLINE Call makeTailRecursiveCall(Jump oldJump) 1852 { 1853 oldJump.link(this); 1854 return tailRecursiveCall(); 1855 } 1856 1857 1858 static FunctionPtr readCallTarget(CodeLocationCall call) 1859 { 1860 return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation()))); 1861 } 1862 1863 static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } 1864 static bool canJumpReplacePatchableBranch32WithPatch() { return false; } 1865 1866 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) 1867 { 1868 const unsigned twoWordOpSize = 4; 1869 return label.labelAtOffset(-twoWordOpSize * 2); 1870 } 1871 1872 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue) 1873 { 1874#if OS(LINUX) 1875 ARMv7Assembler::revertJumpTo_movT3movtcmpT2(instructionStart.dataLocation(), rd, dataTempRegister, reinterpret_cast<uintptr_t>(initialValue)); 1876#else 1877 UNUSED_PARAM(rd); 1878 ARMv7Assembler::revertJumpTo_movT3(instructionStart.dataLocation(), dataTempRegister, ARMThumbImmediate::makeUInt16(reinterpret_cast<uintptr_t>(initialValue) & 0xffff)); 1879#endif 1880 } 1881 1882 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr) 1883 { 1884 UNREACHABLE_FOR_PLATFORM(); 1885 return CodeLocationLabel(); 1886 } 1887 1888 static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32) 1889 { 1890 UNREACHABLE_FOR_PLATFORM(); 1891 return CodeLocationLabel(); 1892 } 1893 1894 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel, Address, void*) 1895 { 1896 UNREACHABLE_FOR_PLATFORM(); 1897 } 1898 1899 static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t) 1900 { 1901 UNREACHABLE_FOR_PLATFORM(); 1902 } 1903 1904#if USE(MASM_PROBE) 1905 struct CPUState { 1906 #define DECLARE_REGISTER(_type, _regName) \ 1907 _type _regName; 1908 FOR_EACH_CPU_REGISTER(DECLARE_REGISTER) 1909 #undef DECLARE_REGISTER 1910 }; 1911 1912 struct ProbeContext; 1913 typedef void (*ProbeFunction)(struct ProbeContext*); 1914 1915 struct ProbeContext { 1916 ProbeFunction probeFunction; 1917 void* arg1; 1918 void* arg2; 1919 CPUState cpu; 1920 1921 void dump(const char* indentation = 0); 1922 private: 1923 void dumpCPURegisters(const char* indentation); 1924 }; 1925 1926 // For details about probe(), see comment in MacroAssemblerX86_64.h. 1927 void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); 1928#endif // USE(MASM_PROBE) 1929 1930protected: 1931 ALWAYS_INLINE Jump jump() 1932 { 1933 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. 1934 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); 1935 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition); 1936 } 1937 1938 ALWAYS_INLINE Jump makeBranch(ARMv7Assembler::Condition cond) 1939 { 1940 m_assembler.label(); // Force nop-padding if we're in the middle of a watchpoint. 1941 m_assembler.it(cond, true, true); 1942 moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister); 1943 return Jump(m_assembler.bx(dataTempRegister), m_makeJumpPatchable ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond); 1944 } 1945 ALWAYS_INLINE Jump makeBranch(RelationalCondition cond) { return makeBranch(armV7Condition(cond)); } 1946 ALWAYS_INLINE Jump makeBranch(ResultCondition cond) { return makeBranch(armV7Condition(cond)); } 1947 ALWAYS_INLINE Jump makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } 1948 1949 ArmAddress setupArmAddress(BaseIndex address) 1950 { 1951 if (address.offset) { 1952 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); 1953 if (imm.isValid()) 1954 m_assembler.add(addressTempRegister, address.base, imm); 1955 else { 1956 move(TrustedImm32(address.offset), addressTempRegister); 1957 m_assembler.add(addressTempRegister, addressTempRegister, address.base); 1958 } 1959 1960 return ArmAddress(addressTempRegister, address.index, address.scale); 1961 } else 1962 return ArmAddress(address.base, address.index, address.scale); 1963 } 1964 1965 ArmAddress setupArmAddress(Address address) 1966 { 1967 if ((address.offset >= -0xff) && (address.offset <= 0xfff)) 1968 return ArmAddress(address.base, address.offset); 1969 1970 move(TrustedImm32(address.offset), addressTempRegister); 1971 return ArmAddress(address.base, addressTempRegister); 1972 } 1973 1974 ArmAddress setupArmAddress(ImplicitAddress address) 1975 { 1976 if ((address.offset >= -0xff) && (address.offset <= 0xfff)) 1977 return ArmAddress(address.base, address.offset); 1978 1979 move(TrustedImm32(address.offset), addressTempRegister); 1980 return ArmAddress(address.base, addressTempRegister); 1981 } 1982 1983 RegisterID makeBaseIndexBase(BaseIndex address) 1984 { 1985 if (!address.offset) 1986 return address.base; 1987 1988 ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); 1989 if (imm.isValid()) 1990 m_assembler.add(addressTempRegister, address.base, imm); 1991 else { 1992 move(TrustedImm32(address.offset), addressTempRegister); 1993 m_assembler.add(addressTempRegister, addressTempRegister, address.base); 1994 } 1995 1996 return addressTempRegister; 1997 } 1998 1999 void moveFixedWidthEncoding(TrustedImm32 imm, RegisterID dst) 2000 { 2001 uint32_t value = imm.m_value; 2002 m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); 2003 m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16)); 2004 } 2005 2006 ARMv7Assembler::Condition armV7Condition(RelationalCondition cond) 2007 { 2008 return static_cast<ARMv7Assembler::Condition>(cond); 2009 } 2010 2011 ARMv7Assembler::Condition armV7Condition(ResultCondition cond) 2012 { 2013 return static_cast<ARMv7Assembler::Condition>(cond); 2014 } 2015 2016 ARMv7Assembler::Condition armV7Condition(DoubleCondition cond) 2017 { 2018 return static_cast<ARMv7Assembler::Condition>(cond); 2019 } 2020 2021private: 2022 friend class LinkBuffer; 2023 friend class RepatchBuffer; 2024 2025 static void linkCall(void* code, Call call, FunctionPtr function) 2026 { 2027 ARMv7Assembler::linkCall(code, call.m_label, function.value()); 2028 } 2029 2030 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 2031 { 2032 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 2033 } 2034 2035 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 2036 { 2037 ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 2038 } 2039 2040#if USE(MASM_PROBE) 2041 inline TrustedImm32 trustedImm32FromPtr(void* ptr) 2042 { 2043 return TrustedImm32(TrustedImmPtr(ptr)); 2044 } 2045 2046 inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function) 2047 { 2048 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); 2049 } 2050 2051 inline TrustedImm32 trustedImm32FromPtr(void (*function)()) 2052 { 2053 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); 2054 } 2055#endif 2056 2057 bool m_makeJumpPatchable; 2058}; 2059 2060} // namespace JSC 2061 2062#endif // ENABLE(ASSEMBLER) 2063 2064#endif // MacroAssemblerARMv7_h 2065