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_x86_MacroAssembler_x86_h |
michael@0 | 8 | #define jit_x86_MacroAssembler_x86_h |
michael@0 | 9 | |
michael@0 | 10 | #include "jscompartment.h" |
michael@0 | 11 | |
michael@0 | 12 | #include "jit/IonFrames.h" |
michael@0 | 13 | #include "jit/MoveResolver.h" |
michael@0 | 14 | #include "jit/shared/MacroAssembler-x86-shared.h" |
michael@0 | 15 | |
michael@0 | 16 | namespace js { |
michael@0 | 17 | namespace jit { |
michael@0 | 18 | |
michael@0 | 19 | class MacroAssemblerX86 : public MacroAssemblerX86Shared |
michael@0 | 20 | { |
michael@0 | 21 | // Number of bytes the stack is adjusted inside a call to C. Calls to C may |
michael@0 | 22 | // not be nested. |
michael@0 | 23 | bool inCall_; |
michael@0 | 24 | uint32_t args_; |
michael@0 | 25 | uint32_t passedArgs_; |
michael@0 | 26 | uint32_t stackForCall_; |
michael@0 | 27 | bool dynamicAlignment_; |
michael@0 | 28 | bool enoughMemory_; |
michael@0 | 29 | |
michael@0 | 30 | struct Double { |
michael@0 | 31 | double value; |
michael@0 | 32 | AbsoluteLabel uses; |
michael@0 | 33 | Double(double value) : value(value) {} |
michael@0 | 34 | }; |
michael@0 | 35 | Vector<Double, 0, SystemAllocPolicy> doubles_; |
michael@0 | 36 | struct Float { |
michael@0 | 37 | float value; |
michael@0 | 38 | AbsoluteLabel uses; |
michael@0 | 39 | Float(float value) : value(value) {} |
michael@0 | 40 | }; |
michael@0 | 41 | Vector<Float, 0, SystemAllocPolicy> floats_; |
michael@0 | 42 | |
michael@0 | 43 | typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap; |
michael@0 | 44 | DoubleMap doubleMap_; |
michael@0 | 45 | typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap; |
michael@0 | 46 | FloatMap floatMap_; |
michael@0 | 47 | |
michael@0 | 48 | Double *getDouble(double d); |
michael@0 | 49 | Float *getFloat(float f); |
michael@0 | 50 | |
michael@0 | 51 | protected: |
michael@0 | 52 | MoveResolver moveResolver_; |
michael@0 | 53 | |
michael@0 | 54 | private: |
michael@0 | 55 | Operand payloadOf(const Address &address) { |
michael@0 | 56 | return Operand(address.base, address.offset); |
michael@0 | 57 | } |
michael@0 | 58 | Operand tagOf(const Address &address) { |
michael@0 | 59 | return Operand(address.base, address.offset + 4); |
michael@0 | 60 | } |
michael@0 | 61 | Operand tagOf(const BaseIndex &address) { |
michael@0 | 62 | return Operand(address.base, address.index, address.scale, address.offset + 4); |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | void setupABICall(uint32_t args); |
michael@0 | 66 | |
michael@0 | 67 | public: |
michael@0 | 68 | using MacroAssemblerX86Shared::Push; |
michael@0 | 69 | using MacroAssemblerX86Shared::Pop; |
michael@0 | 70 | using MacroAssemblerX86Shared::callWithExitFrame; |
michael@0 | 71 | using MacroAssemblerX86Shared::branch32; |
michael@0 | 72 | using MacroAssemblerX86Shared::load32; |
michael@0 | 73 | using MacroAssemblerX86Shared::store32; |
michael@0 | 74 | using MacroAssemblerX86Shared::call; |
michael@0 | 75 | |
michael@0 | 76 | MacroAssemblerX86() |
michael@0 | 77 | : inCall_(false), |
michael@0 | 78 | enoughMemory_(true) |
michael@0 | 79 | { |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | // The buffer is about to be linked, make sure any constant pools or excess |
michael@0 | 83 | // bookkeeping has been flushed to the instruction stream. |
michael@0 | 84 | void finish(); |
michael@0 | 85 | |
michael@0 | 86 | bool oom() const { |
michael@0 | 87 | return MacroAssemblerX86Shared::oom() || !enoughMemory_; |
michael@0 | 88 | } |
michael@0 | 89 | |
michael@0 | 90 | ///////////////////////////////////////////////////////////////// |
michael@0 | 91 | // X86-specific interface. |
michael@0 | 92 | ///////////////////////////////////////////////////////////////// |
michael@0 | 93 | |
michael@0 | 94 | Operand ToPayload(Operand base) { |
michael@0 | 95 | return base; |
michael@0 | 96 | } |
michael@0 | 97 | Address ToPayload(Address base) { |
michael@0 | 98 | return base; |
michael@0 | 99 | } |
michael@0 | 100 | Operand ToType(Operand base) { |
michael@0 | 101 | switch (base.kind()) { |
michael@0 | 102 | case Operand::MEM_REG_DISP: |
michael@0 | 103 | return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *)); |
michael@0 | 104 | |
michael@0 | 105 | case Operand::MEM_SCALE: |
michael@0 | 106 | return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), |
michael@0 | 107 | base.scale(), base.disp() + sizeof(void *)); |
michael@0 | 108 | |
michael@0 | 109 | default: |
michael@0 | 110 | MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); |
michael@0 | 111 | } |
michael@0 | 112 | } |
michael@0 | 113 | Address ToType(Address base) { |
michael@0 | 114 | return ToType(Operand(base)).toAddress(); |
michael@0 | 115 | } |
michael@0 | 116 | void moveValue(const Value &val, Register type, Register data) { |
michael@0 | 117 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 118 | movl(Imm32(jv.s.tag), type); |
michael@0 | 119 | if (val.isMarkable()) |
michael@0 | 120 | movl(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())), data); |
michael@0 | 121 | else |
michael@0 | 122 | movl(Imm32(jv.s.payload.i32), data); |
michael@0 | 123 | } |
michael@0 | 124 | void moveValue(const Value &val, const ValueOperand &dest) { |
michael@0 | 125 | moveValue(val, dest.typeReg(), dest.payloadReg()); |
michael@0 | 126 | } |
michael@0 | 127 | void moveValue(const ValueOperand &src, const ValueOperand &dest) { |
michael@0 | 128 | Register s0 = src.typeReg(), d0 = dest.typeReg(), |
michael@0 | 129 | s1 = src.payloadReg(), d1 = dest.payloadReg(); |
michael@0 | 130 | |
michael@0 | 131 | // Either one or both of the source registers could be the same as a |
michael@0 | 132 | // destination register. |
michael@0 | 133 | if (s1 == d0) { |
michael@0 | 134 | if (s0 == d1) { |
michael@0 | 135 | // If both are, this is just a swap of two registers. |
michael@0 | 136 | xchgl(d0, d1); |
michael@0 | 137 | return; |
michael@0 | 138 | } |
michael@0 | 139 | // If only one is, copy that source first. |
michael@0 | 140 | mozilla::Swap(s0, s1); |
michael@0 | 141 | mozilla::Swap(d0, d1); |
michael@0 | 142 | } |
michael@0 | 143 | |
michael@0 | 144 | if (s0 != d0) |
michael@0 | 145 | movl(s0, d0); |
michael@0 | 146 | if (s1 != d1) |
michael@0 | 147 | movl(s1, d1); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | ///////////////////////////////////////////////////////////////// |
michael@0 | 151 | // X86/X64-common interface. |
michael@0 | 152 | ///////////////////////////////////////////////////////////////// |
michael@0 | 153 | void storeValue(ValueOperand val, Operand dest) { |
michael@0 | 154 | movl(val.payloadReg(), ToPayload(dest)); |
michael@0 | 155 | movl(val.typeReg(), ToType(dest)); |
michael@0 | 156 | } |
michael@0 | 157 | void storeValue(ValueOperand val, const Address &dest) { |
michael@0 | 158 | storeValue(val, Operand(dest)); |
michael@0 | 159 | } |
michael@0 | 160 | template <typename T> |
michael@0 | 161 | void storeValue(JSValueType type, Register reg, const T &dest) { |
michael@0 | 162 | storeTypeTag(ImmTag(JSVAL_TYPE_TO_TAG(type)), Operand(dest)); |
michael@0 | 163 | storePayload(reg, Operand(dest)); |
michael@0 | 164 | } |
michael@0 | 165 | template <typename T> |
michael@0 | 166 | void storeValue(const Value &val, const T &dest) { |
michael@0 | 167 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 168 | storeTypeTag(ImmTag(jv.s.tag), Operand(dest)); |
michael@0 | 169 | storePayload(val, Operand(dest)); |
michael@0 | 170 | } |
michael@0 | 171 | void storeValue(ValueOperand val, BaseIndex dest) { |
michael@0 | 172 | storeValue(val, Operand(dest)); |
michael@0 | 173 | } |
michael@0 | 174 | void loadValue(Operand src, ValueOperand val) { |
michael@0 | 175 | Operand payload = ToPayload(src); |
michael@0 | 176 | Operand type = ToType(src); |
michael@0 | 177 | |
michael@0 | 178 | // Ensure that loading the payload does not erase the pointer to the |
michael@0 | 179 | // Value in memory or the index. |
michael@0 | 180 | Register baseReg = Register::FromCode(src.base()); |
michael@0 | 181 | Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg; |
michael@0 | 182 | |
michael@0 | 183 | if (baseReg == val.payloadReg() || indexReg == val.payloadReg()) { |
michael@0 | 184 | JS_ASSERT(baseReg != val.typeReg()); |
michael@0 | 185 | JS_ASSERT(indexReg != val.typeReg()); |
michael@0 | 186 | |
michael@0 | 187 | movl(type, val.typeReg()); |
michael@0 | 188 | movl(payload, val.payloadReg()); |
michael@0 | 189 | } else { |
michael@0 | 190 | JS_ASSERT(baseReg != val.payloadReg()); |
michael@0 | 191 | JS_ASSERT(indexReg != val.payloadReg()); |
michael@0 | 192 | |
michael@0 | 193 | movl(payload, val.payloadReg()); |
michael@0 | 194 | movl(type, val.typeReg()); |
michael@0 | 195 | } |
michael@0 | 196 | } |
michael@0 | 197 | void loadValue(Address src, ValueOperand val) { |
michael@0 | 198 | loadValue(Operand(src), val); |
michael@0 | 199 | } |
michael@0 | 200 | void loadValue(const BaseIndex &src, ValueOperand val) { |
michael@0 | 201 | loadValue(Operand(src), val); |
michael@0 | 202 | } |
michael@0 | 203 | void tagValue(JSValueType type, Register payload, ValueOperand dest) { |
michael@0 | 204 | JS_ASSERT(dest.typeReg() != dest.payloadReg()); |
michael@0 | 205 | if (payload != dest.payloadReg()) |
michael@0 | 206 | movl(payload, dest.payloadReg()); |
michael@0 | 207 | movl(ImmType(type), dest.typeReg()); |
michael@0 | 208 | } |
michael@0 | 209 | void pushValue(ValueOperand val) { |
michael@0 | 210 | push(val.typeReg()); |
michael@0 | 211 | push(val.payloadReg()); |
michael@0 | 212 | } |
michael@0 | 213 | void popValue(ValueOperand val) { |
michael@0 | 214 | pop(val.payloadReg()); |
michael@0 | 215 | pop(val.typeReg()); |
michael@0 | 216 | } |
michael@0 | 217 | void pushValue(const Value &val) { |
michael@0 | 218 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 219 | push(Imm32(jv.s.tag)); |
michael@0 | 220 | if (val.isMarkable()) |
michael@0 | 221 | push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing()))); |
michael@0 | 222 | else |
michael@0 | 223 | push(Imm32(jv.s.payload.i32)); |
michael@0 | 224 | } |
michael@0 | 225 | void pushValue(JSValueType type, Register reg) { |
michael@0 | 226 | push(ImmTag(JSVAL_TYPE_TO_TAG(type))); |
michael@0 | 227 | push(reg); |
michael@0 | 228 | } |
michael@0 | 229 | void pushValue(const Address &addr) { |
michael@0 | 230 | push(tagOf(addr)); |
michael@0 | 231 | push(payloadOf(addr)); |
michael@0 | 232 | } |
michael@0 | 233 | void Push(const ValueOperand &val) { |
michael@0 | 234 | pushValue(val); |
michael@0 | 235 | framePushed_ += sizeof(Value); |
michael@0 | 236 | } |
michael@0 | 237 | void Pop(const ValueOperand &val) { |
michael@0 | 238 | popValue(val); |
michael@0 | 239 | framePushed_ -= sizeof(Value); |
michael@0 | 240 | } |
michael@0 | 241 | void storePayload(const Value &val, Operand dest) { |
michael@0 | 242 | jsval_layout jv = JSVAL_TO_IMPL(val); |
michael@0 | 243 | if (val.isMarkable()) |
michael@0 | 244 | movl(ImmGCPtr((gc::Cell *)jv.s.payload.ptr), ToPayload(dest)); |
michael@0 | 245 | else |
michael@0 | 246 | movl(Imm32(jv.s.payload.i32), ToPayload(dest)); |
michael@0 | 247 | } |
michael@0 | 248 | void storePayload(Register src, Operand dest) { |
michael@0 | 249 | movl(src, ToPayload(dest)); |
michael@0 | 250 | } |
michael@0 | 251 | void storeTypeTag(ImmTag tag, Operand dest) { |
michael@0 | 252 | movl(tag, ToType(dest)); |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | void movePtr(const Register &src, const Register &dest) { |
michael@0 | 256 | movl(src, dest); |
michael@0 | 257 | } |
michael@0 | 258 | void movePtr(const Register &src, const Operand &dest) { |
michael@0 | 259 | movl(src, dest); |
michael@0 | 260 | } |
michael@0 | 261 | |
michael@0 | 262 | // Returns the register containing the type tag. |
michael@0 | 263 | Register splitTagForTest(const ValueOperand &value) { |
michael@0 | 264 | return value.typeReg(); |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | Condition testUndefined(Condition cond, const Register &tag) { |
michael@0 | 268 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 269 | cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED)); |
michael@0 | 270 | return cond; |
michael@0 | 271 | } |
michael@0 | 272 | Condition testBoolean(Condition cond, const Register &tag) { |
michael@0 | 273 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 274 | cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN)); |
michael@0 | 275 | return cond; |
michael@0 | 276 | } |
michael@0 | 277 | Condition testInt32(Condition cond, const Register &tag) { |
michael@0 | 278 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 279 | cmpl(tag, ImmTag(JSVAL_TAG_INT32)); |
michael@0 | 280 | return cond; |
michael@0 | 281 | } |
michael@0 | 282 | Condition testDouble(Condition cond, const Register &tag) { |
michael@0 | 283 | JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); |
michael@0 | 284 | Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
michael@0 | 285 | cmpl(tag, ImmTag(JSVAL_TAG_CLEAR)); |
michael@0 | 286 | return actual; |
michael@0 | 287 | } |
michael@0 | 288 | Condition testNull(Condition cond, const Register &tag) { |
michael@0 | 289 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 290 | cmpl(tag, ImmTag(JSVAL_TAG_NULL)); |
michael@0 | 291 | return cond; |
michael@0 | 292 | } |
michael@0 | 293 | Condition testString(Condition cond, const Register &tag) { |
michael@0 | 294 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 295 | cmpl(tag, ImmTag(JSVAL_TAG_STRING)); |
michael@0 | 296 | return cond; |
michael@0 | 297 | } |
michael@0 | 298 | Condition testObject(Condition cond, const Register &tag) { |
michael@0 | 299 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 300 | cmpl(tag, ImmTag(JSVAL_TAG_OBJECT)); |
michael@0 | 301 | return cond; |
michael@0 | 302 | } |
michael@0 | 303 | Condition testNumber(Condition cond, const Register &tag) { |
michael@0 | 304 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 305 | cmpl(tag, ImmTag(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); |
michael@0 | 306 | return cond == Equal ? BelowOrEqual : Above; |
michael@0 | 307 | } |
michael@0 | 308 | Condition testGCThing(Condition cond, const Register &tag) { |
michael@0 | 309 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 310 | cmpl(tag, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
michael@0 | 311 | return cond == Equal ? AboveOrEqual : Below; |
michael@0 | 312 | } |
michael@0 | 313 | Condition testGCThing(Condition cond, const Address &address) { |
michael@0 | 314 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 315 | cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
michael@0 | 316 | return cond == Equal ? AboveOrEqual : Below; |
michael@0 | 317 | } |
michael@0 | 318 | Condition testMagic(Condition cond, const Address &address) { |
michael@0 | 319 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 320 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); |
michael@0 | 321 | return cond; |
michael@0 | 322 | } |
michael@0 | 323 | Condition testMagic(Condition cond, const Register &tag) { |
michael@0 | 324 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 325 | cmpl(tag, ImmTag(JSVAL_TAG_MAGIC)); |
michael@0 | 326 | return cond; |
michael@0 | 327 | } |
michael@0 | 328 | Condition testMagic(Condition cond, const Operand &operand) { |
michael@0 | 329 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 330 | cmpl(ToType(operand), ImmTag(JSVAL_TAG_MAGIC)); |
michael@0 | 331 | return cond; |
michael@0 | 332 | } |
michael@0 | 333 | Condition testPrimitive(Condition cond, const Register &tag) { |
michael@0 | 334 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 335 | cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); |
michael@0 | 336 | return cond == Equal ? Below : AboveOrEqual; |
michael@0 | 337 | } |
michael@0 | 338 | Condition testError(Condition cond, const Register &tag) { |
michael@0 | 339 | return testMagic(cond, tag); |
michael@0 | 340 | } |
michael@0 | 341 | Condition testInt32(Condition cond, const Operand &operand) { |
michael@0 | 342 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 343 | cmpl(ToType(operand), ImmTag(JSVAL_TAG_INT32)); |
michael@0 | 344 | return cond; |
michael@0 | 345 | } |
michael@0 | 346 | Condition testInt32(Condition cond, const Address &address) { |
michael@0 | 347 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 348 | return testInt32(cond, Operand(address)); |
michael@0 | 349 | } |
michael@0 | 350 | Condition testDouble(Condition cond, const Operand &operand) { |
michael@0 | 351 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 352 | Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
michael@0 | 353 | cmpl(ToType(operand), ImmTag(JSVAL_TAG_CLEAR)); |
michael@0 | 354 | return actual; |
michael@0 | 355 | } |
michael@0 | 356 | Condition testDouble(Condition cond, const Address &address) { |
michael@0 | 357 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 358 | return testDouble(cond, Operand(address)); |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | |
michael@0 | 362 | Condition testUndefined(Condition cond, const Operand &operand) { |
michael@0 | 363 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 364 | cmpl(ToType(operand), ImmTag(JSVAL_TAG_UNDEFINED)); |
michael@0 | 365 | return cond; |
michael@0 | 366 | } |
michael@0 | 367 | Condition testUndefined(Condition cond, const Address &addr) { |
michael@0 | 368 | return testUndefined(cond, Operand(addr)); |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | |
michael@0 | 372 | Condition testUndefined(Condition cond, const ValueOperand &value) { |
michael@0 | 373 | return testUndefined(cond, value.typeReg()); |
michael@0 | 374 | } |
michael@0 | 375 | Condition testBoolean(Condition cond, const ValueOperand &value) { |
michael@0 | 376 | return testBoolean(cond, value.typeReg()); |
michael@0 | 377 | } |
michael@0 | 378 | Condition testInt32(Condition cond, const ValueOperand &value) { |
michael@0 | 379 | return testInt32(cond, value.typeReg()); |
michael@0 | 380 | } |
michael@0 | 381 | Condition testDouble(Condition cond, const ValueOperand &value) { |
michael@0 | 382 | return testDouble(cond, value.typeReg()); |
michael@0 | 383 | } |
michael@0 | 384 | Condition testNull(Condition cond, const ValueOperand &value) { |
michael@0 | 385 | return testNull(cond, value.typeReg()); |
michael@0 | 386 | } |
michael@0 | 387 | Condition testString(Condition cond, const ValueOperand &value) { |
michael@0 | 388 | return testString(cond, value.typeReg()); |
michael@0 | 389 | } |
michael@0 | 390 | Condition testObject(Condition cond, const ValueOperand &value) { |
michael@0 | 391 | return testObject(cond, value.typeReg()); |
michael@0 | 392 | } |
michael@0 | 393 | Condition testMagic(Condition cond, const ValueOperand &value) { |
michael@0 | 394 | return testMagic(cond, value.typeReg()); |
michael@0 | 395 | } |
michael@0 | 396 | Condition testError(Condition cond, const ValueOperand &value) { |
michael@0 | 397 | return testMagic(cond, value); |
michael@0 | 398 | } |
michael@0 | 399 | Condition testNumber(Condition cond, const ValueOperand &value) { |
michael@0 | 400 | return testNumber(cond, value.typeReg()); |
michael@0 | 401 | } |
michael@0 | 402 | Condition testGCThing(Condition cond, const ValueOperand &value) { |
michael@0 | 403 | return testGCThing(cond, value.typeReg()); |
michael@0 | 404 | } |
michael@0 | 405 | Condition testPrimitive(Condition cond, const ValueOperand &value) { |
michael@0 | 406 | return testPrimitive(cond, value.typeReg()); |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | |
michael@0 | 410 | Condition testUndefined(Condition cond, const BaseIndex &address) { |
michael@0 | 411 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 412 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED)); |
michael@0 | 413 | return cond; |
michael@0 | 414 | } |
michael@0 | 415 | Condition testNull(Condition cond, const BaseIndex &address) { |
michael@0 | 416 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 417 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_NULL)); |
michael@0 | 418 | return cond; |
michael@0 | 419 | } |
michael@0 | 420 | Condition testBoolean(Condition cond, const BaseIndex &address) { |
michael@0 | 421 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 422 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN)); |
michael@0 | 423 | return cond; |
michael@0 | 424 | } |
michael@0 | 425 | Condition testString(Condition cond, const BaseIndex &address) { |
michael@0 | 426 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 427 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_STRING)); |
michael@0 | 428 | return cond; |
michael@0 | 429 | } |
michael@0 | 430 | Condition testInt32(Condition cond, const BaseIndex &address) { |
michael@0 | 431 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 432 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_INT32)); |
michael@0 | 433 | return cond; |
michael@0 | 434 | } |
michael@0 | 435 | Condition testObject(Condition cond, const BaseIndex &address) { |
michael@0 | 436 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 437 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_OBJECT)); |
michael@0 | 438 | return cond; |
michael@0 | 439 | } |
michael@0 | 440 | Condition testDouble(Condition cond, const BaseIndex &address) { |
michael@0 | 441 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 442 | Condition actual = (cond == Equal) ? Below : AboveOrEqual; |
michael@0 | 443 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_CLEAR)); |
michael@0 | 444 | return actual; |
michael@0 | 445 | } |
michael@0 | 446 | Condition testMagic(Condition cond, const BaseIndex &address) { |
michael@0 | 447 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 448 | cmpl(tagOf(address), ImmTag(JSVAL_TAG_MAGIC)); |
michael@0 | 449 | return cond; |
michael@0 | 450 | } |
michael@0 | 451 | Condition testGCThing(Condition cond, const BaseIndex &address) { |
michael@0 | 452 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 453 | cmpl(tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); |
michael@0 | 454 | return cond == Equal ? AboveOrEqual : Below; |
michael@0 | 455 | } |
michael@0 | 456 | |
michael@0 | 457 | |
michael@0 | 458 | |
michael@0 | 459 | void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label); |
michael@0 | 460 | void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, |
michael@0 | 461 | Label *label) |
michael@0 | 462 | { |
michael@0 | 463 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 464 | // Check payload before tag, since payload is more likely to differ. |
michael@0 | 465 | if (cond == NotEqual) { |
michael@0 | 466 | branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), label); |
michael@0 | 467 | branchPtr(NotEqual, tagOf(valaddr), value.typeReg(), label); |
michael@0 | 468 | |
michael@0 | 469 | } else { |
michael@0 | 470 | Label fallthrough; |
michael@0 | 471 | branchPtr(NotEqual, payloadOf(valaddr), value.payloadReg(), &fallthrough); |
michael@0 | 472 | branchPtr(Equal, tagOf(valaddr), value.typeReg(), label); |
michael@0 | 473 | bind(&fallthrough); |
michael@0 | 474 | } |
michael@0 | 475 | } |
michael@0 | 476 | |
michael@0 | 477 | void testNullSet(Condition cond, const ValueOperand &value, Register dest) { |
michael@0 | 478 | cond = testNull(cond, value); |
michael@0 | 479 | emitSet(cond, dest); |
michael@0 | 480 | } |
michael@0 | 481 | void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) { |
michael@0 | 482 | cond = testUndefined(cond, value); |
michael@0 | 483 | emitSet(cond, dest); |
michael@0 | 484 | } |
michael@0 | 485 | |
michael@0 | 486 | void cmpPtr(Register lhs, const ImmWord rhs) { |
michael@0 | 487 | cmpl(lhs, Imm32(rhs.value)); |
michael@0 | 488 | } |
michael@0 | 489 | void cmpPtr(Register lhs, const ImmPtr imm) { |
michael@0 | 490 | cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); |
michael@0 | 491 | } |
michael@0 | 492 | void cmpPtr(Register lhs, const ImmGCPtr rhs) { |
michael@0 | 493 | cmpl(lhs, rhs); |
michael@0 | 494 | } |
michael@0 | 495 | void cmpPtr(Register lhs, const Imm32 rhs) { |
michael@0 | 496 | cmpl(lhs, rhs); |
michael@0 | 497 | } |
michael@0 | 498 | void cmpPtr(const Operand &lhs, const ImmWord rhs) { |
michael@0 | 499 | cmpl(lhs, rhs); |
michael@0 | 500 | } |
michael@0 | 501 | void cmpPtr(const Operand &lhs, const ImmPtr imm) { |
michael@0 | 502 | cmpPtr(lhs, ImmWord(uintptr_t(imm.value))); |
michael@0 | 503 | } |
michael@0 | 504 | void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) { |
michael@0 | 505 | cmpl(lhs, rhs); |
michael@0 | 506 | } |
michael@0 | 507 | void cmpPtr(const Operand &lhs, const Imm32 rhs) { |
michael@0 | 508 | cmpl(lhs, rhs); |
michael@0 | 509 | } |
michael@0 | 510 | void cmpPtr(const Address &lhs, Register rhs) { |
michael@0 | 511 | cmpl(Operand(lhs), rhs); |
michael@0 | 512 | } |
michael@0 | 513 | void cmpPtr(const Address &lhs, const ImmWord rhs) { |
michael@0 | 514 | cmpl(Operand(lhs), rhs); |
michael@0 | 515 | } |
michael@0 | 516 | void cmpPtr(const Address &lhs, const ImmPtr rhs) { |
michael@0 | 517 | cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); |
michael@0 | 518 | } |
michael@0 | 519 | void cmpPtr(Register lhs, Register rhs) { |
michael@0 | 520 | cmpl(lhs, rhs); |
michael@0 | 521 | } |
michael@0 | 522 | void testPtr(Register lhs, Register rhs) { |
michael@0 | 523 | testl(lhs, rhs); |
michael@0 | 524 | } |
michael@0 | 525 | |
michael@0 | 526 | template <typename T1, typename T2> |
michael@0 | 527 | void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest) |
michael@0 | 528 | { |
michael@0 | 529 | cmpPtr(lhs, rhs); |
michael@0 | 530 | emitSet(cond, dest); |
michael@0 | 531 | } |
michael@0 | 532 | |
michael@0 | 533 | ///////////////////////////////////////////////////////////////// |
michael@0 | 534 | // Common interface. |
michael@0 | 535 | ///////////////////////////////////////////////////////////////// |
michael@0 | 536 | void reserveStack(uint32_t amount) { |
michael@0 | 537 | if (amount) |
michael@0 | 538 | subl(Imm32(amount), StackPointer); |
michael@0 | 539 | framePushed_ += amount; |
michael@0 | 540 | } |
michael@0 | 541 | void freeStack(uint32_t amount) { |
michael@0 | 542 | JS_ASSERT(amount <= framePushed_); |
michael@0 | 543 | if (amount) |
michael@0 | 544 | addl(Imm32(amount), StackPointer); |
michael@0 | 545 | framePushed_ -= amount; |
michael@0 | 546 | } |
michael@0 | 547 | void freeStack(Register amount) { |
michael@0 | 548 | addl(amount, StackPointer); |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | void addPtr(const Register &src, const Register &dest) { |
michael@0 | 552 | addl(src, dest); |
michael@0 | 553 | } |
michael@0 | 554 | void addPtr(Imm32 imm, const Register &dest) { |
michael@0 | 555 | addl(imm, dest); |
michael@0 | 556 | } |
michael@0 | 557 | void addPtr(ImmWord imm, const Register &dest) { |
michael@0 | 558 | addl(Imm32(imm.value), dest); |
michael@0 | 559 | } |
michael@0 | 560 | void addPtr(ImmPtr imm, const Register &dest) { |
michael@0 | 561 | addPtr(ImmWord(uintptr_t(imm.value)), dest); |
michael@0 | 562 | } |
michael@0 | 563 | void addPtr(Imm32 imm, const Address &dest) { |
michael@0 | 564 | addl(imm, Operand(dest)); |
michael@0 | 565 | } |
michael@0 | 566 | void addPtr(Imm32 imm, const Operand &dest) { |
michael@0 | 567 | addl(imm, dest); |
michael@0 | 568 | } |
michael@0 | 569 | void addPtr(const Address &src, const Register &dest) { |
michael@0 | 570 | addl(Operand(src), dest); |
michael@0 | 571 | } |
michael@0 | 572 | void subPtr(Imm32 imm, const Register &dest) { |
michael@0 | 573 | subl(imm, dest); |
michael@0 | 574 | } |
michael@0 | 575 | void subPtr(const Register &src, const Register &dest) { |
michael@0 | 576 | subl(src, dest); |
michael@0 | 577 | } |
michael@0 | 578 | void subPtr(const Address &addr, const Register &dest) { |
michael@0 | 579 | subl(Operand(addr), dest); |
michael@0 | 580 | } |
michael@0 | 581 | void subPtr(const Register &src, const Address &dest) { |
michael@0 | 582 | subl(src, Operand(dest)); |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { |
michael@0 | 586 | cmpl(Operand(lhs), rhs); |
michael@0 | 587 | j(cond, label); |
michael@0 | 588 | } |
michael@0 | 589 | void branch32(Condition cond, const AbsoluteAddress &lhs, Register rhs, Label *label) { |
michael@0 | 590 | cmpl(Operand(lhs), rhs); |
michael@0 | 591 | j(cond, label); |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | // Specialization for AsmJSAbsoluteAddress. |
michael@0 | 595 | void branchPtr(Condition cond, AsmJSAbsoluteAddress lhs, Register ptr, Label *label) { |
michael@0 | 596 | cmpl(lhs, ptr); |
michael@0 | 597 | j(cond, label); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | template <typename T, typename S> |
michael@0 | 601 | void branchPtr(Condition cond, T lhs, S ptr, Label *label) { |
michael@0 | 602 | cmpl(Operand(lhs), ptr); |
michael@0 | 603 | j(cond, label); |
michael@0 | 604 | } |
michael@0 | 605 | |
michael@0 | 606 | void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) { |
michael@0 | 607 | branchPtr(cond, lhs, ptr, label); |
michael@0 | 608 | } |
michael@0 | 609 | |
michael@0 | 610 | void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) { |
michael@0 | 611 | branchPtr(cond, lhs, ptr, label); |
michael@0 | 612 | } |
michael@0 | 613 | |
michael@0 | 614 | template <typename T, typename S> |
michael@0 | 615 | void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel *label) { |
michael@0 | 616 | cmpl(Operand(lhs), ptr); |
michael@0 | 617 | j(cond, label); |
michael@0 | 618 | } |
michael@0 | 619 | |
michael@0 | 620 | CodeOffsetJump jumpWithPatch(RepatchLabel *label) { |
michael@0 | 621 | jump(label); |
michael@0 | 622 | return CodeOffsetJump(size()); |
michael@0 | 623 | } |
michael@0 | 624 | |
michael@0 | 625 | CodeOffsetJump jumpWithPatch(RepatchLabel *label, Assembler::Condition cond) { |
michael@0 | 626 | j(cond, label); |
michael@0 | 627 | return CodeOffsetJump(size()); |
michael@0 | 628 | } |
michael@0 | 629 | |
michael@0 | 630 | template <typename S, typename T> |
michael@0 | 631 | CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel *label) { |
michael@0 | 632 | branchPtr(cond, lhs, ptr, label); |
michael@0 | 633 | return CodeOffsetJump(size()); |
michael@0 | 634 | } |
michael@0 | 635 | void branchPtr(Condition cond, Register lhs, Register rhs, RepatchLabel *label) { |
michael@0 | 636 | cmpl(lhs, rhs); |
michael@0 | 637 | j(cond, label); |
michael@0 | 638 | } |
michael@0 | 639 | void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
michael@0 | 640 | cmpl(lhs, rhs); |
michael@0 | 641 | j(cond, label); |
michael@0 | 642 | } |
michael@0 | 643 | void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) { |
michael@0 | 644 | testl(lhs, rhs); |
michael@0 | 645 | j(cond, label); |
michael@0 | 646 | } |
michael@0 | 647 | void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { |
michael@0 | 648 | testl(lhs, imm); |
michael@0 | 649 | j(cond, label); |
michael@0 | 650 | } |
michael@0 | 651 | void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { |
michael@0 | 652 | testl(Operand(lhs), imm); |
michael@0 | 653 | j(cond, label); |
michael@0 | 654 | } |
michael@0 | 655 | void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { |
michael@0 | 656 | subPtr(imm, lhs); |
michael@0 | 657 | j(cond, label); |
michael@0 | 658 | } |
michael@0 | 659 | |
michael@0 | 660 | void movePtr(ImmWord imm, Register dest) { |
michael@0 | 661 | movl(Imm32(imm.value), dest); |
michael@0 | 662 | } |
michael@0 | 663 | void movePtr(ImmPtr imm, Register dest) { |
michael@0 | 664 | movl(imm, dest); |
michael@0 | 665 | } |
michael@0 | 666 | void movePtr(AsmJSImmPtr imm, Register dest) { |
michael@0 | 667 | mov(imm, dest); |
michael@0 | 668 | } |
michael@0 | 669 | void movePtr(ImmGCPtr imm, Register dest) { |
michael@0 | 670 | movl(imm, dest); |
michael@0 | 671 | } |
michael@0 | 672 | void loadPtr(const Address &address, Register dest) { |
michael@0 | 673 | movl(Operand(address), dest); |
michael@0 | 674 | } |
michael@0 | 675 | void loadPtr(const Operand &src, Register dest) { |
michael@0 | 676 | movl(src, dest); |
michael@0 | 677 | } |
michael@0 | 678 | void loadPtr(const BaseIndex &src, Register dest) { |
michael@0 | 679 | movl(Operand(src), dest); |
michael@0 | 680 | } |
michael@0 | 681 | void loadPtr(const AbsoluteAddress &address, Register dest) { |
michael@0 | 682 | movl(Operand(address), dest); |
michael@0 | 683 | } |
michael@0 | 684 | void loadPrivate(const Address &src, Register dest) { |
michael@0 | 685 | movl(payloadOf(src), dest); |
michael@0 | 686 | } |
michael@0 | 687 | void load32(const AbsoluteAddress &address, Register dest) { |
michael@0 | 688 | movl(Operand(address), dest); |
michael@0 | 689 | } |
michael@0 | 690 | void storePtr(ImmWord imm, const Address &address) { |
michael@0 | 691 | movl(Imm32(imm.value), Operand(address)); |
michael@0 | 692 | } |
michael@0 | 693 | void storePtr(ImmPtr imm, const Address &address) { |
michael@0 | 694 | storePtr(ImmWord(uintptr_t(imm.value)), address); |
michael@0 | 695 | } |
michael@0 | 696 | void storePtr(ImmGCPtr imm, const Address &address) { |
michael@0 | 697 | movl(imm, Operand(address)); |
michael@0 | 698 | } |
michael@0 | 699 | void storePtr(Register src, const Address &address) { |
michael@0 | 700 | movl(src, Operand(address)); |
michael@0 | 701 | } |
michael@0 | 702 | void storePtr(Register src, const Operand &dest) { |
michael@0 | 703 | movl(src, dest); |
michael@0 | 704 | } |
michael@0 | 705 | void storePtr(Register src, const AbsoluteAddress &address) { |
michael@0 | 706 | movl(src, Operand(address)); |
michael@0 | 707 | } |
michael@0 | 708 | void store32(Register src, const AbsoluteAddress &address) { |
michael@0 | 709 | movl(src, Operand(address)); |
michael@0 | 710 | } |
michael@0 | 711 | |
michael@0 | 712 | void setStackArg(const Register ®, uint32_t arg) { |
michael@0 | 713 | movl(reg, Operand(esp, arg * sizeof(intptr_t))); |
michael@0 | 714 | } |
michael@0 | 715 | |
michael@0 | 716 | // Type testing instructions can take a tag in a register or a |
michael@0 | 717 | // ValueOperand. |
michael@0 | 718 | template <typename T> |
michael@0 | 719 | void branchTestUndefined(Condition cond, const T &t, Label *label) { |
michael@0 | 720 | cond = testUndefined(cond, t); |
michael@0 | 721 | j(cond, label); |
michael@0 | 722 | } |
michael@0 | 723 | template <typename T> |
michael@0 | 724 | void branchTestInt32(Condition cond, const T &t, Label *label) { |
michael@0 | 725 | cond = testInt32(cond, t); |
michael@0 | 726 | j(cond, label); |
michael@0 | 727 | } |
michael@0 | 728 | template <typename T> |
michael@0 | 729 | void branchTestBoolean(Condition cond, const T &t, Label *label) { |
michael@0 | 730 | cond = testBoolean(cond, t); |
michael@0 | 731 | j(cond, label); |
michael@0 | 732 | } |
michael@0 | 733 | template <typename T> |
michael@0 | 734 | void branchTestDouble(Condition cond, const T &t, Label *label) { |
michael@0 | 735 | cond = testDouble(cond, t); |
michael@0 | 736 | j(cond, label); |
michael@0 | 737 | } |
michael@0 | 738 | template <typename T> |
michael@0 | 739 | void branchTestNull(Condition cond, const T &t, Label *label) { |
michael@0 | 740 | cond = testNull(cond, t); |
michael@0 | 741 | j(cond, label); |
michael@0 | 742 | } |
michael@0 | 743 | template <typename T> |
michael@0 | 744 | void branchTestString(Condition cond, const T &t, Label *label) { |
michael@0 | 745 | cond = testString(cond, t); |
michael@0 | 746 | j(cond, label); |
michael@0 | 747 | } |
michael@0 | 748 | template <typename T> |
michael@0 | 749 | void branchTestObject(Condition cond, const T &t, Label *label) { |
michael@0 | 750 | cond = testObject(cond, t); |
michael@0 | 751 | j(cond, label); |
michael@0 | 752 | } |
michael@0 | 753 | template <typename T> |
michael@0 | 754 | void branchTestNumber(Condition cond, const T &t, Label *label) { |
michael@0 | 755 | cond = testNumber(cond, t); |
michael@0 | 756 | j(cond, label); |
michael@0 | 757 | } |
michael@0 | 758 | template <typename T> |
michael@0 | 759 | void branchTestGCThing(Condition cond, const T &t, Label *label) { |
michael@0 | 760 | cond = testGCThing(cond, t); |
michael@0 | 761 | j(cond, label); |
michael@0 | 762 | } |
michael@0 | 763 | template <typename T> |
michael@0 | 764 | void branchTestPrimitive(Condition cond, const T &t, Label *label) { |
michael@0 | 765 | cond = testPrimitive(cond, t); |
michael@0 | 766 | j(cond, label); |
michael@0 | 767 | } |
michael@0 | 768 | template <typename T> |
michael@0 | 769 | void branchTestMagic(Condition cond, const T &t, Label *label) { |
michael@0 | 770 | cond = testMagic(cond, t); |
michael@0 | 771 | j(cond, label); |
michael@0 | 772 | } |
michael@0 | 773 | void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, |
michael@0 | 774 | Label *label) |
michael@0 | 775 | { |
michael@0 | 776 | JS_ASSERT(cond == Equal || cond == NotEqual); |
michael@0 | 777 | if (cond == Equal) { |
michael@0 | 778 | // Test for magic |
michael@0 | 779 | Label notmagic; |
michael@0 | 780 | Condition testCond = testMagic(Equal, val); |
michael@0 | 781 | j(InvertCondition(testCond), ¬magic); |
michael@0 | 782 | // Test magic value |
michael@0 | 783 | branch32(Equal, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label); |
michael@0 | 784 | bind(¬magic); |
michael@0 | 785 | } else { |
michael@0 | 786 | Condition testCond = testMagic(NotEqual, val); |
michael@0 | 787 | j(testCond, label); |
michael@0 | 788 | branch32(NotEqual, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label); |
michael@0 | 789 | } |
michael@0 | 790 | } |
michael@0 | 791 | |
michael@0 | 792 | // Note: this function clobbers the source register. |
michael@0 | 793 | void boxDouble(const FloatRegister &src, const ValueOperand &dest) { |
michael@0 | 794 | movd(src, dest.payloadReg()); |
michael@0 | 795 | psrldq(Imm32(4), src); |
michael@0 | 796 | movd(src, dest.typeReg()); |
michael@0 | 797 | } |
michael@0 | 798 | void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest) { |
michael@0 | 799 | if (src != dest.payloadReg()) |
michael@0 | 800 | movl(src, dest.payloadReg()); |
michael@0 | 801 | movl(ImmType(type), dest.typeReg()); |
michael@0 | 802 | } |
michael@0 | 803 | void unboxInt32(const ValueOperand &src, const Register &dest) { |
michael@0 | 804 | movl(src.payloadReg(), dest); |
michael@0 | 805 | } |
michael@0 | 806 | void unboxInt32(const Address &src, const Register &dest) { |
michael@0 | 807 | movl(payloadOf(src), dest); |
michael@0 | 808 | } |
michael@0 | 809 | void unboxDouble(const Address &src, const FloatRegister &dest) { |
michael@0 | 810 | loadDouble(Operand(src), dest); |
michael@0 | 811 | } |
michael@0 | 812 | void unboxBoolean(const ValueOperand &src, const Register &dest) { |
michael@0 | 813 | movl(src.payloadReg(), dest); |
michael@0 | 814 | } |
michael@0 | 815 | void unboxBoolean(const Address &src, const Register &dest) { |
michael@0 | 816 | movl(payloadOf(src), dest); |
michael@0 | 817 | } |
michael@0 | 818 | void unboxObject(const ValueOperand &src, const Register &dest) { |
michael@0 | 819 | if (src.payloadReg() != dest) |
michael@0 | 820 | movl(src.payloadReg(), dest); |
michael@0 | 821 | } |
michael@0 | 822 | void unboxDouble(const ValueOperand &src, const FloatRegister &dest) { |
michael@0 | 823 | JS_ASSERT(dest != ScratchFloatReg); |
michael@0 | 824 | if (Assembler::HasSSE41()) { |
michael@0 | 825 | movd(src.payloadReg(), dest); |
michael@0 | 826 | pinsrd(src.typeReg(), dest); |
michael@0 | 827 | } else { |
michael@0 | 828 | movd(src.payloadReg(), dest); |
michael@0 | 829 | movd(src.typeReg(), ScratchFloatReg); |
michael@0 | 830 | unpcklps(ScratchFloatReg, dest); |
michael@0 | 831 | } |
michael@0 | 832 | } |
michael@0 | 833 | void unboxDouble(const Operand &payload, const Operand &type, |
michael@0 | 834 | const Register &scratch, const FloatRegister &dest) { |
michael@0 | 835 | JS_ASSERT(dest != ScratchFloatReg); |
michael@0 | 836 | if (Assembler::HasSSE41()) { |
michael@0 | 837 | movl(payload, scratch); |
michael@0 | 838 | movd(scratch, dest); |
michael@0 | 839 | movl(type, scratch); |
michael@0 | 840 | pinsrd(scratch, dest); |
michael@0 | 841 | } else { |
michael@0 | 842 | movl(payload, scratch); |
michael@0 | 843 | movd(scratch, dest); |
michael@0 | 844 | movl(type, scratch); |
michael@0 | 845 | movd(scratch, ScratchFloatReg); |
michael@0 | 846 | unpcklps(ScratchFloatReg, dest); |
michael@0 | 847 | } |
michael@0 | 848 | } |
michael@0 | 849 | void unboxString(const ValueOperand &src, const Register &dest) { |
michael@0 | 850 | movl(src.payloadReg(), dest); |
michael@0 | 851 | } |
michael@0 | 852 | void unboxString(const Address &src, const Register &dest) { |
michael@0 | 853 | movl(payloadOf(src), dest); |
michael@0 | 854 | } |
michael@0 | 855 | void unboxValue(const ValueOperand &src, AnyRegister dest) { |
michael@0 | 856 | if (dest.isFloat()) { |
michael@0 | 857 | Label notInt32, end; |
michael@0 | 858 | branchTestInt32(Assembler::NotEqual, src, ¬Int32); |
michael@0 | 859 | convertInt32ToDouble(src.payloadReg(), dest.fpu()); |
michael@0 | 860 | jump(&end); |
michael@0 | 861 | bind(¬Int32); |
michael@0 | 862 | unboxDouble(src, dest.fpu()); |
michael@0 | 863 | bind(&end); |
michael@0 | 864 | } else { |
michael@0 | 865 | if (src.payloadReg() != dest.gpr()) |
michael@0 | 866 | movl(src.payloadReg(), dest.gpr()); |
michael@0 | 867 | } |
michael@0 | 868 | } |
michael@0 | 869 | void unboxPrivate(const ValueOperand &src, Register dest) { |
michael@0 | 870 | if (src.payloadReg() != dest) |
michael@0 | 871 | movl(src.payloadReg(), dest); |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | void notBoolean(const ValueOperand &val) { |
michael@0 | 875 | xorl(Imm32(1), val.payloadReg()); |
michael@0 | 876 | } |
michael@0 | 877 | |
michael@0 | 878 | // Extended unboxing API. If the payload is already in a register, returns |
michael@0 | 879 | // that register. Otherwise, provides a move to the given scratch register, |
michael@0 | 880 | // and returns that. |
michael@0 | 881 | Register extractObject(const Address &address, Register scratch) { |
michael@0 | 882 | movl(payloadOf(address), scratch); |
michael@0 | 883 | return scratch; |
michael@0 | 884 | } |
michael@0 | 885 | Register extractObject(const ValueOperand &value, Register scratch) { |
michael@0 | 886 | return value.payloadReg(); |
michael@0 | 887 | } |
michael@0 | 888 | Register extractInt32(const ValueOperand &value, Register scratch) { |
michael@0 | 889 | return value.payloadReg(); |
michael@0 | 890 | } |
michael@0 | 891 | Register extractBoolean(const ValueOperand &value, Register scratch) { |
michael@0 | 892 | return value.payloadReg(); |
michael@0 | 893 | } |
michael@0 | 894 | Register extractTag(const Address &address, Register scratch) { |
michael@0 | 895 | movl(tagOf(address), scratch); |
michael@0 | 896 | return scratch; |
michael@0 | 897 | } |
michael@0 | 898 | Register extractTag(const ValueOperand &value, Register scratch) { |
michael@0 | 899 | return value.typeReg(); |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 903 | convertInt32ToDouble(operand.payloadReg(), dest); |
michael@0 | 904 | } |
michael@0 | 905 | void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 906 | convertInt32ToFloat32(operand.payloadReg(), dest); |
michael@0 | 907 | } |
michael@0 | 908 | void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 909 | convertInt32ToDouble(operand.payloadReg(), dest); |
michael@0 | 910 | } |
michael@0 | 911 | void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { |
michael@0 | 912 | convertInt32ToFloat32(operand.payloadReg(), dest); |
michael@0 | 913 | } |
michael@0 | 914 | |
michael@0 | 915 | void loadConstantDouble(double d, const FloatRegister &dest); |
michael@0 | 916 | void addConstantDouble(double d, const FloatRegister &dest); |
michael@0 | 917 | void loadConstantFloat32(float f, const FloatRegister &dest); |
michael@0 | 918 | void addConstantFloat32(float f, const FloatRegister &dest); |
michael@0 | 919 | |
michael@0 | 920 | void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) { |
michael@0 | 921 | cvttsd2si(src, dest); |
michael@0 | 922 | |
michael@0 | 923 | // cvttsd2si returns 0x80000000 on failure. Test for it by |
michael@0 | 924 | // subtracting 1 and testing overflow (this permits the use of a |
michael@0 | 925 | // smaller immediate field). |
michael@0 | 926 | cmpl(dest, Imm32(1)); |
michael@0 | 927 | j(Assembler::Overflow, fail); |
michael@0 | 928 | } |
michael@0 | 929 | void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail) { |
michael@0 | 930 | cvttss2si(src, dest); |
michael@0 | 931 | |
michael@0 | 932 | // cvttss2si returns 0x80000000 on failure. Test for it by |
michael@0 | 933 | // subtracting 1 and testing overflow (this permits the use of a |
michael@0 | 934 | // smaller immediate field). |
michael@0 | 935 | cmpl(dest, Imm32(1)); |
michael@0 | 936 | j(Assembler::Overflow, fail); |
michael@0 | 937 | } |
michael@0 | 938 | |
michael@0 | 939 | Condition testInt32Truthy(bool truthy, const ValueOperand &operand) { |
michael@0 | 940 | testl(operand.payloadReg(), operand.payloadReg()); |
michael@0 | 941 | return truthy ? NonZero : Zero; |
michael@0 | 942 | } |
michael@0 | 943 | void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) { |
michael@0 | 944 | Condition cond = testInt32Truthy(truthy, operand); |
michael@0 | 945 | j(cond, label); |
michael@0 | 946 | } |
michael@0 | 947 | void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) { |
michael@0 | 948 | testl(operand.payloadReg(), operand.payloadReg()); |
michael@0 | 949 | j(truthy ? NonZero : Zero, label); |
michael@0 | 950 | } |
michael@0 | 951 | Condition testStringTruthy(bool truthy, const ValueOperand &value) { |
michael@0 | 952 | Register string = value.payloadReg(); |
michael@0 | 953 | Operand lengthAndFlags(string, JSString::offsetOfLengthAndFlags()); |
michael@0 | 954 | |
michael@0 | 955 | size_t mask = (0xFFFFFFFF << JSString::LENGTH_SHIFT); |
michael@0 | 956 | testl(lengthAndFlags, Imm32(mask)); |
michael@0 | 957 | return truthy ? Assembler::NonZero : Assembler::Zero; |
michael@0 | 958 | } |
michael@0 | 959 | void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) { |
michael@0 | 960 | Condition cond = testStringTruthy(truthy, value); |
michael@0 | 961 | j(cond, label); |
michael@0 | 962 | } |
michael@0 | 963 | |
michael@0 | 964 | void loadInt32OrDouble(const Operand &operand, const FloatRegister &dest) { |
michael@0 | 965 | Label notInt32, end; |
michael@0 | 966 | branchTestInt32(Assembler::NotEqual, operand, ¬Int32); |
michael@0 | 967 | convertInt32ToDouble(ToPayload(operand), dest); |
michael@0 | 968 | jump(&end); |
michael@0 | 969 | bind(¬Int32); |
michael@0 | 970 | loadDouble(operand, dest); |
michael@0 | 971 | bind(&end); |
michael@0 | 972 | } |
michael@0 | 973 | |
michael@0 | 974 | template <typename T> |
michael@0 | 975 | void loadUnboxedValue(const T &src, MIRType type, AnyRegister dest) { |
michael@0 | 976 | if (dest.isFloat()) |
michael@0 | 977 | loadInt32OrDouble(Operand(src), dest.fpu()); |
michael@0 | 978 | else |
michael@0 | 979 | movl(Operand(src), dest.gpr()); |
michael@0 | 980 | } |
michael@0 | 981 | |
michael@0 | 982 | void rshiftPtr(Imm32 imm, Register dest) { |
michael@0 | 983 | shrl(imm, dest); |
michael@0 | 984 | } |
michael@0 | 985 | void lshiftPtr(Imm32 imm, Register dest) { |
michael@0 | 986 | shll(imm, dest); |
michael@0 | 987 | } |
michael@0 | 988 | void xorPtr(Imm32 imm, Register dest) { |
michael@0 | 989 | xorl(imm, dest); |
michael@0 | 990 | } |
michael@0 | 991 | void xorPtr(Register src, Register dest) { |
michael@0 | 992 | xorl(src, dest); |
michael@0 | 993 | } |
michael@0 | 994 | void orPtr(Imm32 imm, Register dest) { |
michael@0 | 995 | orl(imm, dest); |
michael@0 | 996 | } |
michael@0 | 997 | void orPtr(Register src, Register dest) { |
michael@0 | 998 | orl(src, dest); |
michael@0 | 999 | } |
michael@0 | 1000 | void andPtr(Imm32 imm, Register dest) { |
michael@0 | 1001 | andl(imm, dest); |
michael@0 | 1002 | } |
michael@0 | 1003 | void andPtr(Register src, Register dest) { |
michael@0 | 1004 | andl(src, dest); |
michael@0 | 1005 | } |
michael@0 | 1006 | |
michael@0 | 1007 | void loadInstructionPointerAfterCall(const Register &dest) { |
michael@0 | 1008 | movl(Operand(StackPointer, 0x0), dest); |
michael@0 | 1009 | } |
michael@0 | 1010 | |
michael@0 | 1011 | // Note: this function clobbers the source register. |
michael@0 | 1012 | void convertUInt32ToDouble(const Register &src, const FloatRegister &dest) { |
michael@0 | 1013 | // src is [0, 2^32-1] |
michael@0 | 1014 | subl(Imm32(0x80000000), src); |
michael@0 | 1015 | |
michael@0 | 1016 | // Now src is [-2^31, 2^31-1] - int range, but not the same value. |
michael@0 | 1017 | convertInt32ToDouble(src, dest); |
michael@0 | 1018 | |
michael@0 | 1019 | // dest is now a double with the int range. |
michael@0 | 1020 | // correct the double value by adding 0x80000000. |
michael@0 | 1021 | addConstantDouble(2147483648.0, dest); |
michael@0 | 1022 | } |
michael@0 | 1023 | |
michael@0 | 1024 | // Note: this function clobbers the source register. |
michael@0 | 1025 | void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest) { |
michael@0 | 1026 | convertUInt32ToDouble(src, dest); |
michael@0 | 1027 | convertDoubleToFloat32(dest, dest); |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | void inc64(AbsoluteAddress dest) { |
michael@0 | 1031 | addl(Imm32(1), Operand(dest)); |
michael@0 | 1032 | Label noOverflow; |
michael@0 | 1033 | j(NonZero, &noOverflow); |
michael@0 | 1034 | addl(Imm32(1), Operand(dest.offset(4))); |
michael@0 | 1035 | bind(&noOverflow); |
michael@0 | 1036 | } |
michael@0 | 1037 | |
michael@0 | 1038 | |
michael@0 | 1039 | // If source is a double, load it into dest. If source is int32, |
michael@0 | 1040 | // convert it to double. Else, branch to failure. |
michael@0 | 1041 | void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) { |
michael@0 | 1042 | Label isDouble, done; |
michael@0 | 1043 | branchTestDouble(Assembler::Equal, source.typeReg(), &isDouble); |
michael@0 | 1044 | branchTestInt32(Assembler::NotEqual, source.typeReg(), failure); |
michael@0 | 1045 | |
michael@0 | 1046 | convertInt32ToDouble(source.payloadReg(), dest); |
michael@0 | 1047 | jump(&done); |
michael@0 | 1048 | |
michael@0 | 1049 | bind(&isDouble); |
michael@0 | 1050 | unboxDouble(source, dest); |
michael@0 | 1051 | |
michael@0 | 1052 | bind(&done); |
michael@0 | 1053 | } |
michael@0 | 1054 | |
michael@0 | 1055 | // Setup a call to C/C++ code, given the number of general arguments it |
michael@0 | 1056 | // takes. Note that this only supports cdecl. |
michael@0 | 1057 | // |
michael@0 | 1058 | // In order for alignment to work correctly, the MacroAssembler must have a |
michael@0 | 1059 | // consistent view of the stack displacement. It is okay to call "push" |
michael@0 | 1060 | // manually, however, if the stack alignment were to change, the macro |
michael@0 | 1061 | // assembler should be notified before starting a call. |
michael@0 | 1062 | void setupAlignedABICall(uint32_t args); |
michael@0 | 1063 | |
michael@0 | 1064 | // Sets up an ABI call for when the alignment is not known. This may need a |
michael@0 | 1065 | // scratch register. |
michael@0 | 1066 | void setupUnalignedABICall(uint32_t args, const Register &scratch); |
michael@0 | 1067 | |
michael@0 | 1068 | // Arguments must be assigned to a C/C++ call in order. They are moved |
michael@0 | 1069 | // in parallel immediately before performing the call. This process may |
michael@0 | 1070 | // temporarily use more stack, in which case esp-relative addresses will be |
michael@0 | 1071 | // automatically adjusted. It is extremely important that esp-relative |
michael@0 | 1072 | // addresses are computed *after* setupABICall(). Furthermore, no |
michael@0 | 1073 | // operations should be emitted while setting arguments. |
michael@0 | 1074 | void passABIArg(const MoveOperand &from, MoveOp::Type type); |
michael@0 | 1075 | void passABIArg(const Register ®); |
michael@0 | 1076 | void passABIArg(const FloatRegister ®, MoveOp::Type type); |
michael@0 | 1077 | |
michael@0 | 1078 | private: |
michael@0 | 1079 | void callWithABIPre(uint32_t *stackAdjust); |
michael@0 | 1080 | void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); |
michael@0 | 1081 | |
michael@0 | 1082 | public: |
michael@0 | 1083 | // Emits a call to a C/C++ function, resolving all argument moves. |
michael@0 | 1084 | void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1085 | void callWithABI(AsmJSImmPtr fun, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1086 | void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL); |
michael@0 | 1087 | |
michael@0 | 1088 | // Used from within an Exit frame to handle a pending exception. |
michael@0 | 1089 | void handleFailureWithHandler(void *handler); |
michael@0 | 1090 | void handleFailureWithHandlerTail(); |
michael@0 | 1091 | |
michael@0 | 1092 | void makeFrameDescriptor(Register frameSizeReg, FrameType type) { |
michael@0 | 1093 | shll(Imm32(FRAMESIZE_SHIFT), frameSizeReg); |
michael@0 | 1094 | orl(Imm32(type), frameSizeReg); |
michael@0 | 1095 | } |
michael@0 | 1096 | |
michael@0 | 1097 | // Save an exit frame (which must be aligned to the stack pointer) to |
michael@0 | 1098 | // ThreadData::ionTop of the main thread. |
michael@0 | 1099 | void linkExitFrame() { |
michael@0 | 1100 | movl(StackPointer, Operand(AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop()))); |
michael@0 | 1101 | } |
michael@0 | 1102 | |
michael@0 | 1103 | void callWithExitFrame(JitCode *target, Register dynStack) { |
michael@0 | 1104 | addPtr(Imm32(framePushed()), dynStack); |
michael@0 | 1105 | makeFrameDescriptor(dynStack, JitFrame_IonJS); |
michael@0 | 1106 | Push(dynStack); |
michael@0 | 1107 | call(target); |
michael@0 | 1108 | } |
michael@0 | 1109 | void call(const CallSiteDesc &desc, AsmJSImmPtr target) { |
michael@0 | 1110 | call(target); |
michael@0 | 1111 | appendCallSite(desc); |
michael@0 | 1112 | } |
michael@0 | 1113 | void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { |
michael@0 | 1114 | call(CallSiteDesc::Exit(), target); |
michael@0 | 1115 | } |
michael@0 | 1116 | |
michael@0 | 1117 | // Save an exit frame to the thread data of the current thread, given a |
michael@0 | 1118 | // register that holds a PerThreadData *. |
michael@0 | 1119 | void linkParallelExitFrame(const Register &pt) { |
michael@0 | 1120 | movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop))); |
michael@0 | 1121 | } |
michael@0 | 1122 | |
michael@0 | 1123 | #ifdef JSGC_GENERATIONAL |
michael@0 | 1124 | void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); |
michael@0 | 1125 | void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); |
michael@0 | 1126 | #endif |
michael@0 | 1127 | }; |
michael@0 | 1128 | |
michael@0 | 1129 | typedef MacroAssemblerX86 MacroAssemblerSpecific; |
michael@0 | 1130 | |
michael@0 | 1131 | } // namespace jit |
michael@0 | 1132 | } // namespace js |
michael@0 | 1133 | |
michael@0 | 1134 | #endif /* jit_x86_MacroAssembler_x86_h */ |