1/* 2 * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef MacroAssemblerX86_h 27#define MacroAssemblerX86_h 28 29#if ENABLE(ASSEMBLER) && CPU(X86) 30 31#include "MacroAssemblerX86Common.h" 32 33#if USE(MASM_PROBE) 34#include <wtf/StdLibExtras.h> 35#endif 36 37namespace JSC { 38 39class MacroAssemblerX86 : public MacroAssemblerX86Common { 40public: 41 static const Scale ScalePtr = TimesFour; 42 43 using MacroAssemblerX86Common::add32; 44 using MacroAssemblerX86Common::and32; 45 using MacroAssemblerX86Common::branchAdd32; 46 using MacroAssemblerX86Common::branchSub32; 47 using MacroAssemblerX86Common::sub32; 48 using MacroAssemblerX86Common::or32; 49 using MacroAssemblerX86Common::load32; 50 using MacroAssemblerX86Common::load8; 51 using MacroAssemblerX86Common::store32; 52 using MacroAssemblerX86Common::store8; 53 using MacroAssemblerX86Common::branch32; 54 using MacroAssemblerX86Common::call; 55 using MacroAssemblerX86Common::jump; 56 using MacroAssemblerX86Common::addDouble; 57 using MacroAssemblerX86Common::loadDouble; 58 using MacroAssemblerX86Common::storeDouble; 59 using MacroAssemblerX86Common::convertInt32ToDouble; 60 using MacroAssemblerX86Common::branch8; 61 using MacroAssemblerX86Common::branchTest8; 62 63 void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) 64 { 65 m_assembler.leal_mr(imm.m_value, src, dest); 66 } 67 68 void add32(TrustedImm32 imm, AbsoluteAddress address) 69 { 70 m_assembler.addl_im(imm.m_value, address.m_ptr); 71 } 72 73 void add32(AbsoluteAddress address, RegisterID dest) 74 { 75 m_assembler.addl_mr(address.m_ptr, dest); 76 } 77 78 void add64(TrustedImm32 imm, AbsoluteAddress address) 79 { 80 m_assembler.addl_im(imm.m_value, address.m_ptr); 81 m_assembler.adcl_im(imm.m_value >> 31, reinterpret_cast<const char*>(address.m_ptr) + sizeof(int32_t)); 82 } 83 84 void and32(TrustedImm32 imm, AbsoluteAddress address) 85 { 86 m_assembler.andl_im(imm.m_value, address.m_ptr); 87 } 88 89 void or32(TrustedImm32 imm, AbsoluteAddress address) 90 { 91 m_assembler.orl_im(imm.m_value, address.m_ptr); 92 } 93 94 void or32(RegisterID reg, AbsoluteAddress address) 95 { 96 m_assembler.orl_rm(reg, address.m_ptr); 97 } 98 99 void sub32(TrustedImm32 imm, AbsoluteAddress address) 100 { 101 m_assembler.subl_im(imm.m_value, address.m_ptr); 102 } 103 104 void load32(const void* address, RegisterID dest) 105 { 106 m_assembler.movl_mr(address, dest); 107 } 108 109 void load8(const void* address, RegisterID dest) 110 { 111 m_assembler.movzbl_mr(address, dest); 112 } 113 114 void abortWithReason(AbortReason reason) 115 { 116 move(TrustedImm32(reason), X86Registers::eax); 117 breakpoint(); 118 } 119 120 void abortWithReason(AbortReason reason, intptr_t misc) 121 { 122 move(TrustedImm32(misc), X86Registers::edx); 123 abortWithReason(reason); 124 } 125 126 ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) 127 { 128 ConvertibleLoadLabel result = ConvertibleLoadLabel(this); 129 m_assembler.movl_mr(address.offset, address.base, dest); 130 return result; 131 } 132 133 void addDouble(AbsoluteAddress address, FPRegisterID dest) 134 { 135 m_assembler.addsd_mr(address.m_ptr, dest); 136 } 137 138 void storeDouble(FPRegisterID src, TrustedImmPtr address) 139 { 140 ASSERT(isSSE2Present()); 141 ASSERT(address.m_value); 142 m_assembler.movsd_rm(src, address.m_value); 143 } 144 145 void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) 146 { 147 m_assembler.cvtsi2sd_mr(src.m_ptr, dest); 148 } 149 150 void store32(TrustedImm32 imm, void* address) 151 { 152 m_assembler.movl_i32m(imm.m_value, address); 153 } 154 155 void store32(RegisterID src, void* address) 156 { 157 m_assembler.movl_rm(src, address); 158 } 159 160 void store8(RegisterID src, void* address) 161 { 162 m_assembler.movb_rm(src, address); 163 } 164 165 void store8(TrustedImm32 imm, void* address) 166 { 167 ASSERT(-128 <= imm.m_value && imm.m_value < 128); 168 m_assembler.movb_i8m(imm.m_value, address); 169 } 170 171 // Possibly clobbers src. 172 // FIXME: Don't do that. 173 // https://bugs.webkit.org/show_bug.cgi?id=131690 174 void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2) 175 { 176 movePackedToInt32(src, dest1); 177 rshiftPacked(TrustedImm32(32), src); 178 movePackedToInt32(src, dest2); 179 } 180 181 void moveIntsToDouble(RegisterID src1, RegisterID src2, FPRegisterID dest, FPRegisterID scratch) 182 { 183 moveInt32ToPacked(src1, dest); 184 moveInt32ToPacked(src2, scratch); 185 lshiftPacked(TrustedImm32(32), scratch); 186 orPacked(scratch, dest); 187 } 188 189 Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest) 190 { 191 m_assembler.addl_im(imm.m_value, dest.m_ptr); 192 return Jump(m_assembler.jCC(x86Condition(cond))); 193 } 194 195 Jump branchSub32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest) 196 { 197 m_assembler.subl_im(imm.m_value, dest.m_ptr); 198 return Jump(m_assembler.jCC(x86Condition(cond))); 199 } 200 201 Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) 202 { 203 m_assembler.cmpl_rm(right, left.m_ptr); 204 return Jump(m_assembler.jCC(x86Condition(cond))); 205 } 206 207 Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) 208 { 209 m_assembler.cmpl_im(right.m_value, left.m_ptr); 210 return Jump(m_assembler.jCC(x86Condition(cond))); 211 } 212 213 Call call() 214 { 215 return Call(m_assembler.call(), Call::Linkable); 216 } 217 218 // Address is a memory location containing the address to jump to 219 void jump(AbsoluteAddress address) 220 { 221 m_assembler.jmp_m(address.m_ptr); 222 } 223 224 Call tailRecursiveCall() 225 { 226 return Call::fromTailJump(jump()); 227 } 228 229 Call makeTailRecursiveCall(Jump oldJump) 230 { 231 return Call::fromTailJump(oldJump); 232 } 233 234 235 DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) 236 { 237 padBeforePatch(); 238 m_assembler.movl_i32r(initialValue.asIntptr(), dest); 239 return DataLabelPtr(this); 240 } 241 242 Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) 243 { 244 m_assembler.cmpb_im(right.m_value, left.m_ptr); 245 return Jump(m_assembler.jCC(x86Condition(cond))); 246 } 247 248 Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1)) 249 { 250 ASSERT(mask.m_value >= -128 && mask.m_value <= 255); 251 if (mask.m_value == -1) 252 m_assembler.cmpb_im(0, address.m_ptr); 253 else 254 m_assembler.testb_im(mask.m_value, address.m_ptr); 255 return Jump(m_assembler.jCC(x86Condition(cond))); 256 } 257 258 Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 259 { 260 padBeforePatch(); 261 m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left); 262 dataLabel = DataLabelPtr(this); 263 return Jump(m_assembler.jCC(x86Condition(cond))); 264 } 265 266 Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) 267 { 268 padBeforePatch(); 269 m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base); 270 dataLabel = DataLabelPtr(this); 271 return Jump(m_assembler.jCC(x86Condition(cond))); 272 } 273 274 Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) 275 { 276 padBeforePatch(); 277 m_assembler.cmpl_im_force32(initialRightValue.m_value, left.offset, left.base); 278 dataLabel = DataLabel32(this); 279 return Jump(m_assembler.jCC(x86Condition(cond))); 280 } 281 282 DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) 283 { 284 padBeforePatch(); 285 m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base); 286 return DataLabelPtr(this); 287 } 288 289 static bool supportsFloatingPoint() { return isSSE2Present(); } 290 // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() 291 static bool supportsFloatingPointTruncate() { return isSSE2Present(); } 292 static bool supportsFloatingPointSqrt() { return isSSE2Present(); } 293 static bool supportsFloatingPointAbs() { return isSSE2Present(); } 294 295 static FunctionPtr readCallTarget(CodeLocationCall call) 296 { 297 intptr_t offset = reinterpret_cast<int32_t*>(call.dataLocation())[-1]; 298 return FunctionPtr(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(call.dataLocation()) + offset)); 299 } 300 301 static bool canJumpReplacePatchableBranchPtrWithPatch() { return true; } 302 static bool canJumpReplacePatchableBranch32WithPatch() { return true; } 303 304 static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) 305 { 306 const int opcodeBytes = 1; 307 const int modRMBytes = 1; 308 const int immediateBytes = 4; 309 const int totalBytes = opcodeBytes + modRMBytes + immediateBytes; 310 ASSERT(totalBytes >= maxJumpReplacementSize()); 311 return label.labelAtOffset(-totalBytes); 312 } 313 314 static CodeLocationLabel startOfPatchableBranchPtrWithPatchOnAddress(CodeLocationDataLabelPtr label) 315 { 316 const int opcodeBytes = 1; 317 const int modRMBytes = 1; 318 const int offsetBytes = 0; 319 const int immediateBytes = 4; 320 const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes; 321 ASSERT(totalBytes >= maxJumpReplacementSize()); 322 return label.labelAtOffset(-totalBytes); 323 } 324 325 static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32 label) 326 { 327 const int opcodeBytes = 1; 328 const int modRMBytes = 1; 329 const int offsetBytes = 0; 330 const int immediateBytes = 4; 331 const int totalBytes = opcodeBytes + modRMBytes + offsetBytes + immediateBytes; 332 ASSERT(totalBytes >= maxJumpReplacementSize()); 333 return label.labelAtOffset(-totalBytes); 334 } 335 336 static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID reg, void* initialValue) 337 { 338 X86Assembler::revertJumpTo_cmpl_ir_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), reg); 339 } 340 341 static void revertJumpReplacementToPatchableBranchPtrWithPatch(CodeLocationLabel instructionStart, Address address, void* initialValue) 342 { 343 ASSERT(!address.offset); 344 X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), reinterpret_cast<intptr_t>(initialValue), 0, address.base); 345 } 346 347 static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel instructionStart, Address address, int32_t initialValue) 348 { 349 ASSERT(!address.offset); 350 X86Assembler::revertJumpTo_cmpl_im_force32(instructionStart.executableAddress(), initialValue, 0, address.base); 351 } 352 353#if USE(MASM_PROBE) 354 // For details about probe(), see comment in MacroAssemblerX86_64.h. 355 void probe(ProbeFunction, void* arg1 = 0, void* arg2 = 0); 356#endif // USE(MASM_PROBE) 357 358private: 359 friend class LinkBuffer; 360 friend class RepatchBuffer; 361 362 static void linkCall(void* code, Call call, FunctionPtr function) 363 { 364 X86Assembler::linkCall(code, call.m_label, function.value()); 365 } 366 367 static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) 368 { 369 X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 370 } 371 372 static void repatchCall(CodeLocationCall call, FunctionPtr destination) 373 { 374 X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); 375 } 376 377#if USE(MASM_PROBE) 378 inline TrustedImm32 trustedImm32FromPtr(void* ptr) 379 { 380 return TrustedImm32(TrustedImmPtr(ptr)); 381 } 382 383 inline TrustedImm32 trustedImm32FromPtr(ProbeFunction function) 384 { 385 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); 386 } 387 388 inline TrustedImm32 trustedImm32FromPtr(void (*function)()) 389 { 390 return TrustedImm32(TrustedImmPtr(reinterpret_cast<void*>(function))); 391 } 392#endif 393}; 394 395#if USE(MASM_PROBE) 396 397extern "C" void ctiMasmProbeTrampoline(); 398 399// For details on "What code is emitted for the probe?" and "What values are in 400// the saved registers?", see comment for MacroAssemblerX86::probe() in 401// MacroAssemblerX86_64.h. 402 403inline void MacroAssemblerX86::probe(MacroAssemblerX86::ProbeFunction function, void* arg1, void* arg2) 404{ 405 push(RegisterID::esp); 406 push(RegisterID::eax); 407 push(trustedImm32FromPtr(arg2)); 408 push(trustedImm32FromPtr(arg1)); 409 push(trustedImm32FromPtr(function)); 410 411 move(trustedImm32FromPtr(ctiMasmProbeTrampoline), RegisterID::eax); 412 call(RegisterID::eax); 413} 414#endif // USE(MASM_PROBE) 415 416} // namespace JSC 417 418#endif // ENABLE(ASSEMBLER) 419 420#endif // MacroAssemblerX86_h 421