js/src/jit/x86/MacroAssembler-x86.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 &reg, 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), &notmagic);
michael@0 782 // Test magic value
michael@0 783 branch32(Equal, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
michael@0 784 bind(&notmagic);
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, &notInt32);
michael@0 859 convertInt32ToDouble(src.payloadReg(), dest.fpu());
michael@0 860 jump(&end);
michael@0 861 bind(&notInt32);
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, &notInt32);
michael@0 967 convertInt32ToDouble(ToPayload(operand), dest);
michael@0 968 jump(&end);
michael@0 969 bind(&notInt32);
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 &reg);
michael@0 1076 void passABIArg(const FloatRegister &reg, 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 */

mercurial