1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/shared/Assembler-x86-shared.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1696 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_shared_Assembler_x86_shared_h 1.11 +#define jit_shared_Assembler_x86_shared_h 1.12 + 1.13 +#include <cstddef> 1.14 + 1.15 +#include "assembler/assembler/X86Assembler.h" 1.16 +#include "jit/shared/Assembler-shared.h" 1.17 + 1.18 +namespace js { 1.19 +namespace jit { 1.20 + 1.21 +class Operand 1.22 +{ 1.23 + public: 1.24 + enum Kind { 1.25 + REG, 1.26 + MEM_REG_DISP, 1.27 + FPREG, 1.28 + MEM_SCALE, 1.29 + MEM_ADDRESS32 1.30 + }; 1.31 + 1.32 + private: 1.33 + Kind kind_ : 4; 1.34 + int32_t base_ : 5; 1.35 + Scale scale_ : 3; 1.36 + int32_t index_ : 5; 1.37 + int32_t disp_; 1.38 + 1.39 + public: 1.40 + explicit Operand(Register reg) 1.41 + : kind_(REG), 1.42 + base_(reg.code()) 1.43 + { } 1.44 + explicit Operand(FloatRegister reg) 1.45 + : kind_(FPREG), 1.46 + base_(reg.code()) 1.47 + { } 1.48 + explicit Operand(const Address &address) 1.49 + : kind_(MEM_REG_DISP), 1.50 + base_(address.base.code()), 1.51 + disp_(address.offset) 1.52 + { } 1.53 + explicit Operand(const BaseIndex &address) 1.54 + : kind_(MEM_SCALE), 1.55 + base_(address.base.code()), 1.56 + scale_(address.scale), 1.57 + index_(address.index.code()), 1.58 + disp_(address.offset) 1.59 + { } 1.60 + Operand(Register base, Register index, Scale scale, int32_t disp = 0) 1.61 + : kind_(MEM_SCALE), 1.62 + base_(base.code()), 1.63 + scale_(scale), 1.64 + index_(index.code()), 1.65 + disp_(disp) 1.66 + { } 1.67 + Operand(Register reg, int32_t disp) 1.68 + : kind_(MEM_REG_DISP), 1.69 + base_(reg.code()), 1.70 + disp_(disp) 1.71 + { } 1.72 + explicit Operand(const AbsoluteAddress &address) 1.73 + : kind_(MEM_ADDRESS32), 1.74 + disp_(JSC::X86Assembler::addressImmediate(address.addr)) 1.75 + { } 1.76 + 1.77 + Address toAddress() const { 1.78 + JS_ASSERT(kind() == MEM_REG_DISP); 1.79 + return Address(Register::FromCode(base()), disp()); 1.80 + } 1.81 + 1.82 + BaseIndex toBaseIndex() const { 1.83 + JS_ASSERT(kind() == MEM_SCALE); 1.84 + return BaseIndex(Register::FromCode(base()), Register::FromCode(index()), scale(), disp()); 1.85 + } 1.86 + 1.87 + Kind kind() const { 1.88 + return kind_; 1.89 + } 1.90 + Registers::Code reg() const { 1.91 + JS_ASSERT(kind() == REG); 1.92 + return (Registers::Code)base_; 1.93 + } 1.94 + Registers::Code base() const { 1.95 + JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE); 1.96 + return (Registers::Code)base_; 1.97 + } 1.98 + Registers::Code index() const { 1.99 + JS_ASSERT(kind() == MEM_SCALE); 1.100 + return (Registers::Code)index_; 1.101 + } 1.102 + Scale scale() const { 1.103 + JS_ASSERT(kind() == MEM_SCALE); 1.104 + return scale_; 1.105 + } 1.106 + FloatRegisters::Code fpu() const { 1.107 + JS_ASSERT(kind() == FPREG); 1.108 + return (FloatRegisters::Code)base_; 1.109 + } 1.110 + int32_t disp() const { 1.111 + JS_ASSERT(kind() == MEM_REG_DISP || kind() == MEM_SCALE); 1.112 + return disp_; 1.113 + } 1.114 + void *address() const { 1.115 + JS_ASSERT(kind() == MEM_ADDRESS32); 1.116 + return reinterpret_cast<void *>(disp_); 1.117 + } 1.118 +}; 1.119 + 1.120 +class AssemblerX86Shared : public AssemblerShared 1.121 +{ 1.122 + protected: 1.123 + struct RelativePatch { 1.124 + int32_t offset; 1.125 + void *target; 1.126 + Relocation::Kind kind; 1.127 + 1.128 + RelativePatch(int32_t offset, void *target, Relocation::Kind kind) 1.129 + : offset(offset), 1.130 + target(target), 1.131 + kind(kind) 1.132 + { } 1.133 + }; 1.134 + 1.135 + Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_; 1.136 + Vector<RelativePatch, 8, SystemAllocPolicy> jumps_; 1.137 + CompactBufferWriter jumpRelocations_; 1.138 + CompactBufferWriter dataRelocations_; 1.139 + CompactBufferWriter preBarriers_; 1.140 + bool enoughMemory_; 1.141 + 1.142 + void writeDataRelocation(const Value &val) { 1.143 + if (val.isMarkable()) { 1.144 + JS_ASSERT(static_cast<gc::Cell*>(val.toGCThing())->isTenured()); 1.145 + dataRelocations_.writeUnsigned(masm.currentOffset()); 1.146 + } 1.147 + } 1.148 + void writeDataRelocation(const ImmGCPtr &ptr) { 1.149 + if (ptr.value) 1.150 + dataRelocations_.writeUnsigned(masm.currentOffset()); 1.151 + } 1.152 + void writePrebarrierOffset(CodeOffsetLabel label) { 1.153 + preBarriers_.writeUnsigned(label.offset()); 1.154 + } 1.155 + 1.156 + protected: 1.157 + JSC::X86Assembler masm; 1.158 + 1.159 + typedef JSC::X86Assembler::JmpSrc JmpSrc; 1.160 + typedef JSC::X86Assembler::JmpDst JmpDst; 1.161 + 1.162 + public: 1.163 + enum Condition { 1.164 + Equal = JSC::X86Assembler::ConditionE, 1.165 + NotEqual = JSC::X86Assembler::ConditionNE, 1.166 + Above = JSC::X86Assembler::ConditionA, 1.167 + AboveOrEqual = JSC::X86Assembler::ConditionAE, 1.168 + Below = JSC::X86Assembler::ConditionB, 1.169 + BelowOrEqual = JSC::X86Assembler::ConditionBE, 1.170 + GreaterThan = JSC::X86Assembler::ConditionG, 1.171 + GreaterThanOrEqual = JSC::X86Assembler::ConditionGE, 1.172 + LessThan = JSC::X86Assembler::ConditionL, 1.173 + LessThanOrEqual = JSC::X86Assembler::ConditionLE, 1.174 + Overflow = JSC::X86Assembler::ConditionO, 1.175 + Signed = JSC::X86Assembler::ConditionS, 1.176 + NotSigned = JSC::X86Assembler::ConditionNS, 1.177 + Zero = JSC::X86Assembler::ConditionE, 1.178 + NonZero = JSC::X86Assembler::ConditionNE, 1.179 + Parity = JSC::X86Assembler::ConditionP, 1.180 + NoParity = JSC::X86Assembler::ConditionNP 1.181 + }; 1.182 + 1.183 + // If this bit is set, the ucomisd operands have to be inverted. 1.184 + static const int DoubleConditionBitInvert = 0x10; 1.185 + 1.186 + // Bit set when a DoubleCondition does not map to a single x86 condition. 1.187 + // The macro assembler has to special-case these conditions. 1.188 + static const int DoubleConditionBitSpecial = 0x20; 1.189 + static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial; 1.190 + 1.191 + enum DoubleCondition { 1.192 + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. 1.193 + DoubleOrdered = NoParity, 1.194 + DoubleEqual = Equal | DoubleConditionBitSpecial, 1.195 + DoubleNotEqual = NotEqual, 1.196 + DoubleGreaterThan = Above, 1.197 + DoubleGreaterThanOrEqual = AboveOrEqual, 1.198 + DoubleLessThan = Above | DoubleConditionBitInvert, 1.199 + DoubleLessThanOrEqual = AboveOrEqual | DoubleConditionBitInvert, 1.200 + // If either operand is NaN, these conditions always evaluate to true. 1.201 + DoubleUnordered = Parity, 1.202 + DoubleEqualOrUnordered = Equal, 1.203 + DoubleNotEqualOrUnordered = NotEqual | DoubleConditionBitSpecial, 1.204 + DoubleGreaterThanOrUnordered = Below | DoubleConditionBitInvert, 1.205 + DoubleGreaterThanOrEqualOrUnordered = BelowOrEqual | DoubleConditionBitInvert, 1.206 + DoubleLessThanOrUnordered = Below, 1.207 + DoubleLessThanOrEqualOrUnordered = BelowOrEqual 1.208 + }; 1.209 + 1.210 + enum NaNCond { 1.211 + NaN_HandledByCond, 1.212 + NaN_IsTrue, 1.213 + NaN_IsFalse 1.214 + }; 1.215 + 1.216 + // If the primary condition returned by ConditionFromDoubleCondition doesn't 1.217 + // handle NaNs properly, return NaN_IsFalse if the comparison should be 1.218 + // overridden to return false on NaN, NaN_IsTrue if it should be overridden 1.219 + // to return true on NaN, or NaN_HandledByCond if no secondary check is 1.220 + // needed. 1.221 + static inline NaNCond NaNCondFromDoubleCondition(DoubleCondition cond) { 1.222 + switch (cond) { 1.223 + case DoubleOrdered: 1.224 + case DoubleNotEqual: 1.225 + case DoubleGreaterThan: 1.226 + case DoubleGreaterThanOrEqual: 1.227 + case DoubleLessThan: 1.228 + case DoubleLessThanOrEqual: 1.229 + case DoubleUnordered: 1.230 + case DoubleEqualOrUnordered: 1.231 + case DoubleGreaterThanOrUnordered: 1.232 + case DoubleGreaterThanOrEqualOrUnordered: 1.233 + case DoubleLessThanOrUnordered: 1.234 + case DoubleLessThanOrEqualOrUnordered: 1.235 + return NaN_HandledByCond; 1.236 + case DoubleEqual: 1.237 + return NaN_IsFalse; 1.238 + case DoubleNotEqualOrUnordered: 1.239 + return NaN_IsTrue; 1.240 + } 1.241 + 1.242 + MOZ_ASSUME_UNREACHABLE("Unknown double condition"); 1.243 + } 1.244 + 1.245 + static void staticAsserts() { 1.246 + // DoubleConditionBits should not interfere with x86 condition codes. 1.247 + JS_STATIC_ASSERT(!((Equal | NotEqual | Above | AboveOrEqual | Below | 1.248 + BelowOrEqual | Parity | NoParity) & DoubleConditionBits)); 1.249 + } 1.250 + 1.251 + AssemblerX86Shared() 1.252 + : enoughMemory_(true) 1.253 + { 1.254 + } 1.255 + 1.256 + static Condition InvertCondition(Condition cond); 1.257 + 1.258 + // Return the primary condition to test. Some primary conditions may not 1.259 + // handle NaNs properly and may therefore require a secondary condition. 1.260 + // Use NaNCondFromDoubleCondition to determine what else is needed. 1.261 + static inline Condition ConditionFromDoubleCondition(DoubleCondition cond) { 1.262 + return static_cast<Condition>(cond & ~DoubleConditionBits); 1.263 + } 1.264 + 1.265 + static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); 1.266 + 1.267 + // MacroAssemblers hold onto gcthings, so they are traced by the GC. 1.268 + void trace(JSTracer *trc); 1.269 + 1.270 + bool oom() const { 1.271 + return masm.oom() || 1.272 + !enoughMemory_ || 1.273 + jumpRelocations_.oom() || 1.274 + dataRelocations_.oom() || 1.275 + preBarriers_.oom(); 1.276 + } 1.277 + 1.278 + void setPrinter(Sprinter *sp) { 1.279 + masm.setPrinter(sp); 1.280 + } 1.281 + 1.282 + void executableCopy(void *buffer); 1.283 + void processCodeLabels(uint8_t *rawCode); 1.284 + void copyJumpRelocationTable(uint8_t *dest); 1.285 + void copyDataRelocationTable(uint8_t *dest); 1.286 + void copyPreBarrierTable(uint8_t *dest); 1.287 + 1.288 + bool addCodeLabel(CodeLabel label) { 1.289 + return codeLabels_.append(label); 1.290 + } 1.291 + size_t numCodeLabels() const { 1.292 + return codeLabels_.length(); 1.293 + } 1.294 + CodeLabel codeLabel(size_t i) { 1.295 + return codeLabels_[i]; 1.296 + } 1.297 + 1.298 + // Size of the instruction stream, in bytes. 1.299 + size_t size() const { 1.300 + return masm.size(); 1.301 + } 1.302 + // Size of the jump relocation table, in bytes. 1.303 + size_t jumpRelocationTableBytes() const { 1.304 + return jumpRelocations_.length(); 1.305 + } 1.306 + size_t dataRelocationTableBytes() const { 1.307 + return dataRelocations_.length(); 1.308 + } 1.309 + size_t preBarrierTableBytes() const { 1.310 + return preBarriers_.length(); 1.311 + } 1.312 + // Size of the data table, in bytes. 1.313 + size_t bytesNeeded() const { 1.314 + return size() + 1.315 + jumpRelocationTableBytes() + 1.316 + dataRelocationTableBytes() + 1.317 + preBarrierTableBytes(); 1.318 + } 1.319 + 1.320 + public: 1.321 + void align(int alignment) { 1.322 + masm.align(alignment); 1.323 + } 1.324 + void writeCodePointer(AbsoluteLabel *label) { 1.325 + JS_ASSERT(!label->bound()); 1.326 + // Thread the patch list through the unpatched address word in the 1.327 + // instruction stream. 1.328 + masm.jumpTablePointer(label->prev()); 1.329 + label->setPrev(masm.size()); 1.330 + } 1.331 + void writeDoubleConstant(double d, Label *label) { 1.332 + label->bind(masm.size()); 1.333 + masm.doubleConstant(d); 1.334 + } 1.335 + void writeFloatConstant(float f, Label *label) { 1.336 + label->bind(masm.size()); 1.337 + masm.floatConstant(f); 1.338 + } 1.339 + void movl(const Imm32 &imm32, const Register &dest) { 1.340 + masm.movl_i32r(imm32.value, dest.code()); 1.341 + } 1.342 + void movl(const Register &src, const Register &dest) { 1.343 + masm.movl_rr(src.code(), dest.code()); 1.344 + } 1.345 + void movl(const Operand &src, const Register &dest) { 1.346 + switch (src.kind()) { 1.347 + case Operand::REG: 1.348 + masm.movl_rr(src.reg(), dest.code()); 1.349 + break; 1.350 + case Operand::MEM_REG_DISP: 1.351 + masm.movl_mr(src.disp(), src.base(), dest.code()); 1.352 + break; 1.353 + case Operand::MEM_SCALE: 1.354 + masm.movl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.355 + break; 1.356 + case Operand::MEM_ADDRESS32: 1.357 + masm.movl_mr(src.address(), dest.code()); 1.358 + break; 1.359 + default: 1.360 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.361 + } 1.362 + } 1.363 + void movl(const Register &src, const Operand &dest) { 1.364 + switch (dest.kind()) { 1.365 + case Operand::REG: 1.366 + masm.movl_rr(src.code(), dest.reg()); 1.367 + break; 1.368 + case Operand::MEM_REG_DISP: 1.369 + masm.movl_rm(src.code(), dest.disp(), dest.base()); 1.370 + break; 1.371 + case Operand::MEM_SCALE: 1.372 + masm.movl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); 1.373 + break; 1.374 + case Operand::MEM_ADDRESS32: 1.375 + masm.movl_rm(src.code(), dest.address()); 1.376 + break; 1.377 + default: 1.378 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.379 + } 1.380 + } 1.381 + void movl(const Imm32 &imm32, const Operand &dest) { 1.382 + switch (dest.kind()) { 1.383 + case Operand::REG: 1.384 + masm.movl_i32r(imm32.value, dest.reg()); 1.385 + break; 1.386 + case Operand::MEM_REG_DISP: 1.387 + masm.movl_i32m(imm32.value, dest.disp(), dest.base()); 1.388 + break; 1.389 + case Operand::MEM_SCALE: 1.390 + masm.movl_i32m(imm32.value, dest.disp(), dest.base(), dest.index(), dest.scale()); 1.391 + break; 1.392 + default: 1.393 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.394 + } 1.395 + } 1.396 + 1.397 + void xchgl(const Register &src, const Register &dest) { 1.398 + masm.xchgl_rr(src.code(), dest.code()); 1.399 + } 1.400 + 1.401 + // Eventually movapd and movaps should be overloaded to support loads and 1.402 + // stores too. 1.403 + void movapd(const FloatRegister &src, const FloatRegister &dest) { 1.404 + JS_ASSERT(HasSSE2()); 1.405 + masm.movapd_rr(src.code(), dest.code()); 1.406 + } 1.407 + void movaps(const FloatRegister &src, const FloatRegister &dest) { 1.408 + JS_ASSERT(HasSSE2()); 1.409 + masm.movaps_rr(src.code(), dest.code()); 1.410 + } 1.411 + 1.412 + // movsd and movss are only provided in load/store form since the 1.413 + // register-to-register form has different semantics (it doesn't clobber 1.414 + // the whole output register) and isn't needed currently. 1.415 + void movsd(const Address &src, const FloatRegister &dest) { 1.416 + masm.movsd_mr(src.offset, src.base.code(), dest.code()); 1.417 + } 1.418 + void movsd(const BaseIndex &src, const FloatRegister &dest) { 1.419 + masm.movsd_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code()); 1.420 + } 1.421 + void movsd(const FloatRegister &src, const Address &dest) { 1.422 + masm.movsd_rm(src.code(), dest.offset, dest.base.code()); 1.423 + } 1.424 + void movsd(const FloatRegister &src, const BaseIndex &dest) { 1.425 + masm.movsd_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale); 1.426 + } 1.427 + void movss(const Address &src, const FloatRegister &dest) { 1.428 + masm.movss_mr(src.offset, src.base.code(), dest.code()); 1.429 + } 1.430 + void movss(const BaseIndex &src, const FloatRegister &dest) { 1.431 + masm.movss_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code()); 1.432 + } 1.433 + void movss(const FloatRegister &src, const Address &dest) { 1.434 + masm.movss_rm(src.code(), dest.offset, dest.base.code()); 1.435 + } 1.436 + void movss(const FloatRegister &src, const BaseIndex &dest) { 1.437 + masm.movss_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale); 1.438 + } 1.439 + void movdqa(const Operand &src, const FloatRegister &dest) { 1.440 + JS_ASSERT(HasSSE2()); 1.441 + switch (src.kind()) { 1.442 + case Operand::MEM_REG_DISP: 1.443 + masm.movdqa_mr(src.disp(), src.base(), dest.code()); 1.444 + break; 1.445 + case Operand::MEM_SCALE: 1.446 + masm.movdqa_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.447 + break; 1.448 + default: 1.449 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.450 + } 1.451 + } 1.452 + void movdqa(const FloatRegister &src, const Operand &dest) { 1.453 + JS_ASSERT(HasSSE2()); 1.454 + switch (dest.kind()) { 1.455 + case Operand::MEM_REG_DISP: 1.456 + masm.movdqa_rm(src.code(), dest.disp(), dest.base()); 1.457 + break; 1.458 + case Operand::MEM_SCALE: 1.459 + masm.movdqa_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); 1.460 + break; 1.461 + default: 1.462 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.463 + } 1.464 + } 1.465 + void cvtss2sd(const FloatRegister &src, const FloatRegister &dest) { 1.466 + JS_ASSERT(HasSSE2()); 1.467 + masm.cvtss2sd_rr(src.code(), dest.code()); 1.468 + } 1.469 + void cvtsd2ss(const FloatRegister &src, const FloatRegister &dest) { 1.470 + JS_ASSERT(HasSSE2()); 1.471 + masm.cvtsd2ss_rr(src.code(), dest.code()); 1.472 + } 1.473 + void movzbl(const Operand &src, const Register &dest) { 1.474 + switch (src.kind()) { 1.475 + case Operand::MEM_REG_DISP: 1.476 + masm.movzbl_mr(src.disp(), src.base(), dest.code()); 1.477 + break; 1.478 + case Operand::MEM_SCALE: 1.479 + masm.movzbl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.480 + break; 1.481 + default: 1.482 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.483 + } 1.484 + } 1.485 + void movsbl(const Operand &src, const Register &dest) { 1.486 + switch (src.kind()) { 1.487 + case Operand::MEM_REG_DISP: 1.488 + masm.movsbl_mr(src.disp(), src.base(), dest.code()); 1.489 + break; 1.490 + case Operand::MEM_SCALE: 1.491 + masm.movsbl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.492 + break; 1.493 + default: 1.494 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.495 + } 1.496 + } 1.497 + void movb(const Register &src, const Operand &dest) { 1.498 + switch (dest.kind()) { 1.499 + case Operand::MEM_REG_DISP: 1.500 + masm.movb_rm(src.code(), dest.disp(), dest.base()); 1.501 + break; 1.502 + case Operand::MEM_SCALE: 1.503 + masm.movb_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); 1.504 + break; 1.505 + default: 1.506 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.507 + } 1.508 + } 1.509 + void movb(const Imm32 &src, const Operand &dest) { 1.510 + switch (dest.kind()) { 1.511 + case Operand::MEM_REG_DISP: 1.512 + masm.movb_i8m(src.value, dest.disp(), dest.base()); 1.513 + break; 1.514 + case Operand::MEM_SCALE: 1.515 + masm.movb_i8m(src.value, dest.disp(), dest.base(), dest.index(), dest.scale()); 1.516 + break; 1.517 + default: 1.518 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.519 + } 1.520 + } 1.521 + void movzwl(const Operand &src, const Register &dest) { 1.522 + switch (src.kind()) { 1.523 + case Operand::REG: 1.524 + masm.movzwl_rr(src.reg(), dest.code()); 1.525 + break; 1.526 + case Operand::MEM_REG_DISP: 1.527 + masm.movzwl_mr(src.disp(), src.base(), dest.code()); 1.528 + break; 1.529 + case Operand::MEM_SCALE: 1.530 + masm.movzwl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.531 + break; 1.532 + default: 1.533 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.534 + } 1.535 + } 1.536 + void movzwl(const Register &src, const Register &dest) { 1.537 + masm.movzwl_rr(src.code(), dest.code()); 1.538 + } 1.539 + void movw(const Register &src, const Operand &dest) { 1.540 + switch (dest.kind()) { 1.541 + case Operand::MEM_REG_DISP: 1.542 + masm.movw_rm(src.code(), dest.disp(), dest.base()); 1.543 + break; 1.544 + case Operand::MEM_SCALE: 1.545 + masm.movw_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale()); 1.546 + break; 1.547 + default: 1.548 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.549 + } 1.550 + } 1.551 + void movw(const Imm32 &src, const Operand &dest) { 1.552 + switch (dest.kind()) { 1.553 + case Operand::MEM_REG_DISP: 1.554 + masm.movw_i16m(src.value, dest.disp(), dest.base()); 1.555 + break; 1.556 + case Operand::MEM_SCALE: 1.557 + masm.movw_i16m(src.value, dest.disp(), dest.base(), dest.index(), dest.scale()); 1.558 + break; 1.559 + default: 1.560 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.561 + } 1.562 + } 1.563 + void movswl(const Operand &src, const Register &dest) { 1.564 + switch (src.kind()) { 1.565 + case Operand::MEM_REG_DISP: 1.566 + masm.movswl_mr(src.disp(), src.base(), dest.code()); 1.567 + break; 1.568 + case Operand::MEM_SCALE: 1.569 + masm.movswl_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.570 + break; 1.571 + default: 1.572 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.573 + } 1.574 + } 1.575 + void leal(const Operand &src, const Register &dest) { 1.576 + switch (src.kind()) { 1.577 + case Operand::MEM_REG_DISP: 1.578 + masm.leal_mr(src.disp(), src.base(), dest.code()); 1.579 + break; 1.580 + case Operand::MEM_SCALE: 1.581 + masm.leal_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.582 + break; 1.583 + default: 1.584 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.585 + } 1.586 + } 1.587 + 1.588 + protected: 1.589 + JmpSrc jSrc(Condition cond, Label *label) { 1.590 + JmpSrc j = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond)); 1.591 + if (label->bound()) { 1.592 + // The jump can be immediately patched to the correct destination. 1.593 + masm.linkJump(j, JmpDst(label->offset())); 1.594 + } else { 1.595 + // Thread the jump list through the unpatched jump targets. 1.596 + JmpSrc prev = JmpSrc(label->use(j.offset())); 1.597 + masm.setNextJump(j, prev); 1.598 + } 1.599 + return j; 1.600 + } 1.601 + JmpSrc jmpSrc(Label *label) { 1.602 + JmpSrc j = masm.jmp(); 1.603 + if (label->bound()) { 1.604 + // The jump can be immediately patched to the correct destination. 1.605 + masm.linkJump(j, JmpDst(label->offset())); 1.606 + } else { 1.607 + // Thread the jump list through the unpatched jump targets. 1.608 + JmpSrc prev = JmpSrc(label->use(j.offset())); 1.609 + masm.setNextJump(j, prev); 1.610 + } 1.611 + return j; 1.612 + } 1.613 + 1.614 + // Comparison of EAX against the address given by a Label. 1.615 + JmpSrc cmpSrc(Label *label) { 1.616 + JmpSrc j = masm.cmp_eax(); 1.617 + if (label->bound()) { 1.618 + // The jump can be immediately patched to the correct destination. 1.619 + masm.linkJump(j, JmpDst(label->offset())); 1.620 + } else { 1.621 + // Thread the jump list through the unpatched jump targets. 1.622 + JmpSrc prev = JmpSrc(label->use(j.offset())); 1.623 + masm.setNextJump(j, prev); 1.624 + } 1.625 + return j; 1.626 + } 1.627 + 1.628 + JmpSrc jSrc(Condition cond, RepatchLabel *label) { 1.629 + JmpSrc j = masm.jCC(static_cast<JSC::X86Assembler::Condition>(cond)); 1.630 + if (label->bound()) { 1.631 + // The jump can be immediately patched to the correct destination. 1.632 + masm.linkJump(j, JmpDst(label->offset())); 1.633 + } else { 1.634 + label->use(j.offset()); 1.635 + } 1.636 + return j; 1.637 + } 1.638 + JmpSrc jmpSrc(RepatchLabel *label) { 1.639 + JmpSrc j = masm.jmp(); 1.640 + if (label->bound()) { 1.641 + // The jump can be immediately patched to the correct destination. 1.642 + masm.linkJump(j, JmpDst(label->offset())); 1.643 + } else { 1.644 + // Thread the jump list through the unpatched jump targets. 1.645 + label->use(j.offset()); 1.646 + } 1.647 + return j; 1.648 + } 1.649 + 1.650 + public: 1.651 + void nop() { masm.nop(); } 1.652 + void j(Condition cond, Label *label) { jSrc(cond, label); } 1.653 + void jmp(Label *label) { jmpSrc(label); } 1.654 + void j(Condition cond, RepatchLabel *label) { jSrc(cond, label); } 1.655 + void jmp(RepatchLabel *label) { jmpSrc(label); } 1.656 + 1.657 + void jmp(const Operand &op) { 1.658 + switch (op.kind()) { 1.659 + case Operand::MEM_REG_DISP: 1.660 + masm.jmp_m(op.disp(), op.base()); 1.661 + break; 1.662 + case Operand::MEM_SCALE: 1.663 + masm.jmp_m(op.disp(), op.base(), op.index(), op.scale()); 1.664 + break; 1.665 + case Operand::REG: 1.666 + masm.jmp_r(op.reg()); 1.667 + break; 1.668 + default: 1.669 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.670 + } 1.671 + } 1.672 + void cmpEAX(Label *label) { cmpSrc(label); } 1.673 + void bind(Label *label) { 1.674 + JSC::MacroAssembler::Label jsclabel; 1.675 + JSC::X86Assembler::JmpDst dst(masm.label()); 1.676 + if (label->used()) { 1.677 + bool more; 1.678 + JSC::X86Assembler::JmpSrc jmp(label->offset()); 1.679 + do { 1.680 + JSC::X86Assembler::JmpSrc next; 1.681 + more = masm.nextJump(jmp, &next); 1.682 + masm.linkJump(jmp, dst); 1.683 + jmp = next; 1.684 + } while (more); 1.685 + } 1.686 + label->bind(dst.offset()); 1.687 + } 1.688 + void bind(RepatchLabel *label) { 1.689 + JSC::MacroAssembler::Label jsclabel; 1.690 + JSC::X86Assembler::JmpDst dst(masm.label()); 1.691 + if (label->used()) { 1.692 + JSC::X86Assembler::JmpSrc jmp(label->offset()); 1.693 + masm.linkJump(jmp, dst); 1.694 + } 1.695 + label->bind(dst.offset()); 1.696 + } 1.697 + uint32_t currentOffset() { 1.698 + return masm.label().offset(); 1.699 + } 1.700 + 1.701 + // Re-routes pending jumps to a new label. 1.702 + void retarget(Label *label, Label *target) { 1.703 + JSC::MacroAssembler::Label jsclabel; 1.704 + if (label->used()) { 1.705 + bool more; 1.706 + JSC::X86Assembler::JmpSrc jmp(label->offset()); 1.707 + do { 1.708 + JSC::X86Assembler::JmpSrc next; 1.709 + more = masm.nextJump(jmp, &next); 1.710 + 1.711 + if (target->bound()) { 1.712 + // The jump can be immediately patched to the correct destination. 1.713 + masm.linkJump(jmp, JmpDst(target->offset())); 1.714 + } else { 1.715 + // Thread the jump list through the unpatched jump targets. 1.716 + JmpSrc prev = JmpSrc(target->use(jmp.offset())); 1.717 + masm.setNextJump(jmp, prev); 1.718 + } 1.719 + 1.720 + jmp = next; 1.721 + } while (more); 1.722 + } 1.723 + label->reset(); 1.724 + } 1.725 + 1.726 + static void Bind(uint8_t *raw, AbsoluteLabel *label, const void *address) { 1.727 + if (label->used()) { 1.728 + intptr_t src = label->offset(); 1.729 + do { 1.730 + intptr_t next = reinterpret_cast<intptr_t>(JSC::X86Assembler::getPointer(raw + src)); 1.731 + JSC::X86Assembler::setPointer(raw + src, address); 1.732 + src = next; 1.733 + } while (src != AbsoluteLabel::INVALID_OFFSET); 1.734 + } 1.735 + label->bind(); 1.736 + } 1.737 + 1.738 + // See Bind and JSC::X86Assembler::setPointer. 1.739 + size_t labelOffsetToPatchOffset(size_t offset) { 1.740 + return offset - sizeof(void*); 1.741 + } 1.742 + 1.743 + void ret() { 1.744 + masm.ret(); 1.745 + } 1.746 + void retn(Imm32 n) { 1.747 + // Remove the size of the return address which is included in the frame. 1.748 + masm.ret(n.value - sizeof(void *)); 1.749 + } 1.750 + void call(Label *label) { 1.751 + if (label->bound()) { 1.752 + masm.linkJump(masm.call(), JmpDst(label->offset())); 1.753 + } else { 1.754 + JmpSrc j = masm.call(); 1.755 + JmpSrc prev = JmpSrc(label->use(j.offset())); 1.756 + masm.setNextJump(j, prev); 1.757 + } 1.758 + } 1.759 + void call(const Register ®) { 1.760 + masm.call(reg.code()); 1.761 + } 1.762 + void call(const Operand &op) { 1.763 + switch (op.kind()) { 1.764 + case Operand::REG: 1.765 + masm.call(op.reg()); 1.766 + break; 1.767 + case Operand::MEM_REG_DISP: 1.768 + masm.call_m(op.disp(), op.base()); 1.769 + break; 1.770 + default: 1.771 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.772 + } 1.773 + } 1.774 + 1.775 + void breakpoint() { 1.776 + masm.int3(); 1.777 + } 1.778 + 1.779 +#ifdef DEBUG 1.780 + static bool HasSSE2() { 1.781 + return JSC::MacroAssembler::isSSE2Present(); 1.782 + } 1.783 +#endif 1.784 + static bool HasSSE3() { 1.785 + return JSC::MacroAssembler::isSSE3Present(); 1.786 + } 1.787 + static bool HasSSE41() { 1.788 + return JSC::MacroAssembler::isSSE41Present(); 1.789 + } 1.790 + 1.791 + // The below cmpl methods switch the lhs and rhs when it invokes the 1.792 + // macroassembler to conform with intel standard. When calling this 1.793 + // function put the left operand on the left as you would expect. 1.794 + void cmpl(const Register &lhs, const Register &rhs) { 1.795 + masm.cmpl_rr(rhs.code(), lhs.code()); 1.796 + } 1.797 + void cmpl(const Register &lhs, const Operand &rhs) { 1.798 + switch (rhs.kind()) { 1.799 + case Operand::REG: 1.800 + masm.cmpl_rr(rhs.reg(), lhs.code()); 1.801 + break; 1.802 + case Operand::MEM_REG_DISP: 1.803 + masm.cmpl_mr(rhs.disp(), rhs.base(), lhs.code()); 1.804 + break; 1.805 + default: 1.806 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.807 + } 1.808 + } 1.809 + void cmpl(const Register &src, Imm32 imm) { 1.810 + masm.cmpl_ir(imm.value, src.code()); 1.811 + } 1.812 + void cmpl(const Operand &op, Imm32 imm) { 1.813 + switch (op.kind()) { 1.814 + case Operand::REG: 1.815 + masm.cmpl_ir(imm.value, op.reg()); 1.816 + break; 1.817 + case Operand::MEM_REG_DISP: 1.818 + masm.cmpl_im(imm.value, op.disp(), op.base()); 1.819 + break; 1.820 + case Operand::MEM_SCALE: 1.821 + masm.cmpl_im(imm.value, op.disp(), op.base(), op.index(), op.scale()); 1.822 + break; 1.823 + case Operand::MEM_ADDRESS32: 1.824 + masm.cmpl_im(imm.value, op.address()); 1.825 + break; 1.826 + default: 1.827 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.828 + } 1.829 + } 1.830 + void cmpl(const Operand &lhs, const Register &rhs) { 1.831 + switch (lhs.kind()) { 1.832 + case Operand::REG: 1.833 + masm.cmpl_rr(rhs.code(), lhs.reg()); 1.834 + break; 1.835 + case Operand::MEM_REG_DISP: 1.836 + masm.cmpl_rm(rhs.code(), lhs.disp(), lhs.base()); 1.837 + break; 1.838 + case Operand::MEM_ADDRESS32: 1.839 + masm.cmpl_rm(rhs.code(), lhs.address()); 1.840 + break; 1.841 + default: 1.842 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.843 + } 1.844 + } 1.845 + void cmpl(const Operand &op, ImmWord imm) { 1.846 + switch (op.kind()) { 1.847 + case Operand::REG: 1.848 + masm.cmpl_ir(imm.value, op.reg()); 1.849 + break; 1.850 + case Operand::MEM_REG_DISP: 1.851 + masm.cmpl_im(imm.value, op.disp(), op.base()); 1.852 + break; 1.853 + case Operand::MEM_ADDRESS32: 1.854 + masm.cmpl_im(imm.value, op.address()); 1.855 + break; 1.856 + default: 1.857 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.858 + } 1.859 + } 1.860 + void cmpl(const Operand &op, ImmPtr imm) { 1.861 + cmpl(op, ImmWord(uintptr_t(imm.value))); 1.862 + } 1.863 + void cmpw(const Register &lhs, const Register &rhs) { 1.864 + masm.cmpw_rr(lhs.code(), rhs.code()); 1.865 + } 1.866 + void setCC(Condition cond, const Register &r) { 1.867 + masm.setCC_r(static_cast<JSC::X86Assembler::Condition>(cond), r.code()); 1.868 + } 1.869 + void testb(const Register &lhs, const Register &rhs) { 1.870 + JS_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(lhs)); 1.871 + JS_ASSERT(GeneralRegisterSet(Registers::SingleByteRegs).has(rhs)); 1.872 + masm.testb_rr(rhs.code(), lhs.code()); 1.873 + } 1.874 + void testw(const Register &lhs, const Register &rhs) { 1.875 + masm.testw_rr(rhs.code(), lhs.code()); 1.876 + } 1.877 + void testl(const Register &lhs, const Register &rhs) { 1.878 + masm.testl_rr(rhs.code(), lhs.code()); 1.879 + } 1.880 + void testl(const Register &lhs, Imm32 rhs) { 1.881 + masm.testl_i32r(rhs.value, lhs.code()); 1.882 + } 1.883 + void testl(const Operand &lhs, Imm32 rhs) { 1.884 + switch (lhs.kind()) { 1.885 + case Operand::REG: 1.886 + masm.testl_i32r(rhs.value, lhs.reg()); 1.887 + break; 1.888 + case Operand::MEM_REG_DISP: 1.889 + masm.testl_i32m(rhs.value, lhs.disp(), lhs.base()); 1.890 + break; 1.891 + default: 1.892 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.893 + break; 1.894 + } 1.895 + } 1.896 + 1.897 + void addl(Imm32 imm, const Register &dest) { 1.898 + masm.addl_ir(imm.value, dest.code()); 1.899 + } 1.900 + void addl(Imm32 imm, const Operand &op) { 1.901 + switch (op.kind()) { 1.902 + case Operand::REG: 1.903 + masm.addl_ir(imm.value, op.reg()); 1.904 + break; 1.905 + case Operand::MEM_REG_DISP: 1.906 + masm.addl_im(imm.value, op.disp(), op.base()); 1.907 + break; 1.908 + case Operand::MEM_ADDRESS32: 1.909 + masm.addl_im(imm.value, op.address()); 1.910 + break; 1.911 + default: 1.912 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.913 + } 1.914 + } 1.915 + void subl(Imm32 imm, const Register &dest) { 1.916 + masm.subl_ir(imm.value, dest.code()); 1.917 + } 1.918 + void subl(Imm32 imm, const Operand &op) { 1.919 + switch (op.kind()) { 1.920 + case Operand::REG: 1.921 + masm.subl_ir(imm.value, op.reg()); 1.922 + break; 1.923 + case Operand::MEM_REG_DISP: 1.924 + masm.subl_im(imm.value, op.disp(), op.base()); 1.925 + break; 1.926 + default: 1.927 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.928 + } 1.929 + } 1.930 + void addl(const Register &src, const Register &dest) { 1.931 + masm.addl_rr(src.code(), dest.code()); 1.932 + } 1.933 + void subl(const Register &src, const Register &dest) { 1.934 + masm.subl_rr(src.code(), dest.code()); 1.935 + } 1.936 + void subl(const Operand &src, const Register &dest) { 1.937 + switch (src.kind()) { 1.938 + case Operand::REG: 1.939 + masm.subl_rr(src.reg(), dest.code()); 1.940 + break; 1.941 + case Operand::MEM_REG_DISP: 1.942 + masm.subl_mr(src.disp(), src.base(), dest.code()); 1.943 + break; 1.944 + default: 1.945 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.946 + } 1.947 + } 1.948 + void subl(const Register &src, const Operand &dest) { 1.949 + switch (dest.kind()) { 1.950 + case Operand::REG: 1.951 + masm.subl_rr(src.code(), dest.reg()); 1.952 + break; 1.953 + case Operand::MEM_REG_DISP: 1.954 + masm.subl_rm(src.code(), dest.disp(), dest.base()); 1.955 + break; 1.956 + default: 1.957 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.958 + } 1.959 + } 1.960 + void orl(const Register ®, const Register &dest) { 1.961 + masm.orl_rr(reg.code(), dest.code()); 1.962 + } 1.963 + void orl(Imm32 imm, const Register ®) { 1.964 + masm.orl_ir(imm.value, reg.code()); 1.965 + } 1.966 + void orl(Imm32 imm, const Operand &op) { 1.967 + switch (op.kind()) { 1.968 + case Operand::REG: 1.969 + masm.orl_ir(imm.value, op.reg()); 1.970 + break; 1.971 + case Operand::MEM_REG_DISP: 1.972 + masm.orl_im(imm.value, op.disp(), op.base()); 1.973 + break; 1.974 + default: 1.975 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.976 + } 1.977 + } 1.978 + void xorl(const Register &src, const Register &dest) { 1.979 + masm.xorl_rr(src.code(), dest.code()); 1.980 + } 1.981 + void xorl(Imm32 imm, const Register ®) { 1.982 + masm.xorl_ir(imm.value, reg.code()); 1.983 + } 1.984 + void xorl(Imm32 imm, const Operand &op) { 1.985 + switch (op.kind()) { 1.986 + case Operand::REG: 1.987 + masm.xorl_ir(imm.value, op.reg()); 1.988 + break; 1.989 + case Operand::MEM_REG_DISP: 1.990 + masm.xorl_im(imm.value, op.disp(), op.base()); 1.991 + break; 1.992 + default: 1.993 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.994 + } 1.995 + } 1.996 + void andl(const Register &src, const Register &dest) { 1.997 + masm.andl_rr(src.code(), dest.code()); 1.998 + } 1.999 + void andl(Imm32 imm, const Register &dest) { 1.1000 + masm.andl_ir(imm.value, dest.code()); 1.1001 + } 1.1002 + void andl(Imm32 imm, const Operand &op) { 1.1003 + switch (op.kind()) { 1.1004 + case Operand::REG: 1.1005 + masm.andl_ir(imm.value, op.reg()); 1.1006 + break; 1.1007 + case Operand::MEM_REG_DISP: 1.1008 + masm.andl_im(imm.value, op.disp(), op.base()); 1.1009 + break; 1.1010 + default: 1.1011 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1012 + } 1.1013 + } 1.1014 + void addl(const Operand &src, const Register &dest) { 1.1015 + switch (src.kind()) { 1.1016 + case Operand::REG: 1.1017 + masm.addl_rr(src.reg(), dest.code()); 1.1018 + break; 1.1019 + case Operand::MEM_REG_DISP: 1.1020 + masm.addl_mr(src.disp(), src.base(), dest.code()); 1.1021 + break; 1.1022 + default: 1.1023 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1024 + } 1.1025 + } 1.1026 + void orl(const Operand &src, const Register &dest) { 1.1027 + switch (src.kind()) { 1.1028 + case Operand::REG: 1.1029 + masm.orl_rr(src.reg(), dest.code()); 1.1030 + break; 1.1031 + case Operand::MEM_REG_DISP: 1.1032 + masm.orl_mr(src.disp(), src.base(), dest.code()); 1.1033 + break; 1.1034 + default: 1.1035 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1036 + } 1.1037 + } 1.1038 + void xorl(const Operand &src, const Register &dest) { 1.1039 + switch (src.kind()) { 1.1040 + case Operand::REG: 1.1041 + masm.xorl_rr(src.reg(), dest.code()); 1.1042 + break; 1.1043 + case Operand::MEM_REG_DISP: 1.1044 + masm.xorl_mr(src.disp(), src.base(), dest.code()); 1.1045 + break; 1.1046 + default: 1.1047 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1048 + } 1.1049 + } 1.1050 + void andl(const Operand &src, const Register &dest) { 1.1051 + switch (src.kind()) { 1.1052 + case Operand::REG: 1.1053 + masm.andl_rr(src.reg(), dest.code()); 1.1054 + break; 1.1055 + case Operand::MEM_REG_DISP: 1.1056 + masm.andl_mr(src.disp(), src.base(), dest.code()); 1.1057 + break; 1.1058 + default: 1.1059 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1060 + } 1.1061 + } 1.1062 + void imull(const Register &multiplier) { 1.1063 + masm.imull_r(multiplier.code()); 1.1064 + } 1.1065 + void imull(Imm32 imm, const Register &dest) { 1.1066 + masm.imull_i32r(dest.code(), imm.value, dest.code()); 1.1067 + } 1.1068 + void imull(const Register &src, const Register &dest) { 1.1069 + masm.imull_rr(src.code(), dest.code()); 1.1070 + } 1.1071 + void imull(Imm32 imm, const Register &src, const Register &dest) { 1.1072 + masm.imull_i32r(src.code(), imm.value, dest.code()); 1.1073 + } 1.1074 + void imull(const Operand &src, const Register &dest) { 1.1075 + switch (src.kind()) { 1.1076 + case Operand::REG: 1.1077 + masm.imull_rr(src.reg(), dest.code()); 1.1078 + break; 1.1079 + case Operand::MEM_REG_DISP: 1.1080 + masm.imull_mr(src.disp(), src.base(), dest.code()); 1.1081 + break; 1.1082 + default: 1.1083 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1084 + } 1.1085 + } 1.1086 + void negl(const Operand &src) { 1.1087 + switch (src.kind()) { 1.1088 + case Operand::REG: 1.1089 + masm.negl_r(src.reg()); 1.1090 + break; 1.1091 + case Operand::MEM_REG_DISP: 1.1092 + masm.negl_m(src.disp(), src.base()); 1.1093 + break; 1.1094 + default: 1.1095 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1096 + } 1.1097 + } 1.1098 + void negl(const Register ®) { 1.1099 + masm.negl_r(reg.code()); 1.1100 + } 1.1101 + void notl(const Operand &src) { 1.1102 + switch (src.kind()) { 1.1103 + case Operand::REG: 1.1104 + masm.notl_r(src.reg()); 1.1105 + break; 1.1106 + case Operand::MEM_REG_DISP: 1.1107 + masm.notl_m(src.disp(), src.base()); 1.1108 + break; 1.1109 + default: 1.1110 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1111 + } 1.1112 + } 1.1113 + void notl(const Register ®) { 1.1114 + masm.notl_r(reg.code()); 1.1115 + } 1.1116 + void shrl(const Imm32 imm, const Register &dest) { 1.1117 + masm.shrl_i8r(imm.value, dest.code()); 1.1118 + } 1.1119 + void shll(const Imm32 imm, const Register &dest) { 1.1120 + masm.shll_i8r(imm.value, dest.code()); 1.1121 + } 1.1122 + void sarl(const Imm32 imm, const Register &dest) { 1.1123 + masm.sarl_i8r(imm.value, dest.code()); 1.1124 + } 1.1125 + void shrl_cl(const Register &dest) { 1.1126 + masm.shrl_CLr(dest.code()); 1.1127 + } 1.1128 + void shll_cl(const Register &dest) { 1.1129 + masm.shll_CLr(dest.code()); 1.1130 + } 1.1131 + void sarl_cl(const Register &dest) { 1.1132 + masm.sarl_CLr(dest.code()); 1.1133 + } 1.1134 + 1.1135 + void incl(const Operand &op) { 1.1136 + switch (op.kind()) { 1.1137 + case Operand::MEM_REG_DISP: 1.1138 + masm.incl_m32(op.disp(), op.base()); 1.1139 + break; 1.1140 + default: 1.1141 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1142 + } 1.1143 + } 1.1144 + void lock_incl(const Operand &op) { 1.1145 + masm.prefix_lock(); 1.1146 + incl(op); 1.1147 + } 1.1148 + 1.1149 + void decl(const Operand &op) { 1.1150 + switch (op.kind()) { 1.1151 + case Operand::MEM_REG_DISP: 1.1152 + masm.decl_m32(op.disp(), op.base()); 1.1153 + break; 1.1154 + default: 1.1155 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1156 + } 1.1157 + } 1.1158 + void lock_decl(const Operand &op) { 1.1159 + masm.prefix_lock(); 1.1160 + decl(op); 1.1161 + } 1.1162 + 1.1163 + void lock_cmpxchg32(const Register &src, const Operand &op) { 1.1164 + masm.prefix_lock(); 1.1165 + switch (op.kind()) { 1.1166 + case Operand::MEM_REG_DISP: 1.1167 + masm.cmpxchg32(src.code(), op.disp(), op.base()); 1.1168 + break; 1.1169 + default: 1.1170 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1171 + } 1.1172 + } 1.1173 + 1.1174 + void xaddl(const Register &srcdest, const Operand &mem) { 1.1175 + switch (mem.kind()) { 1.1176 + case Operand::MEM_REG_DISP: 1.1177 + masm.xaddl_rm(srcdest.code(), mem.disp(), mem.base()); 1.1178 + break; 1.1179 + case Operand::MEM_SCALE: 1.1180 + masm.xaddl_rm(srcdest.code(), mem.disp(), mem.base(), mem.index(), mem.scale()); 1.1181 + break; 1.1182 + default: 1.1183 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1184 + } 1.1185 + } 1.1186 + 1.1187 + void push(const Imm32 imm) { 1.1188 + masm.push_i32(imm.value); 1.1189 + } 1.1190 + 1.1191 + void push(const Operand &src) { 1.1192 + switch (src.kind()) { 1.1193 + case Operand::REG: 1.1194 + masm.push_r(src.reg()); 1.1195 + break; 1.1196 + case Operand::MEM_REG_DISP: 1.1197 + masm.push_m(src.disp(), src.base()); 1.1198 + break; 1.1199 + default: 1.1200 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1201 + } 1.1202 + } 1.1203 + void push(const Register &src) { 1.1204 + masm.push_r(src.code()); 1.1205 + } 1.1206 + void push(const Address &src) { 1.1207 + masm.push_m(src.offset, src.base.code()); 1.1208 + } 1.1209 + 1.1210 + void pop(const Operand &src) { 1.1211 + switch (src.kind()) { 1.1212 + case Operand::REG: 1.1213 + masm.pop_r(src.reg()); 1.1214 + break; 1.1215 + case Operand::MEM_REG_DISP: 1.1216 + masm.pop_m(src.disp(), src.base()); 1.1217 + break; 1.1218 + default: 1.1219 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1220 + } 1.1221 + } 1.1222 + void pop(const Register &src) { 1.1223 + masm.pop_r(src.code()); 1.1224 + } 1.1225 + 1.1226 + void pushFlags() { 1.1227 + masm.push_flags(); 1.1228 + } 1.1229 + void popFlags() { 1.1230 + masm.pop_flags(); 1.1231 + } 1.1232 + 1.1233 +#ifdef JS_CODEGEN_X86 1.1234 + void pushAllRegs() { 1.1235 + masm.pusha(); 1.1236 + } 1.1237 + void popAllRegs() { 1.1238 + masm.popa(); 1.1239 + } 1.1240 +#endif 1.1241 + 1.1242 + // Zero-extend byte to 32-bit integer. 1.1243 + void movzbl(const Register &src, const Register &dest) { 1.1244 + masm.movzbl_rr(src.code(), dest.code()); 1.1245 + } 1.1246 + 1.1247 + void cdq() { 1.1248 + masm.cdq(); 1.1249 + } 1.1250 + void idiv(Register divisor) { 1.1251 + masm.idivl_r(divisor.code()); 1.1252 + } 1.1253 + void udiv(Register divisor) { 1.1254 + masm.divl_r(divisor.code()); 1.1255 + } 1.1256 + 1.1257 + void unpcklps(const FloatRegister &src, const FloatRegister &dest) { 1.1258 + JS_ASSERT(HasSSE2()); 1.1259 + masm.unpcklps_rr(src.code(), dest.code()); 1.1260 + } 1.1261 + void pinsrd(const Register &src, const FloatRegister &dest) { 1.1262 + JS_ASSERT(HasSSE2()); 1.1263 + masm.pinsrd_rr(src.code(), dest.code()); 1.1264 + } 1.1265 + void pinsrd(const Operand &src, const FloatRegister &dest) { 1.1266 + JS_ASSERT(HasSSE2()); 1.1267 + switch (src.kind()) { 1.1268 + case Operand::REG: 1.1269 + masm.pinsrd_rr(src.reg(), dest.code()); 1.1270 + break; 1.1271 + case Operand::MEM_REG_DISP: 1.1272 + masm.pinsrd_mr(src.disp(), src.base(), dest.code()); 1.1273 + break; 1.1274 + default: 1.1275 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1276 + } 1.1277 + } 1.1278 + void psrldq(Imm32 shift, const FloatRegister &dest) { 1.1279 + JS_ASSERT(HasSSE2()); 1.1280 + masm.psrldq_ir(shift.value, dest.code()); 1.1281 + } 1.1282 + void psllq(Imm32 shift, const FloatRegister &dest) { 1.1283 + JS_ASSERT(HasSSE2()); 1.1284 + masm.psllq_ir(shift.value, dest.code()); 1.1285 + } 1.1286 + void psrlq(Imm32 shift, const FloatRegister &dest) { 1.1287 + JS_ASSERT(HasSSE2()); 1.1288 + masm.psrlq_ir(shift.value, dest.code()); 1.1289 + } 1.1290 + 1.1291 + void cvtsi2sd(const Operand &src, const FloatRegister &dest) { 1.1292 + JS_ASSERT(HasSSE2()); 1.1293 + switch (src.kind()) { 1.1294 + case Operand::REG: 1.1295 + masm.cvtsi2sd_rr(src.reg(), dest.code()); 1.1296 + break; 1.1297 + case Operand::MEM_REG_DISP: 1.1298 + masm.cvtsi2sd_mr(src.disp(), src.base(), dest.code()); 1.1299 + break; 1.1300 + case Operand::MEM_SCALE: 1.1301 + masm.cvtsi2sd_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.1302 + break; 1.1303 + default: 1.1304 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1305 + } 1.1306 + } 1.1307 + void cvttsd2si(const FloatRegister &src, const Register &dest) { 1.1308 + JS_ASSERT(HasSSE2()); 1.1309 + masm.cvttsd2si_rr(src.code(), dest.code()); 1.1310 + } 1.1311 + void cvttss2si(const FloatRegister &src, const Register &dest) { 1.1312 + JS_ASSERT(HasSSE2()); 1.1313 + masm.cvttss2si_rr(src.code(), dest.code()); 1.1314 + } 1.1315 + void cvtsi2ss(const Operand &src, const FloatRegister &dest) { 1.1316 + JS_ASSERT(HasSSE2()); 1.1317 + switch (src.kind()) { 1.1318 + case Operand::REG: 1.1319 + masm.cvtsi2ss_rr(src.reg(), dest.code()); 1.1320 + break; 1.1321 + case Operand::MEM_REG_DISP: 1.1322 + masm.cvtsi2ss_mr(src.disp(), src.base(), dest.code()); 1.1323 + break; 1.1324 + case Operand::MEM_SCALE: 1.1325 + masm.cvtsi2ss_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code()); 1.1326 + break; 1.1327 + default: 1.1328 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1329 + } 1.1330 + } 1.1331 + void cvtsi2ss(const Register &src, const FloatRegister &dest) { 1.1332 + JS_ASSERT(HasSSE2()); 1.1333 + masm.cvtsi2ss_rr(src.code(), dest.code()); 1.1334 + } 1.1335 + void cvtsi2sd(const Register &src, const FloatRegister &dest) { 1.1336 + JS_ASSERT(HasSSE2()); 1.1337 + masm.cvtsi2sd_rr(src.code(), dest.code()); 1.1338 + } 1.1339 + void movmskpd(const FloatRegister &src, const Register &dest) { 1.1340 + JS_ASSERT(HasSSE2()); 1.1341 + masm.movmskpd_rr(src.code(), dest.code()); 1.1342 + } 1.1343 + void movmskps(const FloatRegister &src, const Register &dest) { 1.1344 + JS_ASSERT(HasSSE2()); 1.1345 + masm.movmskps_rr(src.code(), dest.code()); 1.1346 + } 1.1347 + void ptest(const FloatRegister &lhs, const FloatRegister &rhs) { 1.1348 + JS_ASSERT(HasSSE41()); 1.1349 + masm.ptest_rr(rhs.code(), lhs.code()); 1.1350 + } 1.1351 + void ucomisd(const FloatRegister &lhs, const FloatRegister &rhs) { 1.1352 + JS_ASSERT(HasSSE2()); 1.1353 + masm.ucomisd_rr(rhs.code(), lhs.code()); 1.1354 + } 1.1355 + void ucomiss(const FloatRegister &lhs, const FloatRegister &rhs) { 1.1356 + JS_ASSERT(HasSSE2()); 1.1357 + masm.ucomiss_rr(rhs.code(), lhs.code()); 1.1358 + } 1.1359 + void pcmpeqw(const FloatRegister &lhs, const FloatRegister &rhs) { 1.1360 + JS_ASSERT(HasSSE2()); 1.1361 + masm.pcmpeqw_rr(rhs.code(), lhs.code()); 1.1362 + } 1.1363 + void movd(const Register &src, const FloatRegister &dest) { 1.1364 + JS_ASSERT(HasSSE2()); 1.1365 + masm.movd_rr(src.code(), dest.code()); 1.1366 + } 1.1367 + void movd(const FloatRegister &src, const Register &dest) { 1.1368 + JS_ASSERT(HasSSE2()); 1.1369 + masm.movd_rr(src.code(), dest.code()); 1.1370 + } 1.1371 + void addsd(const FloatRegister &src, const FloatRegister &dest) { 1.1372 + JS_ASSERT(HasSSE2()); 1.1373 + masm.addsd_rr(src.code(), dest.code()); 1.1374 + } 1.1375 + void addss(const FloatRegister &src, const FloatRegister &dest) { 1.1376 + JS_ASSERT(HasSSE2()); 1.1377 + masm.addss_rr(src.code(), dest.code()); 1.1378 + } 1.1379 + void addsd(const Operand &src, const FloatRegister &dest) { 1.1380 + JS_ASSERT(HasSSE2()); 1.1381 + switch (src.kind()) { 1.1382 + case Operand::FPREG: 1.1383 + masm.addsd_rr(src.fpu(), dest.code()); 1.1384 + break; 1.1385 + case Operand::MEM_REG_DISP: 1.1386 + masm.addsd_mr(src.disp(), src.base(), dest.code()); 1.1387 + break; 1.1388 + case Operand::MEM_ADDRESS32: 1.1389 + masm.addsd_mr(src.address(), dest.code()); 1.1390 + break; 1.1391 + default: 1.1392 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1393 + } 1.1394 + } 1.1395 + void addss(const Operand &src, const FloatRegister &dest) { 1.1396 + JS_ASSERT(HasSSE2()); 1.1397 + switch (src.kind()) { 1.1398 + case Operand::FPREG: 1.1399 + masm.addss_rr(src.fpu(), dest.code()); 1.1400 + break; 1.1401 + case Operand::MEM_REG_DISP: 1.1402 + masm.addss_mr(src.disp(), src.base(), dest.code()); 1.1403 + break; 1.1404 + case Operand::MEM_ADDRESS32: 1.1405 + masm.addss_mr(src.address(), dest.code()); 1.1406 + break; 1.1407 + default: 1.1408 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1409 + } 1.1410 + } 1.1411 + void subsd(const FloatRegister &src, const FloatRegister &dest) { 1.1412 + JS_ASSERT(HasSSE2()); 1.1413 + masm.subsd_rr(src.code(), dest.code()); 1.1414 + } 1.1415 + void subss(const FloatRegister &src, const FloatRegister &dest) { 1.1416 + JS_ASSERT(HasSSE2()); 1.1417 + masm.subss_rr(src.code(), dest.code()); 1.1418 + } 1.1419 + void subsd(const Operand &src, const FloatRegister &dest) { 1.1420 + JS_ASSERT(HasSSE2()); 1.1421 + switch (src.kind()) { 1.1422 + case Operand::FPREG: 1.1423 + masm.subsd_rr(src.fpu(), dest.code()); 1.1424 + break; 1.1425 + case Operand::MEM_REG_DISP: 1.1426 + masm.subsd_mr(src.disp(), src.base(), dest.code()); 1.1427 + break; 1.1428 + default: 1.1429 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1430 + } 1.1431 + } 1.1432 + void subss(const Operand &src, const FloatRegister &dest) { 1.1433 + JS_ASSERT(HasSSE2()); 1.1434 + switch (src.kind()) { 1.1435 + case Operand::FPREG: 1.1436 + masm.subss_rr(src.fpu(), dest.code()); 1.1437 + break; 1.1438 + case Operand::MEM_REG_DISP: 1.1439 + masm.subss_mr(src.disp(), src.base(), dest.code()); 1.1440 + break; 1.1441 + default: 1.1442 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1443 + } 1.1444 + } 1.1445 + void mulsd(const FloatRegister &src, const FloatRegister &dest) { 1.1446 + JS_ASSERT(HasSSE2()); 1.1447 + masm.mulsd_rr(src.code(), dest.code()); 1.1448 + } 1.1449 + void mulsd(const Operand &src, const FloatRegister &dest) { 1.1450 + JS_ASSERT(HasSSE2()); 1.1451 + switch (src.kind()) { 1.1452 + case Operand::FPREG: 1.1453 + masm.mulsd_rr(src.fpu(), dest.code()); 1.1454 + break; 1.1455 + case Operand::MEM_REG_DISP: 1.1456 + masm.mulsd_mr(src.disp(), src.base(), dest.code()); 1.1457 + break; 1.1458 + default: 1.1459 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1460 + } 1.1461 + } 1.1462 + void mulss(const Operand &src, const FloatRegister &dest) { 1.1463 + JS_ASSERT(HasSSE2()); 1.1464 + switch (src.kind()) { 1.1465 + case Operand::FPREG: 1.1466 + masm.mulss_rr(src.fpu(), dest.code()); 1.1467 + break; 1.1468 + case Operand::MEM_REG_DISP: 1.1469 + masm.mulss_mr(src.disp(), src.base(), dest.code()); 1.1470 + break; 1.1471 + default: 1.1472 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1473 + } 1.1474 + } 1.1475 + void mulss(const FloatRegister &src, const FloatRegister &dest) { 1.1476 + JS_ASSERT(HasSSE2()); 1.1477 + masm.mulss_rr(src.code(), dest.code()); 1.1478 + } 1.1479 + void divsd(const FloatRegister &src, const FloatRegister &dest) { 1.1480 + JS_ASSERT(HasSSE2()); 1.1481 + masm.divsd_rr(src.code(), dest.code()); 1.1482 + } 1.1483 + void divss(const FloatRegister &src, const FloatRegister &dest) { 1.1484 + JS_ASSERT(HasSSE2()); 1.1485 + masm.divss_rr(src.code(), dest.code()); 1.1486 + } 1.1487 + void divsd(const Operand &src, const FloatRegister &dest) { 1.1488 + JS_ASSERT(HasSSE2()); 1.1489 + switch (src.kind()) { 1.1490 + case Operand::FPREG: 1.1491 + masm.divsd_rr(src.fpu(), dest.code()); 1.1492 + break; 1.1493 + case Operand::MEM_REG_DISP: 1.1494 + masm.divsd_mr(src.disp(), src.base(), dest.code()); 1.1495 + break; 1.1496 + default: 1.1497 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1498 + } 1.1499 + } 1.1500 + void divss(const Operand &src, const FloatRegister &dest) { 1.1501 + JS_ASSERT(HasSSE2()); 1.1502 + switch (src.kind()) { 1.1503 + case Operand::FPREG: 1.1504 + masm.divss_rr(src.fpu(), dest.code()); 1.1505 + break; 1.1506 + case Operand::MEM_REG_DISP: 1.1507 + masm.divss_mr(src.disp(), src.base(), dest.code()); 1.1508 + break; 1.1509 + default: 1.1510 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1511 + } 1.1512 + } 1.1513 + void xorpd(const FloatRegister &src, const FloatRegister &dest) { 1.1514 + JS_ASSERT(HasSSE2()); 1.1515 + masm.xorpd_rr(src.code(), dest.code()); 1.1516 + } 1.1517 + void xorps(const FloatRegister &src, const FloatRegister &dest) { 1.1518 + JS_ASSERT(HasSSE2()); 1.1519 + masm.xorps_rr(src.code(), dest.code()); 1.1520 + } 1.1521 + void orpd(const FloatRegister &src, const FloatRegister &dest) { 1.1522 + JS_ASSERT(HasSSE2()); 1.1523 + masm.orpd_rr(src.code(), dest.code()); 1.1524 + } 1.1525 + void andpd(const FloatRegister &src, const FloatRegister &dest) { 1.1526 + JS_ASSERT(HasSSE2()); 1.1527 + masm.andpd_rr(src.code(), dest.code()); 1.1528 + } 1.1529 + void andps(const FloatRegister &src, const FloatRegister &dest) { 1.1530 + JS_ASSERT(HasSSE2()); 1.1531 + masm.andps_rr(src.code(), dest.code()); 1.1532 + } 1.1533 + void sqrtsd(const FloatRegister &src, const FloatRegister &dest) { 1.1534 + JS_ASSERT(HasSSE2()); 1.1535 + masm.sqrtsd_rr(src.code(), dest.code()); 1.1536 + } 1.1537 + void sqrtss(const FloatRegister &src, const FloatRegister &dest) { 1.1538 + JS_ASSERT(HasSSE2()); 1.1539 + masm.sqrtss_rr(src.code(), dest.code()); 1.1540 + } 1.1541 + void roundsd(const FloatRegister &src, const FloatRegister &dest, 1.1542 + JSC::X86Assembler::RoundingMode mode) 1.1543 + { 1.1544 + JS_ASSERT(HasSSE41()); 1.1545 + masm.roundsd_rr(src.code(), dest.code(), mode); 1.1546 + } 1.1547 + void roundss(const FloatRegister &src, const FloatRegister &dest, 1.1548 + JSC::X86Assembler::RoundingMode mode) 1.1549 + { 1.1550 + JS_ASSERT(HasSSE41()); 1.1551 + masm.roundss_rr(src.code(), dest.code(), mode); 1.1552 + } 1.1553 + void minsd(const FloatRegister &src, const FloatRegister &dest) { 1.1554 + JS_ASSERT(HasSSE2()); 1.1555 + masm.minsd_rr(src.code(), dest.code()); 1.1556 + } 1.1557 + void minsd(const Operand &src, const FloatRegister &dest) { 1.1558 + JS_ASSERT(HasSSE2()); 1.1559 + switch (src.kind()) { 1.1560 + case Operand::FPREG: 1.1561 + masm.minsd_rr(src.fpu(), dest.code()); 1.1562 + break; 1.1563 + case Operand::MEM_REG_DISP: 1.1564 + masm.minsd_mr(src.disp(), src.base(), dest.code()); 1.1565 + break; 1.1566 + default: 1.1567 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1568 + } 1.1569 + } 1.1570 + void maxsd(const FloatRegister &src, const FloatRegister &dest) { 1.1571 + JS_ASSERT(HasSSE2()); 1.1572 + masm.maxsd_rr(src.code(), dest.code()); 1.1573 + } 1.1574 + void maxsd(const Operand &src, const FloatRegister &dest) { 1.1575 + JS_ASSERT(HasSSE2()); 1.1576 + switch (src.kind()) { 1.1577 + case Operand::FPREG: 1.1578 + masm.maxsd_rr(src.fpu(), dest.code()); 1.1579 + break; 1.1580 + case Operand::MEM_REG_DISP: 1.1581 + masm.maxsd_mr(src.disp(), src.base(), dest.code()); 1.1582 + break; 1.1583 + default: 1.1584 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1585 + } 1.1586 + } 1.1587 + void fisttp(const Operand &dest) { 1.1588 + JS_ASSERT(HasSSE3()); 1.1589 + switch (dest.kind()) { 1.1590 + case Operand::MEM_REG_DISP: 1.1591 + masm.fisttp_m(dest.disp(), dest.base()); 1.1592 + break; 1.1593 + default: 1.1594 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1595 + } 1.1596 + } 1.1597 + void fld(const Operand &dest) { 1.1598 + switch (dest.kind()) { 1.1599 + case Operand::MEM_REG_DISP: 1.1600 + masm.fld_m(dest.disp(), dest.base()); 1.1601 + break; 1.1602 + default: 1.1603 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1604 + } 1.1605 + } 1.1606 + void fstp(const Operand &src) { 1.1607 + switch (src.kind()) { 1.1608 + case Operand::MEM_REG_DISP: 1.1609 + masm.fstp_m(src.disp(), src.base()); 1.1610 + break; 1.1611 + default: 1.1612 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1613 + } 1.1614 + } 1.1615 + void fstp32(const Operand &src) { 1.1616 + switch (src.kind()) { 1.1617 + case Operand::MEM_REG_DISP: 1.1618 + masm.fstp32_m(src.disp(), src.base()); 1.1619 + break; 1.1620 + default: 1.1621 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.1622 + } 1.1623 + } 1.1624 + 1.1625 + // Defined for compatibility with ARM's assembler 1.1626 + uint32_t actualOffset(uint32_t x) { 1.1627 + return x; 1.1628 + } 1.1629 + 1.1630 + uint32_t actualIndex(uint32_t x) { 1.1631 + return x; 1.1632 + } 1.1633 + 1.1634 + void flushBuffer() { 1.1635 + } 1.1636 + 1.1637 + // Patching. 1.1638 + 1.1639 + static size_t patchWrite_NearCallSize() { 1.1640 + return 5; 1.1641 + } 1.1642 + static uintptr_t getPointer(uint8_t *instPtr) { 1.1643 + uintptr_t *ptr = ((uintptr_t *) instPtr) - 1; 1.1644 + return *ptr; 1.1645 + } 1.1646 + // Write a relative call at the start location |dataLabel|. 1.1647 + // Note that this DOES NOT patch data that comes before |label|. 1.1648 + static void patchWrite_NearCall(CodeLocationLabel startLabel, CodeLocationLabel target) { 1.1649 + uint8_t *start = startLabel.raw(); 1.1650 + *start = 0xE8; 1.1651 + ptrdiff_t offset = target - startLabel - patchWrite_NearCallSize(); 1.1652 + JS_ASSERT(int32_t(offset) == offset); 1.1653 + *((int32_t *) (start + 1)) = offset; 1.1654 + } 1.1655 + 1.1656 + static void patchWrite_Imm32(CodeLocationLabel dataLabel, Imm32 toWrite) { 1.1657 + *((int32_t *) dataLabel.raw() - 1) = toWrite.value; 1.1658 + } 1.1659 + 1.1660 + static void patchDataWithValueCheck(CodeLocationLabel data, PatchedImmPtr newData, 1.1661 + PatchedImmPtr expectedData) { 1.1662 + // The pointer given is a pointer to *after* the data. 1.1663 + uintptr_t *ptr = ((uintptr_t *) data.raw()) - 1; 1.1664 + JS_ASSERT(*ptr == (uintptr_t)expectedData.value); 1.1665 + *ptr = (uintptr_t)newData.value; 1.1666 + } 1.1667 + static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) { 1.1668 + patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value)); 1.1669 + } 1.1670 + static uint32_t nopSize() { 1.1671 + return 1; 1.1672 + } 1.1673 + static uint8_t *nextInstruction(uint8_t *cur, uint32_t *count) { 1.1674 + MOZ_ASSUME_UNREACHABLE("nextInstruction NYI on x86"); 1.1675 + } 1.1676 + 1.1677 + // Toggle a jmp or cmp emitted by toggledJump(). 1.1678 + static void ToggleToJmp(CodeLocationLabel inst) { 1.1679 + uint8_t *ptr = (uint8_t *)inst.raw(); 1.1680 + JS_ASSERT(*ptr == 0x3D); 1.1681 + *ptr = 0xE9; 1.1682 + } 1.1683 + static void ToggleToCmp(CodeLocationLabel inst) { 1.1684 + uint8_t *ptr = (uint8_t *)inst.raw(); 1.1685 + JS_ASSERT(*ptr == 0xE9); 1.1686 + *ptr = 0x3D; 1.1687 + } 1.1688 + static void ToggleCall(CodeLocationLabel inst, bool enabled) { 1.1689 + uint8_t *ptr = (uint8_t *)inst.raw(); 1.1690 + JS_ASSERT(*ptr == 0x3D || // CMP 1.1691 + *ptr == 0xE8); // CALL 1.1692 + *ptr = enabled ? 0xE8 : 0x3D; 1.1693 + } 1.1694 +}; 1.1695 + 1.1696 +} // namespace jit 1.1697 +} // namespace js 1.1698 + 1.1699 +#endif /* jit_shared_Assembler_x86_shared_h */