Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef jit_x64_MacroAssembler_x64_h |
michael@0 | 8 | #define jit_x64_MacroAssembler_x64_h |
michael@0 | 9 | |
michael@0 | 10 | #include "jit/IonFrames.h" |
michael@0 | 11 | #include "jit/MoveResolver.h" |
michael@0 | 12 | #include "jit/shared/MacroAssembler-x86-shared.h" |
michael@0 | 13 | |
michael@0 | 14 | namespace js { |
michael@0 | 15 | namespace jit { |
michael@0 | 16 | |
michael@0 | 17 | struct ImmShiftedTag : public ImmWord |
michael@0 | 18 | { |
michael@0 | 19 | ImmShiftedTag(JSValueShiftedTag shtag) |
michael@0 | 20 | : ImmWord((uintptr_t)shtag) |
michael@0 | 21 | { } |
michael@0 | 22 | |
michael@0 | 23 | ImmShiftedTag(JSValueType type) |
michael@0 | 24 | : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))) |
michael@0 | 25 | { } |
michael@0 | 26 | }; |
michael@0 | 27 | |
michael@0 | 28 | struct ImmTag : public Imm32 |
michael@0 | 29 | { |
michael@0 | 30 | ImmTag(JSValueTag tag) |
michael@0 | 31 | : Imm32(tag) |
michael@0 | 32 | { } |
michael@0 | 33 | }; |
michael@0 | 34 | |
michael@0 | 35 | class MacroAssemblerX64 : public MacroAssemblerX86Shared |
michael@0 | 36 | { |
michael@0 | 37 | // Number of bytes the stack is adjusted inside a call to C. Calls to C may |
michael@0 | 38 | // not be nested. |
michael@0 | 39 | bool inCall_; |
michael@0 | 40 | uint32_t args_; |
michael@0 | 41 | uint32_t passedIntArgs_; |
michael@0 | 42 | uint32_t passedFloatArgs_; |
michael@0 | 43 | uint32_t stackForCall_; |
michael@0 | 44 | bool dynamicAlignment_; |
michael@0 | 45 | bool enoughMemory_; |
michael@0 | 46 | |
michael@0 | 47 | // These use SystemAllocPolicy since asm.js releases memory after each |
michael@0 | 48 | // function is compiled, and these need to live until after all functions |
michael@0 | 49 | // are compiled. |
michael@0 | 50 | struct Double { |
michael@0 | 51 | double value; |
michael@0 | 52 | NonAssertingLabel uses; |
michael@0 | 53 | Double(double value) : value(value) {} |
michael@0 | 54 | }; |
michael@0 | 55 | Vector<Double, 0, SystemAllocPolicy> doubles_; |
michael@0 | 56 | |
michael@0 | 57 | typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap; |
michael@0 | 58 | DoubleMap doubleMap_; |
michael@0 | 59 | |
michael@0 | 60 | struct Float { |
michael@0 | 61 | float value; |
michael@0 | 62 | NonAssertingLabel uses; |
michael@0 | 63 | Float(float value) : value(value) {} |
michael@0 | 64 | }; |
michael@0 | 65 | Vector<Float, 0, SystemAllocPolicy> floats_; |
michael@0 | 66 | |
michael@0 | 67 | typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap; |
michael@0 | 68 | FloatMap floatMap_; |
michael@0 | 69 | |
michael@0 | 70 | void setupABICall(uint32_t arg); |
michael@0 | 71 | |
michael@0 | 72 | protected: |
michael@0 | 73 | MoveResolver moveResolver_; |
michael@0 | 74 | |
michael@0 | 75 | public: |
michael@0 | 76 | using MacroAssemblerX86Shared::call; |
michael@0 | 77 | using MacroAssemblerX86Shared::Push; |
michael@0 | 78 | using MacroAssemblerX86Shared::Pop; |
michael@0 | 79 | using MacroAssemblerX86Shared::callWithExitFrame; |
michael@0 | 80 | using MacroAssemblerX86Shared::branch32; |
michael@0 | 81 | using MacroAssemblerX86Shared::load32; |
michael@0 | 82 | using MacroAssemblerX86Shared::store32; |
michael@0 | 83 | |
michael@0 | 84 | MacroAssemblerX64() |
michael@0 | 85 | : inCall_(false), |
michael@0 | 86 | enoughMemory_(true) |
michael@0 | 87 | { |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | // The buffer is about to be linked, make sure any constant pools or excess |
michael@0 | 91 | // bookkeeping has been flushed to the instruction stream. |
michael@0 | 92 | void finish(); |
michael@0 | 93 | |
michael@0 | 94 | bool oom() const { |
michael@0 | 95 | return MacroAssemblerX86Shared::oom() || !enoughMemory_; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | ///////////////////////////////////////////////////////////////// |
michael@0 | 99 | // X64 helpers. |
michael@0 | 100 | ///////////////////////////////////////////////////////////////// |
michael@0 | 101 | void call(ImmWord target) { |
michael@0 | 102 | mov(target, rax); |
michael@0 | 103 | call(rax); |
michael@0 | 104 | } |
michael@0 | 105 | void call(ImmPtr target) { |
michael@0 | 106 | call(ImmWord(uintptr_t(target.value))); |
michael@0 | 107 | } |
michael@0 | 108 | void call(AsmJSImmPtr target) { |
michael@0 | 109 | mov(target, rax); |
michael@0 | 110 | call(rax); |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | void call(const CallSiteDesc &desc, AsmJSImmPtr target) { |
michael@0 | 114 | call(target); |
michael@0 | 115 | appendCallSite(desc); |
michael@0 | 116 | } |
michael@0 | 117 | void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { |
michael@0 | 118 | call(CallSiteDesc::Exit(), target); |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | // Refers to the upper 32 bits of a 64-bit Value operand. |
michael@0 | 122 | // On x86_64, the upper 32 bits do not necessarily only contain the type. |
michael@0 | 123 | Operand ToUpper32(Operand base) { |
michael@0 | 124 | switch (base.kind()) { |
michael@0 | 125 | case Operand::MEM_REG_DISP: |
michael@0 | 126 | return Operand(Register::FromCode(base.base()), base.disp() + 4); |
michael@0 | 127 | |
michael@0 | 128 | case Operand::MEM_SCALE: |
michael@0 | 129 | return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), |
michael@0 | 130 | base.scale(), base.disp() + 4); |
michael@0 | 131 | |
michael@0 | 132 | default: |
michael@0 | 133 | MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); |
michael@0 | 134 | } |
michael@0 | 135 | } |
michael@0 | 136 | static inline Operand ToUpper32(const Address &address) { |
michael@0 | 137 | return Operand(address.base, address.offset + 4); |
michael@0 | 138 | } |
michael@0 | 139 | static inline Operand ToUpper32(const BaseIndex &address) { |
michael@0 | 140 | return Operand(address.base, address.index, address.scale, address.offset + 4); |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | uint32_t Upper32Of(JSValueShiftedTag tag) { |
michael@0 | 144 | union { // Implemented in this way to appease MSVC++. |
michael@0 | 145 | uint64_t tag; |
michael@0 | 146 | struct { |
michael@0 | 147 | uint32_t lo32; |
michael@0 | 148 | uint32_t hi32; |
michael@0 | 149 | } s; |
michael@0 | 150 | } e; |
michael@0 | 151 | e.tag = tag; |
michael@0 | 152 | return e.s.hi32; |
michael@0 | 153 | } |
michael@0 | 154 | |
michael@0 | 155 | JSValueShiftedTag GetShiftedTag(JSValueType type) { |
michael@0 | 156 | return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | ///////////////////////////////////////////////////////////////// |
michael@0 | 160 | // X86/X64-common interface. |
michael@0 | 161 | ///////////////////////////////////////////////////////////////// |
michael@0 | 162 | void storeValue(ValueOperand val, Operand dest) { |
michael@0 | 163 | movq(val.valueReg(), dest); |
michael@0 | 164 | } |
michael@0 | 165 | void storeValue(ValueOperand val, const Address &dest) { |
michael@0 | 166 | storeValue(val, Operand(dest)); |
michael@0 | 167 | } |
michael@0 | 168 | template <typename T> |
michael@0 | 169 | void storeValue(JSValueType type, Register reg, const T &dest) { |
michael@0 | 170 | // Value types with 32-bit payloads can be emitted as two 32-bit moves. |
michael@0 | 171 | if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { |
michael@0 | 172 | movl(reg, Operand(dest)); |
michael@0 | 173 | movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest))); |
michael@0 | 174 | } else { |
michael@0 | 175 | boxValue(type, reg, ScratchReg); |
michael@0 | 176 | movq(ScratchReg, Operand(dest)); |
michael@0 | 177 | } |
michael@0 | 178 | } |
michael@0 | 179 | template <typename T> |
michael@0 | 180 | void storeValue(const Value &val, const T &dest) { |
michael@0 | 181 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 182 | if (val.isMarkable()) { |
michael@0 | 183 | movWithPatch(ImmWord(jv.asBits), ScratchReg); |
michael@0 | 184 | writeDataRelocation(val); |
michael@0 | 185 | } else { |
michael@0 | 186 | mov(ImmWord(jv.asBits), ScratchReg); |
michael@0 | 187 | } |
michael@0 | 188 | movq(ScratchReg, Operand(dest)); |
michael@0 | 189 | } |
michael@0 | 190 | void storeValue(ValueOperand val, BaseIndex dest) { |
michael@0 | 191 | storeValue(val, Operand(dest)); |
michael@0 | 192 | } |
michael@0 | 193 | void loadValue(Operand src, ValueOperand val) { |
michael@0 | 194 | movq(src, val.valueReg()); |
michael@0 | 195 | } |
michael@0 | 196 | void loadValue(Address src, ValueOperand val) { |
michael@0 | 197 | loadValue(Operand(src), val); |
michael@0 | 198 | } |
michael@0 | 199 | void loadValue(const BaseIndex &src, ValueOperand val) { |
michael@0 | 200 | loadValue(Operand(src), val); |
michael@0 | 201 | } |
michael@0 | 202 | void tagValue(JSValueType type, Register payload, ValueOperand dest) { |
michael@0 | 203 | JS_ASSERT(dest.valueReg() != ScratchReg); |
michael@0 | 204 | if (payload != dest.valueReg()) |
michael@0 | 205 | movq(payload, dest.valueReg()); |
michael@0 | 206 | mov(ImmShiftedTag(type), ScratchReg); |
michael@0 | 207 | orq(ScratchReg, dest.valueReg()); |
michael@0 | 208 | } |
michael@0 | 209 | void pushValue(ValueOperand val) { |
michael@0 | 210 | push(val.valueReg()); |
michael@0 | 211 | } |
michael@0 | 212 | void Push(const ValueOperand &val) { |
michael@0 | 213 | pushValue(val); |
michael@0 | 214 | framePushed_ += sizeof(Value); |
michael@0 | 215 | } |
michael@0 | 216 | void popValue(ValueOperand val) { |
michael@0 | 217 | pop(val.valueReg()); |
michael@0 | 218 | } |
michael@0 | 219 | void pushValue(const Value &val) { |
michael@0 | 220 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 221 | push(ImmWord(jv.asBits)); |
michael@0 | 222 | } |
michael@0 | 223 | void pushValue(JSValueType type, Register reg) { |
michael@0 | 224 | boxValue(type, reg, ScratchReg); |
michael@0 | 225 | push(ScratchReg); |
michael@0 | 226 | } |
michael@0 | 227 | void pushValue(const Address &addr) { |
michael@0 | 228 | push(Operand(addr)); |
michael@0 | 229 | } |
michael@0 | 230 | void Pop(const ValueOperand &val) { |
michael@0 | 231 | popValue(val); |
michael@0 | 232 | framePushed_ -= sizeof(Value); |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | void moveValue(const Value &val, const Register &dest) { |
michael@0 | 236 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 237 | movWithPatch(ImmWord(jv.asBits), dest); |
michael@0 | 238 | writeDataRelocation(val); |
michael@0 | 239 | } |
michael@0 | 240 | void moveValue(const Value &src, const ValueOperand &dest) { |
michael@0 | 241 | moveValue(src, dest.valueReg()); |
michael@0 | 242 | } |
michael@0 | 243 | void moveValue(const ValueOperand &src, const ValueOperand &dest) { |
michael@0 | 244 | if (src.valueReg() != dest.valueReg()) |
michael@0 | 245 | movq(src.valueReg(), dest.valueReg()); |
michael@0 | 246 | } |
michael@0 | 247 | void boxValue(JSValueType type, Register src, Register dest) { |
michael@0 | 248 | JS_ASSERT(src != dest); |
michael@0 | 249 | |
michael@0 | 250 | JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); |
michael@0 | 251 | #ifdef DEBUG |
michael@0 | 252 | if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { |
michael@0 | 253 | Label upper32BitsZeroed; |
michael@0 | 254 | movePtr(ImmWord(UINT32_MAX), dest); |
michael@0 | 255 | branchPtr(Assembler::BelowOrEqual, src, dest, &upper32BitsZeroed); |
michael@0 | 256 | breakpoint(); |
michael@0 | 257 | bind(&upper32BitsZeroed); |
michael@0 | 258 | } |
michael@0 | 259 | #endif |
michael@0 | 260 | mov(ImmShiftedTag(tag), dest); |
michael@0 | 261 | orq(src, dest); |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | Condition testUndefined(Condition cond, Register tag) { |
michael@0 | 265 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 266 | cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED)); |
michael@0 | 267 | return cond; |
michael@0 | 268 | } |
michael@0 | 269 | Condition testInt32(Condition cond, Register tag) { |
michael@0 | 270 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 271 | cmpl(tag, ImmTag(JSVAL_TAG_INT32)); |
michael@0 | 272 | return cond; |
michael@0 | 273 | } |
michael@0 | 274 | Condition testBoolean(Condition cond, Register tag) { |
michael@0 | 275 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 276 | cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN)); |
michael@0 | 277 | return cond; |
michael@0 | 278 | } |
michael@0 | 279 | Condition testNull(Condition cond, Register tag) { |
michael@0 | 280 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 281 | cmpl(tag, ImmTag(JSVAL_TAG_NULL)); |
michael@0 | 282 | return cond; |
michael@0 | 283 | } |
michael@0 | 284 | Condition testString(Condition cond, Register tag) { |
michael@0 | 285 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 286 | cmpl(tag, ImmTag(JSVAL_TAG_STRING)); |
michael@0 | 287 | return cond; |
michael@0 | 288 | } |
michael@0 | 289 | Condition testObject(Condition cond, Register tag) { |
michael@0 | 290 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 291 | cmpl(tag, ImmTag(JSVAL_TAG_OBJECT)); |
michael@0 | 292 | return cond; |
michael@0 | 293 | } |
michael@0 | 294 | Condition testDouble(Condition cond, Register tag) { |
michael@0 | 295 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 296 | cmpl(tag, Imm32(JSVAL_TAG_MAX_DOUBLE)); |
michael@0 | 297 | return cond == Equal ? BelowOrEqual : Above; |
michael@0 | 298 | } |
michael@0 | 299 | Condition testNumber(Condition cond, Register tag) { |
michael@0 | 300 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 301 | cmpl(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); |
michael@0 | 302 | return cond == Equal ? BelowOrEqual : Above; |
michael@0 | 303 | } |
michael@0 | 304 | Condition testGCThing(Condition cond, Register tag) { |
michael@0 | 305 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 306 | cmpl(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
michael@0 | 307 | return cond == Equal ? AboveOrEqual : Below; |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | Condition testMagic(Condition cond, const Register &tag) { |
michael@0 | 311 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 312 | cmpl(tag, ImmTag(JSVAL_TAG_MAGIC)); |
michael@0 | 313 | return cond; |
michael@0 | 314 | } |
michael@0 | 315 | Condition testError(Condition cond, const Register &tag) { |
michael@0 | 316 | return testMagic(cond, tag); |
michael@0 | 317 | } |
michael@0 | 318 | Condition testPrimitive(Condition cond, const Register &tag) { |
michael@0 | 319 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 320 | cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); |
michael@0 | 321 | return cond == Equal ? Below : AboveOrEqual; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | Condition testUndefined(Condition cond, const ValueOperand &src) { |
michael@0 | 325 | splitTag(src, ScratchReg); |
michael@0 | 326 | return testUndefined(cond, ScratchReg); |
michael@0 | 327 | } |
michael@0 | 328 | Condition testInt32(Condition cond, const ValueOperand &src) { |
michael@0 | 329 | splitTag(src, ScratchReg); |
michael@0 | 330 | return testInt32(cond, ScratchReg); |
michael@0 | 331 | } |
michael@0 | 332 | Condition testBoolean(Condition cond, const ValueOperand &src) { |
michael@0 | 333 | splitTag(src, ScratchReg); |
michael@0 | 334 | return testBoolean(cond, ScratchReg); |
michael@0 | 335 | } |
michael@0 | 336 | Condition testDouble(Condition cond, const ValueOperand &src) { |
michael@0 | 337 | splitTag(src, ScratchReg); |
michael@0 | 338 | return testDouble(cond, ScratchReg); |
michael@0 | 339 | } |
michael@0 | 340 | Condition testNumber(Condition cond, const ValueOperand &src) { |
michael@0 | 341 | splitTag(src, ScratchReg); |
michael@0 | 342 | return testNumber(cond, ScratchReg); |
michael@0 | 343 | } |
michael@0 | 344 | Condition testNull(Condition cond, const ValueOperand &src) { |
michael@0 | 345 | splitTag(src, ScratchReg); |
michael@0 | 346 | return testNull(cond, ScratchReg); |
michael@0 | 347 | } |
michael@0 | 348 | Condition testString(Condition cond, const ValueOperand &src) { |
michael@0 | 349 | splitTag(src, ScratchReg); |
michael@0 | 350 | return testString(cond, ScratchReg); |
michael@0 | 351 | } |
michael@0 | 352 | Condition testObject(Condition cond, const ValueOperand &src) { |
michael@0 | 353 | splitTag(src, ScratchReg); |
michael@0 | 354 | return testObject(cond, ScratchReg); |
michael@0 | 355 | } |
michael@0 | 356 | Condition testGCThing(Condition cond, const ValueOperand &src) { |
michael@0 | 357 | splitTag(src, ScratchReg); |
michael@0 | 358 | return testGCThing(cond, ScratchReg); |
michael@0 | 359 | } |
michael@0 | 360 | Condition testPrimitive(Condition cond, const ValueOperand &src) { |
michael@0 | 361 | splitTag(src, ScratchReg); |
michael@0 | 362 | return testPrimitive(cond, ScratchReg); |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | |
michael@0 | 366 | Condition testUndefined(Condition cond, const Address &src) { |
michael@0 | 367 | splitTag(src, ScratchReg); |
michael@0 | 368 | return testUndefined(cond, ScratchReg); |
michael@0 | 369 | } |
michael@0 | 370 | Condition testInt32(Condition cond, const Address &src) { |
michael@0 | 371 | splitTag(src, ScratchReg); |
michael@0 | 372 | return testInt32(cond, ScratchReg); |
michael@0 | 373 | } |
michael@0 | 374 | Condition testBoolean(Condition cond, const Address &src) { |
michael@0 | 375 | splitTag(src, ScratchReg); |
michael@0 | 376 | return testBoolean(cond, ScratchReg); |
michael@0 | 377 | } |
michael@0 | 378 | Condition testDouble(Condition cond, const Address &src) { |
michael@0 | 379 | splitTag(src, ScratchReg); |
michael@0 | 380 | return testDouble(cond, ScratchReg); |
michael@0 | 381 | } |
michael@0 | 382 | Condition testNumber(Condition cond, const Address &src) { |
michael@0 | 383 | splitTag(src, ScratchReg); |
michael@0 | 384 | return testNumber(cond, ScratchReg); |
michael@0 | 385 | } |
michael@0 | 386 | Condition testNull(Condition cond, const Address &src) { |
michael@0 | 387 | splitTag(src, ScratchReg); |
michael@0 | 388 | return testNull(cond, ScratchReg); |
michael@0 | 389 | } |
michael@0 | 390 | Condition testString(Condition cond, const Address &src) { |
michael@0 | 391 | splitTag(src, ScratchReg); |
michael@0 | 392 | return testString(cond, ScratchReg); |
michael@0 | 393 | } |
michael@0 | 394 | Condition testObject(Condition cond, const Address &src) { |
michael@0 | 395 | splitTag(src, ScratchReg); |
michael@0 | 396 | return testObject(cond, ScratchReg); |
michael@0 | 397 | } |
michael@0 | 398 | Condition testPrimitive(Condition cond, const Address &src) { |
michael@0 | 399 | splitTag(src, ScratchReg); |
michael@0 | 400 | return testPrimitive(cond, ScratchReg); |
michael@0 | 401 | } |
michael@0 | 402 | Condition testGCThing(Condition cond, const Address &src) { |
michael@0 | 403 | splitTag(src, ScratchReg); |
michael@0 | 404 | return testGCThing(cond, ScratchReg); |
michael@0 | 405 | } |
michael@0 | 406 | Condition testMagic(Condition cond, const Address &src) { |
michael@0 | 407 | splitTag(src, ScratchReg); |
michael@0 | 408 | return testMagic(cond, ScratchReg); |
michael@0 | 409 | } |
michael@0 | 410 | |
michael@0 | 411 | |
michael@0 | 412 | Condition testUndefined(Condition cond, const BaseIndex &src) { |
michael@0 | 413 | splitTag(src, ScratchReg); |
michael@0 | 414 | return testUndefined(cond, ScratchReg); |
michael@0 | 415 | } |
michael@0 | 416 | Condition testNull(Condition cond, const BaseIndex &src) { |
michael@0 | 417 | splitTag(src, ScratchReg); |
michael@0 | 418 | return testNull(cond, ScratchReg); |
michael@0 | 419 | } |
michael@0 | 420 | Condition testBoolean(Condition cond, const BaseIndex &src) { |
michael@0 | 421 | splitTag(src, ScratchReg); |
michael@0 | 422 | return testBoolean(cond, ScratchReg); |
michael@0 | 423 | } |
michael@0 | 424 | Condition testString(Condition cond, const BaseIndex &src) { |
michael@0 | 425 | splitTag(src, ScratchReg); |
michael@0 | 426 | return testString(cond, ScratchReg); |
michael@0 | 427 | } |
michael@0 | 428 | Condition testInt32(Condition cond, const BaseIndex &src) { |
michael@0 | 429 | splitTag(src, ScratchReg); |
michael@0 | 430 | return testInt32(cond, ScratchReg); |
michael@0 | 431 | } |
michael@0 | 432 | Condition testObject(Condition cond, const BaseIndex &src) { |
michael@0 | 433 | splitTag(src, ScratchReg); |
michael@0 | 434 | return testObject(cond, ScratchReg); |
michael@0 | 435 | } |
michael@0 | 436 | Condition testDouble(Condition cond, const BaseIndex &src) { |
michael@0 | 437 | splitTag(src, ScratchReg); |
michael@0 | 438 | return testDouble(cond, ScratchReg); |
michael@0 | 439 | } |
michael@0 | 440 | Condition testMagic(Condition cond, const BaseIndex &src) { |
michael@0 | 441 | splitTag(src, ScratchReg); |
michael@0 | 442 | return testMagic(cond, ScratchReg); |
michael@0 | 443 | } |
michael@0 | 444 | Condition testGCThing(Condition cond, const BaseIndex &src) { |
michael@0 | 445 | splitTag(src, ScratchReg); |
michael@0 | 446 | return testGCThing(cond, ScratchReg); |
michael@0 | 447 | } |
michael@0 | 448 | |
michael@0 | 449 | Condition isMagic(Condition cond, const ValueOperand &src, JSWhyMagic why) { |
michael@0 | 450 | uint64_t magic = MagicValue(why).asRawBits(); |
michael@0 | 451 | cmpPtr(src.valueReg(), ImmWord(magic)); |
michael@0 | 452 | return cond; |
michael@0 | 453 | } |
michael@0 | 454 | |
michael@0 | 455 | void cmpPtr(const Register &lhs, const ImmWord rhs) { |
michael@0 | 456 | JS_ASSERT(lhs != ScratchReg); |
michael@0 | 457 | mov(rhs, ScratchReg); |
michael@0 | 458 | cmpq(lhs, ScratchReg); |
michael@0 | 459 | } |
michael@0 | 460 | void cmpPtr(const Register &lhs, const ImmPtr rhs) { |
michael@0 | 461 | cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); |
michael@0 | 462 | } |
michael@0 | 463 | void cmpPtr(const Register &lhs, const ImmGCPtr rhs) { |
michael@0 | 464 | JS_ASSERT(lhs != ScratchReg); |
michael@0 | 465 | movq(rhs, ScratchReg); |
michael@0 | 466 | cmpq(lhs, ScratchReg); |
michael@0 | 467 | } |
michael@0 | 468 | void cmpPtr(const Register &lhs, const Imm32 rhs) { |
michael@0 | 469 | cmpq(lhs, rhs); |
michael@0 | 470 | } |
michael@0 | 471 | void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) { |
michael@0 | 472 | movq(rhs, ScratchReg); |
michael@0 | 473 | cmpq(lhs, ScratchReg); |
michael@0 | 474 | } |
michael@0 | 475 | void cmpPtr(const Operand &lhs, const ImmWord rhs) { |
michael@0 | 476 | if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { |
michael@0 | 477 | cmpq(lhs, Imm32((int32_t)rhs.value)); |
michael@0 | 478 | } else { |
michael@0 | 479 | mov(rhs, ScratchReg); |
michael@0 | 480 | cmpq(lhs, ScratchReg); |
michael@0 | 481 | } |
michael@0 | 482 | } |
michael@0 | 483 | void cmpPtr(const Operand &lhs, const ImmPtr rhs) { |
michael@0 | 484 | cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); |
michael@0 | 485 | } |
michael@0 | 486 | void cmpPtr(const Address &lhs, const ImmGCPtr rhs) { |
michael@0 | 487 | cmpPtr(Operand(lhs), rhs); |
michael@0 | 488 | } |
michael@0 | 489 | void cmpPtr(const Address &lhs, const ImmWord rhs) { |
michael@0 | 490 | cmpPtr(Operand(lhs), rhs); |
michael@0 | 491 | } |
michael@0 | 492 | void cmpPtr(const Address &lhs, const ImmPtr rhs) { |
michael@0 | 493 | cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); |
michael@0 | 494 | } |
michael@0 | 495 | void cmpPtr(const Operand &lhs, const Register &rhs) { |
michael@0 | 496 | cmpq(lhs, rhs); |
michael@0 | 497 | } |
michael@0 | 498 | void cmpPtr(const Operand &lhs, const Imm32 rhs) { |
michael@0 | 499 | cmpq(lhs, rhs); |
michael@0 | 500 | } |
michael@0 | 501 | void cmpPtr(const Address &lhs, const Register &rhs) { |
michael@0 | 502 | cmpPtr(Operand(lhs), rhs); |
michael@0 | 503 | } |
michael@0 | 504 | void cmpPtr(const Register &lhs, const Register &rhs) { |
michael@0 | 505 | return cmpq(lhs, rhs); |
michael@0 | 506 | } |
michael@0 | 507 | void testPtr(const Register &lhs, const Register &rhs) { |
michael@0 | 508 | testq(lhs, rhs); |
michael@0 | 509 | } |
michael@0 | 510 | |
michael@0 | 511 | template <typename T1, typename T2> |
michael@0 | 512 | void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest) |
michael@0 | 513 | { |
michael@0 | 514 | cmpPtr(lhs, rhs); |
michael@0 | 515 | emitSet(cond, dest); |
michael@0 | 516 | } |
michael@0 | 517 | |
michael@0 | 518 | ///////////////////////////////////////////////////////////////// |
michael@0 | 519 | // Common interface. |
michael@0 | 520 | ///////////////////////////////////////////////////////////////// |
michael@0 | 521 | void reserveStack(uint32_t amount) { |
michael@0 | 522 | if (amount) |
michael@0 | 523 | subq(Imm32(amount), StackPointer); |
michael@0 | 524 | framePushed_ += amount; |
michael@0 | 525 | } |
michael@0 | 526 | void freeStack(uint32_t amount) { |
michael@0 | 527 | JS_ASSERT(amount <= framePushed_); |
michael@0 | 528 | if (amount) |
michael@0 | 529 | addq(Imm32(amount), StackPointer); |
michael@0 | 530 | framePushed_ -= amount; |
michael@0 | 531 | } |
michael@0 | 532 | void freeStack(Register amount) { |
michael@0 | 533 | addq(amount, StackPointer); |
michael@0 | 534 | } |
michael@0 | 535 | |
michael@0 | 536 | void addPtr(const Register &src, const Register &dest) { |
michael@0 | 537 | addq(src, dest); |
michael@0 | 538 | } |
michael@0 | 539 | void addPtr(Imm32 imm, const Register &dest) { |
michael@0 | 540 | addq(imm, dest); |
michael@0 | 541 | } |
michael@0 | 542 | void addPtr(Imm32 imm, const Address &dest) { |
michael@0 | 543 | addq(imm, Operand(dest)); |
michael@0 | 544 | } |
michael@0 | 545 | void addPtr(Imm32 imm, const Operand &dest) { |
michael@0 | 546 | addq(imm, dest); |
michael@0 | 547 | } |
michael@0 | 548 | void addPtr(ImmWord imm, const Register &dest) { |
michael@0 | 549 | JS_ASSERT(dest != ScratchReg); |
michael@0 | 550 | if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { |
michael@0 | 551 | addq(Imm32((int32_t)imm.value), dest); |
michael@0 | 552 | } else { |
michael@0 | 553 | mov(imm, ScratchReg); |
michael@0 | 554 | addq(ScratchReg, dest); |
michael@0 | 555 | } |
michael@0 | 556 | } |
michael@0 | 557 | void addPtr(ImmPtr imm, const Register &dest) { |
michael@0 | 558 | addPtr(ImmWord(uintptr_t(imm.value)), dest); |
michael@0 | 559 | } |
michael@0 | 560 | void addPtr(const Address &src, const Register &dest) { |
michael@0 | 561 | addq(Operand(src), dest); |
michael@0 | 562 | } |
michael@0 | 563 | void subPtr(Imm32 imm, const Register &dest) { |
michael@0 | 564 | subq(imm, dest); |
michael@0 | 565 | } |
michael@0 | 566 | void subPtr(const Register &src, const Register &dest) { |
michael@0 | 567 | subq(src, dest); |
michael@0 | 568 | } |
michael@0 | 569 | void subPtr(const Address &addr, const Register &dest) { |
michael@0 | 570 | subq(Operand(addr), dest); |
michael@0 | 571 | } |
michael@0 | 572 | void subPtr(const Register &src, const Address &dest) { |
michael@0 | 573 | subq(src, Operand(dest)); |
michael@0 | 574 | } |
michael@0 | 575 | |
michael@0 | 576 | void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { |
michael@0 | 577 | if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) { |
michael@0 | 578 | branch32(cond, Operand(lhs), rhs, label); |
michael@0 | 579 | } else { |
michael@0 | 580 | mov(ImmPtr(lhs.addr), ScratchReg); |
michael@0 | 581 | branch32(cond, Address(ScratchReg, 0), rhs, label); |
michael@0 | 582 | } |
michael@0 | 583 | } |
michael@0 | 584 | void branch32(Condition cond, const AbsoluteAddress &lhs, Register rhs, Label *label) { |
michael@0 | 585 | if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) { |
michael@0 | 586 | branch32(cond, Operand(lhs), rhs, label); |
michael@0 | 587 | } else { |
michael@0 | 588 | mov(ImmPtr(lhs.addr), ScratchReg); |
michael@0 | 589 | branch32(cond, Address(ScratchReg, 0), rhs, label); |
michael@0 | 590 | } |
michael@0 | 591 | } |
michael@0 | 592 | |
michael@0 | 593 | // Specialization for AbsoluteAddress. |
michael@0 | 594 | void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { |
michael@0 | 595 | JS_ASSERT(ptr != ScratchReg); |
michael@0 | 596 | if (JSC::X86Assembler::isAddressImmediate(addr.addr)) { |
michael@0 | 597 | branchPtr(cond, Operand(addr), ptr, label); |
michael@0 | 598 | } else { |
michael@0 | 599 | mov(ImmPtr(addr.addr), ScratchReg); |
michael@0 | 600 | branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label); |
michael@0 | 601 | } |
michael@0 | 602 | } |
michael@0 | 603 | void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, Label *label) { |
michael@0 | 604 | JS_ASSERT(ptr != ScratchReg); |
michael@0 | 605 | mov(AsmJSImmPtr(addr.kind()), ScratchReg); |
michael@0 | 606 | branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label); |
michael@0 | 607 | } |
michael@0 | 608 | |
michael@0 | 609 | void branchPrivatePtr(Condition cond, Address lhs, ImmPtr ptr, Label *label) { |
michael@0 | 610 | branchPtr(cond, lhs, ImmWord(uintptr_t(ptr.value) >> 1), label); |
michael@0 | 611 | } |
michael@0 | 612 | |
michael@0 | 613 | void branchPrivatePtr(Condition cond, Address lhs, Register ptr, Label *label) { |
michael@0 | 614 | if (ptr != ScratchReg) |
michael@0 | 615 | movePtr(ptr, ScratchReg); |
michael@0 | 616 | rshiftPtr(Imm32(1), ScratchReg); |
michael@0 | 617 | branchPtr(cond, lhs, ScratchReg, label); |
michael@0 | 618 | } |
michael@0 | 619 | |
michael@0 | 620 | template <typename T, typename S> |
michael@0 | 621 | void branchPtr(Condition cond, T lhs, S ptr, Label *label) { |
michael@0 | 622 | cmpPtr(Operand(lhs), ptr); |
michael@0 | 623 | j(cond, label); |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | CodeOffsetJump jumpWithPatch(RepatchLabel *label) { |
michael@0 | 627 | JmpSrc src = jmpSrc(label); |
michael@0 | 628 | return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED)); |
michael@0 | 629 | } |
michael@0 | 630 | |
michael@0 | 631 | CodeOffsetJump jumpWithPatch(RepatchLabel *label, Condition cond) { |
michael@0 | 632 | JmpSrc src = jSrc(cond, label); |
michael@0 | 633 | return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED)); |
michael@0 | 634 | } |
michael@0 | 635 | |
michael@0 | 636 | template <typename S, typename T> |
michael@0 | 637 | CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel *label) { |
michael@0 | 638 | cmpPtr(lhs, ptr); |
michael@0 | 639 | return jumpWithPatch(label, cond); |
michael@0 | 640 | } |
michael@0 | 641 | void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
michael@0 | 642 | cmpPtr(lhs, rhs); |
michael@0 | 643 | j(cond, label); |
michael@0 | 644 | } |
michael@0 | 645 | void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
michael@0 | 646 | testq(lhs, rhs); |
michael@0 | 647 | j(cond, label); |
michael@0 | 648 | } |
michael@0 | 649 | void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { |
michael@0 | 650 | testq(lhs, imm); |
michael@0 | 651 | j(cond, label); |
michael@0 | 652 | } |
michael@0 | 653 | void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { |
michael@0 | 654 | testq(Operand(lhs), imm); |
michael@0 | 655 | j(cond, label); |
michael@0 | 656 | } |
michael@0 | 657 | void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { |
michael@0 | 658 | subPtr(imm, lhs); |
michael@0 | 659 | j(cond, label); |
michael@0 | 660 | } |
michael@0 | 661 | |
michael@0 | 662 | void movePtr(const Register &src, const Register &dest) { |
michael@0 | 663 | movq(src, dest); |
michael@0 | 664 | } |
michael@0 | 665 | void movePtr(const Register &src, const Operand &dest) { |
michael@0 | 666 | movq(src, dest); |
michael@0 | 667 | } |
michael@0 | 668 | void movePtr(ImmWord imm, Register dest) { |
michael@0 | 669 | mov(imm, dest); |
michael@0 | 670 | } |
michael@0 | 671 | void movePtr(ImmPtr imm, Register dest) { |
michael@0 | 672 | mov(imm, dest); |
michael@0 | 673 | } |
michael@0 | 674 | void movePtr(AsmJSImmPtr imm, const Register &dest) { |
michael@0 | 675 | mov(imm, dest); |
michael@0 | 676 | } |
michael@0 | 677 | void movePtr(ImmGCPtr imm, Register dest) { |
michael@0 | 678 | movq(imm, dest); |
michael@0 | 679 | } |
michael@0 | 680 | void loadPtr(const AbsoluteAddress &address, Register dest) { |
michael@0 | 681 | if (JSC::X86Assembler::isAddressImmediate(address.addr)) { |
michael@0 | 682 | movq(Operand(address), dest); |
michael@0 | 683 | } else { |
michael@0 | 684 | mov(ImmPtr(address.addr), ScratchReg); |
michael@0 | 685 | loadPtr(Address(ScratchReg, 0x0), dest); |
michael@0 | 686 | } |
michael@0 | 687 | } |
michael@0 | 688 | void loadPtr(const Address &address, Register dest) { |
michael@0 | 689 | movq(Operand(address), dest); |
michael@0 | 690 | } |
michael@0 | 691 | void loadPtr(const Operand &src, Register dest) { |
michael@0 | 692 | movq(src, dest); |
michael@0 | 693 | } |
michael@0 | 694 | void loadPtr(const BaseIndex &src, Register dest) { |
michael@0 | 695 | movq(Operand(src), dest); |
michael@0 | 696 | } |
michael@0 | 697 | void loadPrivate(const Address &src, Register dest) { |
michael@0 | 698 | loadPtr(src, dest); |
michael@0 | 699 | shlq(Imm32(1), dest); |
michael@0 | 700 | } |
michael@0 | 701 | void load32(const AbsoluteAddress &address, Register dest) { |
michael@0 | 702 | if (JSC::X86Assembler::isAddressImmediate(address.addr)) { |
michael@0 | 703 | movl(Operand(address), dest); |
michael@0 | 704 | } else { |
michael@0 | 705 | mov(ImmPtr(address.addr), ScratchReg); |
michael@0 | 706 | load32(Address(ScratchReg, 0x0), dest); |
michael@0 | 707 | } |
michael@0 | 708 | } |
michael@0 | 709 | void storePtr(ImmWord imm, const Address &address) { |
michael@0 | 710 | if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { |
michael@0 | 711 | movq(Imm32((int32_t)imm.value), Operand(address)); |
michael@0 | 712 | } else { |
michael@0 | 713 | mov(imm, ScratchReg); |
michael@0 | 714 | movq(ScratchReg, Operand(address)); |
michael@0 | 715 | } |
michael@0 | 716 | } |
michael@0 | 717 | void storePtr(ImmPtr imm, const Address &address) { |
michael@0 | 718 | storePtr(ImmWord(uintptr_t(imm.value)), address); |
michael@0 | 719 | } |
michael@0 | 720 | void storePtr(ImmGCPtr imm, const Address &address) { |
michael@0 | 721 | movq(imm, ScratchReg); |
michael@0 | 722 | movq(ScratchReg, Operand(address)); |
michael@0 | 723 | } |
michael@0 | 724 | void storePtr(Register src, const Address &address) { |
michael@0 | 725 | movq(src, Operand(address)); |
michael@0 | 726 | } |
michael@0 | 727 | void storePtr(Register src, const Operand &dest) { |
michael@0 | 728 | movq(src, dest); |
michael@0 | 729 | } |
michael@0 | 730 | void storePtr(const Register &src, const AbsoluteAddress &address) { |
michael@0 | 731 | if (JSC::X86Assembler::isAddressImmediate(address.addr)) { |
michael@0 | 732 | movq(src, Operand(address)); |
michael@0 | 733 | } else { |
michael@0 | 734 | mov(ImmPtr(address.addr), ScratchReg); |
michael@0 | 735 | storePtr(src, Address(ScratchReg, 0x0)); |
michael@0 | 736 | } |
michael@0 | 737 | } |
michael@0 | 738 | void store32(const Register &src, const AbsoluteAddress &address) { |
michael@0 | 739 | if (JSC::X86Assembler::isAddressImmediate(address.addr)) { |
michael@0 | 740 | movl(src, Operand(address)); |
michael@0 | 741 | } else { |
michael@0 | 742 | mov(ImmPtr(address.addr), ScratchReg); |
michael@0 | 743 | store32(src, Address(ScratchReg, 0x0)); |
michael@0 | 744 | } |
michael@0 | 745 | } |
michael@0 | 746 | void rshiftPtr(Imm32 imm, Register dest) { |
michael@0 | 747 | shrq(imm, dest); |
michael@0 | 748 | } |
michael@0 | 749 | void lshiftPtr(Imm32 imm, Register dest) { |
michael@0 | 750 | shlq(imm, dest); |
michael@0 | 751 | } |
michael@0 | 752 | void xorPtr(Imm32 imm, Register dest) { |
michael@0 | 753 | xorq(imm, dest); |
michael@0 | 754 | } |
michael@0 | 755 | void xorPtr(Register src, Register dest) { |
michael@0 | 756 | xorq(src, dest); |
michael@0 | 757 | } |
michael@0 | 758 | void orPtr(Imm32 imm, Register dest) { |
michael@0 | 759 | orq(imm, dest); |
michael@0 | 760 | } |
michael@0 | 761 | void orPtr(Register src, Register dest) { |
michael@0 | 762 | orq(src, dest); |
michael@0 | 763 | } |
michael@0 | 764 | void andPtr(Imm32 imm, Register dest) { |
michael@0 | 765 | andq(imm, dest); |
michael@0 | 766 | } |
michael@0 | 767 | void andPtr(Register src, Register dest) { |
michael@0 | 768 | andq(src, dest); |
michael@0 | 769 | } |
michael@0 | 770 | |
michael@0 | 771 | void splitTag(Register src, Register dest) { |
michael@0 | 772 | if (src != dest) |
michael@0 | 773 | movq(src, dest); |
michael@0 | 774 | shrq(Imm32(JSVAL_TAG_SHIFT), dest); |
michael@0 | 775 | } |
michael@0 | 776 | void splitTag(const ValueOperand &operand, const Register &dest) { |
michael@0 | 777 | splitTag(operand.valueReg(), dest); |
michael@0 | 778 | } |
michael@0 | 779 | void splitTag(const Operand &operand, const Register &dest) { |
michael@0 | 780 | movq(operand, dest); |
michael@0 | 781 | shrq(Imm32(JSVAL_TAG_SHIFT), dest); |
michael@0 | 782 | } |
michael@0 | 783 | void splitTag(const Address &operand, const Register &dest) { |
michael@0 | 784 | splitTag(Operand(operand), dest); |
michael@0 | 785 | } |
michael@0 | 786 | void splitTag(const BaseIndex &operand, const Register &dest) { |
michael@0 | 787 | splitTag(Operand(operand), dest); |
michael@0 | 788 | } |
michael@0 | 789 | |
michael@0 | 790 | // Extracts the tag of a value and places it in ScratchReg. |
michael@0 | 791 | Register splitTagForTest(const ValueOperand &value) { |
michael@0 | 792 | splitTag(value, ScratchReg); |
michael@0 | 793 | return ScratchReg; |
michael@0 | 794 | } |
michael@0 | 795 | void cmpTag(const ValueOperand &operand, ImmTag tag) { |
michael@0 | 796 | Register reg = splitTagForTest(operand); |
michael@0 | 797 | cmpl(reg, tag); |
michael@0 | 798 | } |
michael@0 | 799 | |
michael@0 | 800 | void branchTestUndefined(Condition cond, Register tag, Label *label) { |
michael@0 | 801 | cond = testUndefined(cond, tag); |
michael@0 | 802 | j(cond, label); |
michael@0 | 803 | } |
michael@0 | 804 | void branchTestInt32(Condition cond, Register tag, Label *label) { |
michael@0 | 805 | cond = testInt32(cond, tag); |
michael@0 | 806 | j(cond, label); |
michael@0 | 807 | } |
michael@0 | 808 | void branchTestDouble(Condition cond, Register tag, Label *label) { |
michael@0 | 809 | cond = testDouble(cond, tag); |
michael@0 | 810 | j(cond, label); |
michael@0 | 811 | } |
michael@0 | 812 | void branchTestBoolean(Condition cond, Register tag, Label *label) { |
michael@0 | 813 | cond = testBoolean(cond, tag); |
michael@0 | 814 | j(cond, label); |
michael@0 | 815 | } |
michael@0 | 816 | void branchTestNull(Condition cond, Register tag, Label *label) { |
michael@0 | 817 | cond = testNull(cond, tag); |
michael@0 | 818 | j(cond, label); |
michael@0 | 819 | } |
michael@0 | 820 | void branchTestString(Condition cond, Register tag, Label *label) { |
michael@0 | 821 | cond = testString(cond, tag); |
michael@0 | 822 | j(cond, label); |
michael@0 | 823 | } |
michael@0 | 824 | void branchTestObject(Condition cond, Register tag, Label *label) { |
michael@0 | 825 | cond = testObject(cond, tag); |
michael@0 | 826 | j(cond, label); |
michael@0 | 827 | } |
michael@0 | 828 | void branchTestNumber(Condition cond, Register tag, Label *label) { |
michael@0 | 829 | cond = testNumber(cond, tag); |
michael@0 | 830 | j(cond, label); |
michael@0 | 831 | } |
michael@0 | 832 | |
michael@0 | 833 | // x64 can test for certain types directly from memory when the payload |
michael@0 | 834 | // of the type is limited to 32 bits. This avoids loading into a register, |
michael@0 | 835 | // accesses half as much memory, and removes a right-shift. |
michael@0 | 836 | void branchTestUndefined(Condition cond, const Operand &operand, Label *label) { |
michael@0 | 837 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 838 | cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED)))); |
michael@0 | 839 | j(cond, label); |
michael@0 | 840 | } |
michael@0 | 841 | void branchTestUndefined(Condition cond, const Address &address, Label *label) { |
michael@0 | 842 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 843 | branchTestUndefined(cond, Operand(address), label); |
michael@0 | 844 | } |
michael@0 | 845 | void branchTestInt32(Condition cond, const Operand &operand, Label *label) { |
michael@0 | 846 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 847 | cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); |
michael@0 | 848 | j(cond, label); |
michael@0 | 849 | } |
michael@0 | 850 | void branchTestInt32(Condition cond, const Address &address, Label *label) { |
michael@0 | 851 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 852 | branchTestInt32(cond, Operand(address), label); |
michael@0 | 853 | } |
michael@0 | 854 | void branchTestDouble(Condition cond, const Operand &operand, Label *label) { |
michael@0 | 855 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 856 | splitTag(operand, ScratchReg); |
michael@0 | 857 | branchTestDouble(cond, ScratchReg, label); |
michael@0 | 858 | } |
michael@0 | 859 | void branchTestDouble(Condition cond, const Address &address, Label *label) { |
michael@0 | 860 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 861 | branchTestDouble(cond, Operand(address), label); |
michael@0 | 862 | } |
michael@0 | 863 | void branchTestBoolean(Condition cond, const Operand &operand, Label *label) { |
michael@0 | 864 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 865 | cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN)))); |
michael@0 | 866 | j(cond, label); |
michael@0 | 867 | } |
michael@0 | 868 | void branchTestNull(Condition cond, const Operand &operand, Label *label) { |
michael@0 | 869 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 870 | cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL)))); |
michael@0 | 871 | j(cond, label); |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | // Perform a type-test on a full Value loaded into a register. |
michael@0 | 875 | // Clobbers the ScratchReg. |
michael@0 | 876 | void branchTestUndefined(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 877 | cond = testUndefined(cond, src); |
michael@0 | 878 | j(cond, label); |
michael@0 | 879 | } |
michael@0 | 880 | void branchTestInt32(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 881 | splitTag(src, ScratchReg); |
michael@0 | 882 | branchTestInt32(cond, ScratchReg, label); |
michael@0 | 883 | } |
michael@0 | 884 | void branchTestBoolean(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 885 | splitTag(src, ScratchReg); |
michael@0 | 886 | branchTestBoolean(cond, ScratchReg, label); |
michael@0 | 887 | } |
michael@0 | 888 | void branchTestDouble(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 889 | cond = testDouble(cond, src); |
michael@0 | 890 | j(cond, label); |
michael@0 | 891 | } |
michael@0 | 892 | void branchTestNull(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 893 | cond = testNull(cond, src); |
michael@0 | 894 | j(cond, label); |
michael@0 | 895 | } |
michael@0 | 896 | void branchTestString(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 897 | cond = testString(cond, src); |
michael@0 | 898 | j(cond, label); |
michael@0 | 899 | } |
michael@0 | 900 | void branchTestObject(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 901 | cond = testObject(cond, src); |
michael@0 | 902 | j(cond, label); |
michael@0 | 903 | } |
michael@0 | 904 | void branchTestNumber(Condition cond, const ValueOperand &src, Label *label) { |
michael@0 | 905 | cond = testNumber(cond, src); |
michael@0 | 906 | j(cond, label); |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | // Perform a type-test on a Value addressed by BaseIndex. |
michael@0 | 910 | // Clobbers the ScratchReg. |
michael@0 | 911 | void branchTestUndefined(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 912 | cond = testUndefined(cond, address); |
michael@0 | 913 | j(cond, label); |
michael@0 | 914 | } |
michael@0 | 915 | void branchTestInt32(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 916 | splitTag(address, ScratchReg); |
michael@0 | 917 | branchTestInt32(cond, ScratchReg, label); |
michael@0 | 918 | } |
michael@0 | 919 | void branchTestBoolean(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 920 | splitTag(address, ScratchReg); |
michael@0 | 921 | branchTestBoolean(cond, ScratchReg, label); |
michael@0 | 922 | } |
michael@0 | 923 | void branchTestDouble(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 924 | cond = testDouble(cond, address); |
michael@0 | 925 | j(cond, label); |
michael@0 | 926 | } |
michael@0 | 927 | void branchTestNull(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 928 | cond = testNull(cond, address); |
michael@0 | 929 | j(cond, label); |
michael@0 | 930 | } |
michael@0 | 931 | void branchTestString(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 932 | cond = testString(cond, address); |
michael@0 | 933 | j(cond, label); |
michael@0 | 934 | } |
michael@0 | 935 | void branchTestObject(Condition cond, const BaseIndex &address, Label *label) { |
michael@0 | 936 | cond = testObject(cond, address); |
michael@0 | 937 | j(cond, label); |
michael@0 | 938 | } |
michael@0 | 939 | |
michael@0 | 940 | template <typename T> |
michael@0 | 941 | void branchTestGCThing(Condition cond, const T &src, Label *label) { |
michael@0 | 942 | cond = testGCThing(cond, src); |
michael@0 | 943 | j(cond, label); |
michael@0 | 944 | } |
michael@0 | 945 | template <typename T> |
michael@0 | 946 | void branchTestPrimitive(Condition cond, const T &t, Label *label) { |
michael@0 | 947 | cond = testPrimitive(cond, t); |
michael@0 | 948 | j(cond, label); |
michael@0 | 949 | } |
michael@0 | 950 | template <typename T> |
michael@0 | 951 | void branchTestMagic(Condition cond, const T &t, Label *label) { |
michael@0 | 952 | cond = testMagic(cond, t); |
michael@0 | 953 | j(cond, label); |
michael@0 | 954 | } |
michael@0 | 955 | void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, |
michael@0 | 956 | Label *label) |
michael@0 | 957 | { |
michael@0 | 958 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 959 | // Test for magic |
michael@0 | 960 | Label notmagic; |
michael@0 | 961 | Condition testCond = testMagic(cond, val); |
michael@0 | 962 | j(InvertCondition(testCond), ¬magic); |
michael@0 | 963 | // Test magic value |
michael@0 | 964 | unboxMagic(val, ScratchReg); |
michael@0 | 965 | branch32(cond, ScratchReg, Imm32(static_cast<int32_t>(why)), label); |
michael@0 | 966 | bind(¬magic); |
michael@0 | 967 | } |
michael@0 | 968 | Condition testMagic(Condition cond, const ValueOperand &src) { |
michael@0 | 969 | splitTag(src, ScratchReg); |
michael@0 | 970 | return testMagic(cond, ScratchReg); |
michael@0 | 971 | } |
michael@0 | 972 | Condition testError(Condition cond, const ValueOperand &src) { |
michael@0 | 973 | return testMagic(cond, src); |
michael@0 | 974 | } |
michael@0 | 975 | void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label) { |
michael@0 | 976 | JS_ASSERT(value.valueReg() != ScratchReg); |
michael@0 | 977 | moveValue(v, ScratchReg); |
michael@0 | 978 | cmpq(value.valueReg(), ScratchReg); |
michael@0 | 979 | j(cond, label); |
michael@0 | 980 | } |
michael@0 | 981 | void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, |
michael@0 | 982 | Label *label) |
michael@0 | 983 | { |
michael@0 | 984 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 985 | branchPtr(cond, valaddr, value.valueReg(), label); |
michael@0 | 986 | } |
michael@0 | 987 | |
michael@0 | 988 | void testNullSet(Condition cond, const ValueOperand &value, Register dest) { |
michael@0 | 989 | cond = testNull(cond, value); |
michael@0 | 990 | emitSet(cond, dest); |
michael@0 | 991 | } |
michael@0 | 992 | void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) { |
michael@0 | 993 | cond = testUndefined(cond, value); |
michael@0 | 994 | emitSet(cond, dest); |
michael@0 | 995 | } |
michael@0 | 996 | |
michael@0 | 997 | void boxDouble(const FloatRegister &src, const ValueOperand &dest) { |
michael@0 | 998 | movq(src, dest.valueReg()); |
michael@0 | 999 | } |
michael@0 | 1000 | void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest) { |
michael@0 | 1001 | JS_ASSERT(src != dest.valueReg()); |
michael@0 | 1002 | boxValue(type, src, dest.valueReg()); |
michael@0 | 1003 | } |
michael@0 | 1004 | |
michael@0 | 1005 | // Note that the |dest| register here may be ScratchReg, so we shouldn't |
michael@0 | 1006 | // use it. |
michael@0 | 1007 | void unboxInt32(const ValueOperand &src, const Register &dest) { |
michael@0 | 1008 | movl(src.valueReg(), dest); |
michael@0 | 1009 | } |
michael@0 | 1010 | void unboxInt32(const Operand &src, const Register &dest) { |
michael@0 | 1011 | movl(src, dest); |
michael@0 | 1012 | } |
michael@0 | 1013 | void unboxInt32(const Address &src, const Register &dest) { |
michael@0 | 1014 | unboxInt32(Operand(src), dest); |
michael@0 | 1015 | } |
michael@0 | 1016 | void unboxDouble(const Address &src, const FloatRegister &dest) { |
michael@0 | 1017 | loadDouble(Operand(src), dest); |
michael@0 | 1018 | } |
michael@0 | 1019 | |
michael@0 | 1020 | void unboxArgObjMagic(const ValueOperand &src, const Register &dest) { |
michael@0 | 1021 | unboxArgObjMagic(Operand(src.valueReg()), dest); |
michael@0 | 1022 | } |
michael@0 | 1023 | void unboxArgObjMagic(const Operand &src, const Register &dest) { |
michael@0 | 1024 | mov(ImmWord(0), dest); |
michael@0 | 1025 | } |
michael@0 | 1026 | void unboxArgObjMagic(const Address &src, const Register &dest) { |
michael@0 | 1027 | unboxArgObjMagic(Operand(src), dest); |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | void unboxBoolean(const ValueOperand &src, const Register &dest) { |
michael@0 | 1031 | movl(src.valueReg(), dest); |
michael@0 | 1032 | } |
michael@0 | 1033 | void unboxBoolean(const Operand &src, const Register &dest) { |
michael@0 | 1034 | movl(src, dest); |
michael@0 | 1035 | } |
michael@0 | 1036 | void unboxBoolean(const Address &src, const Register &dest) { |
michael@0 | 1037 | unboxBoolean(Operand(src), dest); |
michael@0 | 1038 | } |
michael@0 | 1039 | |
michael@0 | 1040 | void unboxMagic(const ValueOperand &src, const Register &dest) { |
michael@0 | 1041 | movl(src.valueReg(), dest); |
michael@0 | 1042 | } |
michael@0 | 1043 | |
michael@0 | 1044 | void unboxDouble(const ValueOperand &src, const FloatRegister &dest) { |
michael@0 | 1045 | movq(src.valueReg(), dest); |
michael@0 | 1046 | } |
michael@0 | 1047 | void unboxPrivate(const ValueOperand &src, const Register dest) { |
michael@0 | 1048 | movq(src.valueReg(), dest); |
michael@0 | 1049 | shlq(Imm32(1), dest); |
michael@0 | 1050 | } |
michael@0 | 1051 | |
michael@0 | 1052 | void notBoolean(const ValueOperand &val) { |
michael@0 | 1053 | xorq(Imm32(1), val.valueReg()); |
michael@0 | 1054 | } |
michael@0 | 1055 | |
michael@0 | 1056 | // Unbox any non-double value into dest. Prefer unboxInt32 or unboxBoolean |
michael@0 | 1057 | // instead if the source type is known. |
michael@0 | 1058 | void unboxNonDouble(const ValueOperand &src, const Register &dest) { |
michael@0 | 1059 | // In a non-trivial coupling, we're not permitted to use ScratchReg when |
michael@0 | 1060 | // src and dest are different registers, because of how extractObject is |
michael@0 | 1061 | // implemented. |
michael@0 | 1062 | if (src.valueReg() == dest) { |
michael@0 | 1063 | mov(ImmWord(JSVAL_PAYLOAD_MASK), ScratchReg); |
michael@0 | 1064 | andq(ScratchReg, dest); |
michael@0 | 1065 | } else { |
michael@0 | 1066 | mov(ImmWord(JSVAL_PAYLOAD_MASK), dest); |
michael@0 | 1067 | andq(src.valueReg(), dest); |
michael@0 | 1068 | } |
michael@0 | 1069 | } |
michael@0 | 1070 | void unboxNonDouble(const Operand &src, const Register &dest) { |
michael@0 | 1071 | // Explicitly permits |dest| to be used in |src|. |
michael@0 | 1072 | JS_ASSERT(dest != ScratchReg); |
michael@0 | 1073 | mov(ImmWord(JSVAL_PAYLOAD_MASK), ScratchReg); |
michael@0 | 1074 | movq(src, dest); |
michael@0 | 1075 | andq(ScratchReg, dest); |
michael@0 | 1076 | } |
michael@0 | 1077 | |
michael@0 | 1078 | void unboxString(const ValueOperand &src, const Register &dest) { unboxNonDouble(src, dest); } |
michael@0 | 1079 | void unboxString(const Operand &src, const Register &dest) { unboxNonDouble(src, dest); } |
michael@0 | 1080 | |
michael@0 | 1081 | void unboxObject(const ValueOperand &src, const Register &dest) { unboxNonDouble(src, dest); } |
michael@0 | 1082 | void unboxObject(const Operand &src, const Register &dest) { unboxNonDouble(src, dest); } |
michael@0 | 1083 | |
michael@0 | 1084 | // Extended unboxing API. If the payload is already in a register, returns |
michael@0 | 1085 | // that register. Otherwise, provides a move to the given scratch register, |
michael@0 | 1086 | // and returns that. |
michael@0 | 1087 | Register extractObject(const Address &address, Register scratch) { |
michael@0 | 1088 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1089 | loadPtr(address, ScratchReg); |
michael@0 | 1090 | // We have a special coupling with unboxObject. As long as the registers |
michael@0 | 1091 | // aren't equal, it doesn't use ScratchReg. |
michael@0 | 1092 | unboxObject(ValueOperand(ScratchReg), scratch); |
michael@0 | 1093 | return scratch; |
michael@0 | 1094 | } |
michael@0 | 1095 | Register extractObject(const ValueOperand &value, Register scratch) { |
michael@0 | 1096 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1097 | unboxObject(value, scratch); |
michael@0 | 1098 | return scratch; |
michael@0 | 1099 | } |
michael@0 | 1100 | Register extractInt32(const ValueOperand &value, Register scratch) { |
michael@0 | 1101 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1102 | unboxInt32(value, scratch); |
michael@0 | 1103 | return scratch; |
michael@0 | 1104 | } |
michael@0 | 1105 | Register extractBoolean(const ValueOperand &value, Register scratch) { |
michael@0 | 1106 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1107 | unboxBoolean(value, scratch); |
michael@0 | 1108 | return scratch; |
michael@0 | 1109 | } |
michael@0 | 1110 | Register extractTag(const Address &address, Register scratch) { |
michael@0 | 1111 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1112 | loadPtr(address, scratch); |
michael@0 | 1113 | splitTag(scratch, scratch); |
michael@0 | 1114 | return scratch; |
michael@0 | 1115 | } |
michael@0 | 1116 | Register extractTag(const ValueOperand &value, Register scratch) { |
michael@0 | 1117 | JS_ASSERT(scratch != ScratchReg); |
michael@0 | 1118 | splitTag(value, scratch); |
michael@0 | 1119 | return scratch; |
michael@0 | 1120 | } |
michael@0 | 1121 | |
michael@0 | 1122 | void unboxValue(const ValueOperand &src, AnyRegister dest) { |
michael@0 | 1123 | if (dest.isFloat()) { |
michael@0 | 1124 | Label notInt32, end; |
michael@0 | 1125 | branchTestInt32(Assembler::NotEqual, src, ¬Int32); |
michael@0 | 1126 | convertInt32ToDouble(src.valueReg(), dest.fpu()); |
michael@0 | 1127 | jump(&end); |
michael@0 | 1128 | bind(¬Int32); |
michael@0 | 1129 | unboxDouble(src, dest.fpu()); |
michael@0 | 1130 | bind(&end); |
michael@0 | 1131 | } else { |
michael@0 | 1132 | unboxNonDouble(src, dest.gpr()); |
michael@0 | 1133 | } |
michael@0 | 1134 | } |
michael@0 | 1135 | |
michael@0 | 1136 | // These two functions use the low 32-bits of the full value register. |
michael@0 | 1137 | void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 1138 | convertInt32ToDouble(operand.valueReg(), dest); |
michael@0 | 1139 | } |
michael@0 | 1140 | void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 1141 | convertInt32ToDouble(operand.valueReg(), dest); |
michael@0 | 1142 | } |
michael@0 | 1143 | |
michael@0 | 1144 | void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 1145 | convertInt32ToFloat32(operand.valueReg(), dest); |
michael@0 | 1146 | } |
michael@0 | 1147 | void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 1148 | convertInt32ToFloat32(operand.valueReg(), dest); |
michael@0 | 1149 | } |
michael@0 | 1150 | |
michael@0 | 1151 | void loadConstantDouble(double d, const FloatRegister &dest); |
michael@0 | 1152 | void loadConstantFloat32(float f, const FloatRegister &dest); |
michael@0 | 1153 | |
michael@0 | 1154 | void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) { |
michael@0 | 1155 | cvttsd2sq(src, dest); |
michael@0 | 1156 | |
michael@0 | 1157 | // cvttsd2sq returns 0x8000000000000000 on failure. Test for it by |
michael@0 | 1158 | // subtracting 1 and testing overflow (this avoids the need to |
michael@0 | 1159 | // materialize that value in a register). |
michael@0 | 1160 | cmpq(dest, Imm32(1)); |
michael@0 | 1161 | j(Assembler::Overflow, fail); |
michael@0 | 1162 | |
michael@0 | 1163 | movl(dest, dest); // Zero upper 32-bits. |
michael@0 | 1164 | } |
michael@0 | 1165 | void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail) { |
michael@0 | 1166 | cvttss2sq(src, dest); |
michael@0 | 1167 | |
michael@0 | 1168 | // Same trick as for Doubles |
michael@0 | 1169 | cmpq(dest, Imm32(1)); |
michael@0 | 1170 | j(Assembler::Overflow, fail); |
michael@0 | 1171 | |
michael@0 | 1172 | movl(dest, dest); // Zero upper 32-bits. |
michael@0 | 1173 | } |
michael@0 | 1174 | |
michael@0 | 1175 | Condition testInt32Truthy(bool truthy, const ValueOperand &operand) { |
michael@0 | 1176 | testl(operand.valueReg(), operand.valueReg()); |
michael@0 | 1177 | return truthy ? NonZero : Zero; |
michael@0 | 1178 | } |
michael@0 | 1179 | void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) { |
michael@0 | 1180 | Condition cond = testInt32Truthy(truthy, operand); |
michael@0 | 1181 | j(cond, label); |
michael@0 | 1182 | } |
michael@0 | 1183 | void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) { |
michael@0 | 1184 | testl(operand.valueReg(), operand.valueReg()); |
michael@0 | 1185 | j(truthy ? NonZero : Zero, label); |
michael@0 | 1186 | } |
michael@0 | 1187 | Condition testStringTruthy(bool truthy, const ValueOperand &value) { |
michael@0 | 1188 | unboxString(value, ScratchReg); |
michael@0 | 1189 | |
michael@0 | 1190 | Operand lengthAndFlags(ScratchReg, JSString::offsetOfLengthAndFlags()); |
michael@0 | 1191 | testq(lengthAndFlags, Imm32(-1 << JSString::LENGTH_SHIFT)); |
michael@0 | 1192 | return truthy ? Assembler::NonZero : Assembler::Zero; |
michael@0 | 1193 | } |
michael@0 | 1194 | void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) { |
michael@0 | 1195 | Condition cond = testStringTruthy(truthy, value); |
michael@0 | 1196 | j(cond, label); |
michael@0 | 1197 | } |
michael@0 | 1198 | |
michael@0 | 1199 | void loadInt32OrDouble(const Operand &operand, const FloatRegister &dest) { |
michael@0 | 1200 | Label notInt32, end; |
michael@0 | 1201 | branchTestInt32(Assembler::NotEqual, operand, ¬Int32); |
michael@0 | 1202 | convertInt32ToDouble(operand, dest); |
michael@0 | 1203 | jump(&end); |
michael@0 | 1204 | bind(¬Int32); |
michael@0 | 1205 | loadDouble(operand, dest); |
michael@0 | 1206 | bind(&end); |
michael@0 | 1207 | } |
michael@0 | 1208 | |
michael@0 | 1209 | template <typename T> |
michael@0 | 1210 | void loadUnboxedValue(const T &src, MIRType type, AnyRegister dest) { |
michael@0 | 1211 | if (dest.isFloat()) |
michael@0 | 1212 | loadInt32OrDouble(Operand(src), dest.fpu()); |
michael@0 | 1213 | else if (type == MIRType_Int32 || type == MIRType_Boolean) |
michael@0 | 1214 | movl(Operand(src), dest.gpr()); |
michael@0 | 1215 | else |
michael@0 | 1216 | unboxNonDouble(Operand(src), dest.gpr()); |
michael@0 | 1217 | } |
michael@0 | 1218 | |
michael@0 | 1219 | void loadInstructionPointerAfterCall(const Register &dest) { |
michael@0 | 1220 | loadPtr(Address(StackPointer, 0x0), dest); |
michael@0 | 1221 | } |
michael@0 | 1222 | |
michael@0 | 1223 | void convertUInt32ToDouble(const Register &src, const FloatRegister &dest) { |
michael@0 | 1224 | cvtsq2sd(src, dest); |
michael@0 | 1225 | } |
michael@0 | 1226 | |
michael@0 | 1227 | void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest) { |
michael@0 | 1228 | cvtsq2ss(src, dest); |
michael@0 | 1229 | } |
michael@0 | 1230 | |
michael@0 | 1231 | void inc64(AbsoluteAddress dest) { |
michael@0 | 1232 | if (JSC::X86Assembler::isAddressImmediate(dest.addr)) { |
michael@0 | 1233 | addPtr(Imm32(1), Operand(dest)); |
michael@0 | 1234 | } else { |
michael@0 | 1235 | mov(ImmPtr(dest.addr), ScratchReg); |
michael@0 | 1236 | addPtr(Imm32(1), Address(ScratchReg, 0)); |
michael@0 | 1237 | } |
michael@0 | 1238 | } |
michael@0 | 1239 | |
michael@0 | 1240 | // If source is a double, load it into dest. If source is int32, |
michael@0 | 1241 | // convert it to double. Else, branch to failure. |
michael@0 | 1242 | void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) { |
michael@0 | 1243 | Label isDouble, done; |
michael@0 | 1244 | Register tag = splitTagForTest(source); |
michael@0 | 1245 | branchTestDouble(Assembler::Equal, tag, &isDouble); |
michael@0 | 1246 | branchTestInt32(Assembler::NotEqual, tag, failure); |
michael@0 | 1247 | |
michael@0 | 1248 | unboxInt32(source, ScratchReg); |
michael@0 | 1249 | convertInt32ToDouble(ScratchReg, dest); |
michael@0 | 1250 | jump(&done); |
michael@0 | 1251 | |
michael@0 | 1252 | bind(&isDouble); |
michael@0 | 1253 | unboxDouble(source, dest); |
michael@0 | 1254 | |
michael@0 | 1255 | bind(&done); |
michael@0 | 1256 | } |
michael@0 | 1257 | |
michael@0 | 1258 | // Setup a call to C/C++ code, given the number of general arguments it |
michael@0 | 1259 | // takes. Note that this only supports cdecl. |
michael@0 | 1260 | // |
michael@0 | 1261 | // In order for alignment to work correctly, the MacroAssembler must have a |
michael@0 | 1262 | // consistent view of the stack displacement. It is okay to call "push" |
michael@0 | 1263 | // manually, however, if the stack alignment were to change, the macro |
michael@0 | 1264 | // assembler should be notified before starting a call. |
michael@0 | 1265 | void setupAlignedABICall(uint32_t args); |
michael@0 | 1266 | |
michael@0 | 1267 | // Sets up an ABI call for when the alignment is not known. This may need a |
michael@0 | 1268 | // scratch register. |
michael@0 | 1269 | void setupUnalignedABICall(uint32_t args, const Register &scratch); |
michael@0 | 1270 | |
michael@0 | 1271 | // Arguments must be assigned to a C/C++ call in order. They are moved |
michael@0 | 1272 | // in parallel immediately before performing the call. This process may |
michael@0 | 1273 | // temporarily use more stack, in which case esp-relative addresses will be |
michael@0 | 1274 | // automatically adjusted. It is extremely important that esp-relative |
michael@0 | 1275 | // addresses are computed *after* setupABICall(). Furthermore, no |
michael@0 | 1276 | // operations should be emitted while setting arguments. |
michael@0 | 1277 | void passABIArg(const MoveOperand &from, MoveOp::Type type); |
michael@0 | 1278 | void passABIArg(const Register ®); |
michael@0 | 1279 | void passABIArg(const FloatRegister ®, MoveOp::Type type); |
michael@0 | 1280 | |
michael@0 | 1281 | private: |
michael@0 | 1282 | void callWithABIPre(uint32_t *stackAdjust); |
michael@0 | 1283 | void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); |
michael@0 | 1284 | |
michael@0 | 1285 | public: |
michael@0 | 1286 | // Emits a call to a C/C++ function, resolving all argument moves. |
michael@0 | 1287 | void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1288 | void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1289 | void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1290 | |
michael@0 | 1291 | void handleFailureWithHandler(void *handler); |
michael@0 | 1292 | void handleFailureWithHandlerTail(); |
michael@0 | 1293 | |
michael@0 | 1294 | void makeFrameDescriptor(Register frameSizeReg, FrameType type) { |
michael@0 | 1295 | shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg); |
michael@0 | 1296 | orq(Imm32(type), frameSizeReg); |
michael@0 | 1297 | } |
michael@0 | 1298 | |
michael@0 | 1299 | // Save an exit frame (which must be aligned to the stack pointer) to |
michael@0 | 1300 | // ThreadData::ionTop of the main thread. |
michael@0 | 1301 | void linkExitFrame() { |
michael@0 | 1302 | storePtr(StackPointer, |
michael@0 | 1303 | AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop())); |
michael@0 | 1304 | } |
michael@0 | 1305 | |
michael@0 | 1306 | void callWithExitFrame(JitCode *target, Register dynStack) { |
michael@0 | 1307 | addPtr(Imm32(framePushed()), dynStack); |
michael@0 | 1308 | makeFrameDescriptor(dynStack, JitFrame_IonJS); |
michael@0 | 1309 | Push(dynStack); |
michael@0 | 1310 | call(target); |
michael@0 | 1311 | } |
michael@0 | 1312 | |
michael@0 | 1313 | // Save an exit frame to the thread data of the current thread, given a |
michael@0 | 1314 | // register that holds a PerThreadData *. |
michael@0 | 1315 | void linkParallelExitFrame(const Register &pt) { |
michael@0 | 1316 | storePtr(StackPointer, Address(pt, offsetof(PerThreadData, ionTop))); |
michael@0 | 1317 | } |
michael@0 | 1318 | |
michael@0 | 1319 | // See CodeGeneratorX64 calls to noteAsmJSGlobalAccess. |
michael@0 | 1320 | void patchAsmJSGlobalAccess(CodeOffsetLabel patchAt, uint8_t *code, uint8_t *globalData, |
michael@0 | 1321 | unsigned globalDataOffset) |
michael@0 | 1322 | { |
michael@0 | 1323 | uint8_t *nextInsn = code + patchAt.offset(); |
michael@0 | 1324 | JS_ASSERT(nextInsn <= globalData); |
michael@0 | 1325 | uint8_t *target = globalData + globalDataOffset; |
michael@0 | 1326 | ((int32_t *)nextInsn)[-1] = target - nextInsn; |
michael@0 | 1327 | } |
michael@0 | 1328 | void memIntToValue(Address Source, Address Dest) { |
michael@0 | 1329 | load32(Source, ScratchReg); |
michael@0 | 1330 | storeValue(JSVAL_TYPE_INT32, ScratchReg, Dest); |
michael@0 | 1331 | } |
michael@0 | 1332 | |
michael@0 | 1333 | #ifdef JSGC_GENERATIONAL |
michael@0 | 1334 | void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); |
michael@0 | 1335 | void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); |
michael@0 | 1336 | #endif |
michael@0 | 1337 | }; |
michael@0 | 1338 | |
michael@0 | 1339 | typedef MacroAssemblerX64 MacroAssemblerSpecific; |
michael@0 | 1340 | |
michael@0 | 1341 | } // namespace jit |
michael@0 | 1342 | } // namespace js |
michael@0 | 1343 | |
michael@0 | 1344 | #endif /* jit_x64_MacroAssembler_x64_h */ |