1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x64/MacroAssembler-x64.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1344 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jit_x64_MacroAssembler_x64_h 1.11 +#define jit_x64_MacroAssembler_x64_h 1.12 + 1.13 +#include "jit/IonFrames.h" 1.14 +#include "jit/MoveResolver.h" 1.15 +#include "jit/shared/MacroAssembler-x86-shared.h" 1.16 + 1.17 +namespace js { 1.18 +namespace jit { 1.19 + 1.20 +struct ImmShiftedTag : public ImmWord 1.21 +{ 1.22 + ImmShiftedTag(JSValueShiftedTag shtag) 1.23 + : ImmWord((uintptr_t)shtag) 1.24 + { } 1.25 + 1.26 + ImmShiftedTag(JSValueType type) 1.27 + : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type)))) 1.28 + { } 1.29 +}; 1.30 + 1.31 +struct ImmTag : public Imm32 1.32 +{ 1.33 + ImmTag(JSValueTag tag) 1.34 + : Imm32(tag) 1.35 + { } 1.36 +}; 1.37 + 1.38 +class MacroAssemblerX64 : public MacroAssemblerX86Shared 1.39 +{ 1.40 + // Number of bytes the stack is adjusted inside a call to C. Calls to C may 1.41 + // not be nested. 1.42 + bool inCall_; 1.43 + uint32_t args_; 1.44 + uint32_t passedIntArgs_; 1.45 + uint32_t passedFloatArgs_; 1.46 + uint32_t stackForCall_; 1.47 + bool dynamicAlignment_; 1.48 + bool enoughMemory_; 1.49 + 1.50 + // These use SystemAllocPolicy since asm.js releases memory after each 1.51 + // function is compiled, and these need to live until after all functions 1.52 + // are compiled. 1.53 + struct Double { 1.54 + double value; 1.55 + NonAssertingLabel uses; 1.56 + Double(double value) : value(value) {} 1.57 + }; 1.58 + Vector<Double, 0, SystemAllocPolicy> doubles_; 1.59 + 1.60 + typedef HashMap<double, size_t, DefaultHasher<double>, SystemAllocPolicy> DoubleMap; 1.61 + DoubleMap doubleMap_; 1.62 + 1.63 + struct Float { 1.64 + float value; 1.65 + NonAssertingLabel uses; 1.66 + Float(float value) : value(value) {} 1.67 + }; 1.68 + Vector<Float, 0, SystemAllocPolicy> floats_; 1.69 + 1.70 + typedef HashMap<float, size_t, DefaultHasher<float>, SystemAllocPolicy> FloatMap; 1.71 + FloatMap floatMap_; 1.72 + 1.73 + void setupABICall(uint32_t arg); 1.74 + 1.75 + protected: 1.76 + MoveResolver moveResolver_; 1.77 + 1.78 + public: 1.79 + using MacroAssemblerX86Shared::call; 1.80 + using MacroAssemblerX86Shared::Push; 1.81 + using MacroAssemblerX86Shared::Pop; 1.82 + using MacroAssemblerX86Shared::callWithExitFrame; 1.83 + using MacroAssemblerX86Shared::branch32; 1.84 + using MacroAssemblerX86Shared::load32; 1.85 + using MacroAssemblerX86Shared::store32; 1.86 + 1.87 + MacroAssemblerX64() 1.88 + : inCall_(false), 1.89 + enoughMemory_(true) 1.90 + { 1.91 + } 1.92 + 1.93 + // The buffer is about to be linked, make sure any constant pools or excess 1.94 + // bookkeeping has been flushed to the instruction stream. 1.95 + void finish(); 1.96 + 1.97 + bool oom() const { 1.98 + return MacroAssemblerX86Shared::oom() || !enoughMemory_; 1.99 + } 1.100 + 1.101 + ///////////////////////////////////////////////////////////////// 1.102 + // X64 helpers. 1.103 + ///////////////////////////////////////////////////////////////// 1.104 + void call(ImmWord target) { 1.105 + mov(target, rax); 1.106 + call(rax); 1.107 + } 1.108 + void call(ImmPtr target) { 1.109 + call(ImmWord(uintptr_t(target.value))); 1.110 + } 1.111 + void call(AsmJSImmPtr target) { 1.112 + mov(target, rax); 1.113 + call(rax); 1.114 + } 1.115 + 1.116 + void call(const CallSiteDesc &desc, AsmJSImmPtr target) { 1.117 + call(target); 1.118 + appendCallSite(desc); 1.119 + } 1.120 + void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) { 1.121 + call(CallSiteDesc::Exit(), target); 1.122 + } 1.123 + 1.124 + // Refers to the upper 32 bits of a 64-bit Value operand. 1.125 + // On x86_64, the upper 32 bits do not necessarily only contain the type. 1.126 + Operand ToUpper32(Operand base) { 1.127 + switch (base.kind()) { 1.128 + case Operand::MEM_REG_DISP: 1.129 + return Operand(Register::FromCode(base.base()), base.disp() + 4); 1.130 + 1.131 + case Operand::MEM_SCALE: 1.132 + return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()), 1.133 + base.scale(), base.disp() + 4); 1.134 + 1.135 + default: 1.136 + MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); 1.137 + } 1.138 + } 1.139 + static inline Operand ToUpper32(const Address &address) { 1.140 + return Operand(address.base, address.offset + 4); 1.141 + } 1.142 + static inline Operand ToUpper32(const BaseIndex &address) { 1.143 + return Operand(address.base, address.index, address.scale, address.offset + 4); 1.144 + } 1.145 + 1.146 + uint32_t Upper32Of(JSValueShiftedTag tag) { 1.147 + union { // Implemented in this way to appease MSVC++. 1.148 + uint64_t tag; 1.149 + struct { 1.150 + uint32_t lo32; 1.151 + uint32_t hi32; 1.152 + } s; 1.153 + } e; 1.154 + e.tag = tag; 1.155 + return e.s.hi32; 1.156 + } 1.157 + 1.158 + JSValueShiftedTag GetShiftedTag(JSValueType type) { 1.159 + return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); 1.160 + } 1.161 + 1.162 + ///////////////////////////////////////////////////////////////// 1.163 + // X86/X64-common interface. 1.164 + ///////////////////////////////////////////////////////////////// 1.165 + void storeValue(ValueOperand val, Operand dest) { 1.166 + movq(val.valueReg(), dest); 1.167 + } 1.168 + void storeValue(ValueOperand val, const Address &dest) { 1.169 + storeValue(val, Operand(dest)); 1.170 + } 1.171 + template <typename T> 1.172 + void storeValue(JSValueType type, Register reg, const T &dest) { 1.173 + // Value types with 32-bit payloads can be emitted as two 32-bit moves. 1.174 + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 1.175 + movl(reg, Operand(dest)); 1.176 + movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest))); 1.177 + } else { 1.178 + boxValue(type, reg, ScratchReg); 1.179 + movq(ScratchReg, Operand(dest)); 1.180 + } 1.181 + } 1.182 + template <typename T> 1.183 + void storeValue(const Value &val, const T &dest) { 1.184 + jsval_layout jv = JSVAL_TO_IMPL(val); 1.185 + if (val.isMarkable()) { 1.186 + movWithPatch(ImmWord(jv.asBits), ScratchReg); 1.187 + writeDataRelocation(val); 1.188 + } else { 1.189 + mov(ImmWord(jv.asBits), ScratchReg); 1.190 + } 1.191 + movq(ScratchReg, Operand(dest)); 1.192 + } 1.193 + void storeValue(ValueOperand val, BaseIndex dest) { 1.194 + storeValue(val, Operand(dest)); 1.195 + } 1.196 + void loadValue(Operand src, ValueOperand val) { 1.197 + movq(src, val.valueReg()); 1.198 + } 1.199 + void loadValue(Address src, ValueOperand val) { 1.200 + loadValue(Operand(src), val); 1.201 + } 1.202 + void loadValue(const BaseIndex &src, ValueOperand val) { 1.203 + loadValue(Operand(src), val); 1.204 + } 1.205 + void tagValue(JSValueType type, Register payload, ValueOperand dest) { 1.206 + JS_ASSERT(dest.valueReg() != ScratchReg); 1.207 + if (payload != dest.valueReg()) 1.208 + movq(payload, dest.valueReg()); 1.209 + mov(ImmShiftedTag(type), ScratchReg); 1.210 + orq(ScratchReg, dest.valueReg()); 1.211 + } 1.212 + void pushValue(ValueOperand val) { 1.213 + push(val.valueReg()); 1.214 + } 1.215 + void Push(const ValueOperand &val) { 1.216 + pushValue(val); 1.217 + framePushed_ += sizeof(Value); 1.218 + } 1.219 + void popValue(ValueOperand val) { 1.220 + pop(val.valueReg()); 1.221 + } 1.222 + void pushValue(const Value &val) { 1.223 + jsval_layout jv = JSVAL_TO_IMPL(val); 1.224 + push(ImmWord(jv.asBits)); 1.225 + } 1.226 + void pushValue(JSValueType type, Register reg) { 1.227 + boxValue(type, reg, ScratchReg); 1.228 + push(ScratchReg); 1.229 + } 1.230 + void pushValue(const Address &addr) { 1.231 + push(Operand(addr)); 1.232 + } 1.233 + void Pop(const ValueOperand &val) { 1.234 + popValue(val); 1.235 + framePushed_ -= sizeof(Value); 1.236 + } 1.237 + 1.238 + void moveValue(const Value &val, const Register &dest) { 1.239 + jsval_layout jv = JSVAL_TO_IMPL(val); 1.240 + movWithPatch(ImmWord(jv.asBits), dest); 1.241 + writeDataRelocation(val); 1.242 + } 1.243 + void moveValue(const Value &src, const ValueOperand &dest) { 1.244 + moveValue(src, dest.valueReg()); 1.245 + } 1.246 + void moveValue(const ValueOperand &src, const ValueOperand &dest) { 1.247 + if (src.valueReg() != dest.valueReg()) 1.248 + movq(src.valueReg(), dest.valueReg()); 1.249 + } 1.250 + void boxValue(JSValueType type, Register src, Register dest) { 1.251 + JS_ASSERT(src != dest); 1.252 + 1.253 + JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type); 1.254 +#ifdef DEBUG 1.255 + if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) { 1.256 + Label upper32BitsZeroed; 1.257 + movePtr(ImmWord(UINT32_MAX), dest); 1.258 + branchPtr(Assembler::BelowOrEqual, src, dest, &upper32BitsZeroed); 1.259 + breakpoint(); 1.260 + bind(&upper32BitsZeroed); 1.261 + } 1.262 +#endif 1.263 + mov(ImmShiftedTag(tag), dest); 1.264 + orq(src, dest); 1.265 + } 1.266 + 1.267 + Condition testUndefined(Condition cond, Register tag) { 1.268 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.269 + cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED)); 1.270 + return cond; 1.271 + } 1.272 + Condition testInt32(Condition cond, Register tag) { 1.273 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.274 + cmpl(tag, ImmTag(JSVAL_TAG_INT32)); 1.275 + return cond; 1.276 + } 1.277 + Condition testBoolean(Condition cond, Register tag) { 1.278 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.279 + cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN)); 1.280 + return cond; 1.281 + } 1.282 + Condition testNull(Condition cond, Register tag) { 1.283 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.284 + cmpl(tag, ImmTag(JSVAL_TAG_NULL)); 1.285 + return cond; 1.286 + } 1.287 + Condition testString(Condition cond, Register tag) { 1.288 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.289 + cmpl(tag, ImmTag(JSVAL_TAG_STRING)); 1.290 + return cond; 1.291 + } 1.292 + Condition testObject(Condition cond, Register tag) { 1.293 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.294 + cmpl(tag, ImmTag(JSVAL_TAG_OBJECT)); 1.295 + return cond; 1.296 + } 1.297 + Condition testDouble(Condition cond, Register tag) { 1.298 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.299 + cmpl(tag, Imm32(JSVAL_TAG_MAX_DOUBLE)); 1.300 + return cond == Equal ? BelowOrEqual : Above; 1.301 + } 1.302 + Condition testNumber(Condition cond, Register tag) { 1.303 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.304 + cmpl(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)); 1.305 + return cond == Equal ? BelowOrEqual : Above; 1.306 + } 1.307 + Condition testGCThing(Condition cond, Register tag) { 1.308 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.309 + cmpl(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET)); 1.310 + return cond == Equal ? AboveOrEqual : Below; 1.311 + } 1.312 + 1.313 + Condition testMagic(Condition cond, const Register &tag) { 1.314 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.315 + cmpl(tag, ImmTag(JSVAL_TAG_MAGIC)); 1.316 + return cond; 1.317 + } 1.318 + Condition testError(Condition cond, const Register &tag) { 1.319 + return testMagic(cond, tag); 1.320 + } 1.321 + Condition testPrimitive(Condition cond, const Register &tag) { 1.322 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.323 + cmpl(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET)); 1.324 + return cond == Equal ? Below : AboveOrEqual; 1.325 + } 1.326 + 1.327 + Condition testUndefined(Condition cond, const ValueOperand &src) { 1.328 + splitTag(src, ScratchReg); 1.329 + return testUndefined(cond, ScratchReg); 1.330 + } 1.331 + Condition testInt32(Condition cond, const ValueOperand &src) { 1.332 + splitTag(src, ScratchReg); 1.333 + return testInt32(cond, ScratchReg); 1.334 + } 1.335 + Condition testBoolean(Condition cond, const ValueOperand &src) { 1.336 + splitTag(src, ScratchReg); 1.337 + return testBoolean(cond, ScratchReg); 1.338 + } 1.339 + Condition testDouble(Condition cond, const ValueOperand &src) { 1.340 + splitTag(src, ScratchReg); 1.341 + return testDouble(cond, ScratchReg); 1.342 + } 1.343 + Condition testNumber(Condition cond, const ValueOperand &src) { 1.344 + splitTag(src, ScratchReg); 1.345 + return testNumber(cond, ScratchReg); 1.346 + } 1.347 + Condition testNull(Condition cond, const ValueOperand &src) { 1.348 + splitTag(src, ScratchReg); 1.349 + return testNull(cond, ScratchReg); 1.350 + } 1.351 + Condition testString(Condition cond, const ValueOperand &src) { 1.352 + splitTag(src, ScratchReg); 1.353 + return testString(cond, ScratchReg); 1.354 + } 1.355 + Condition testObject(Condition cond, const ValueOperand &src) { 1.356 + splitTag(src, ScratchReg); 1.357 + return testObject(cond, ScratchReg); 1.358 + } 1.359 + Condition testGCThing(Condition cond, const ValueOperand &src) { 1.360 + splitTag(src, ScratchReg); 1.361 + return testGCThing(cond, ScratchReg); 1.362 + } 1.363 + Condition testPrimitive(Condition cond, const ValueOperand &src) { 1.364 + splitTag(src, ScratchReg); 1.365 + return testPrimitive(cond, ScratchReg); 1.366 + } 1.367 + 1.368 + 1.369 + Condition testUndefined(Condition cond, const Address &src) { 1.370 + splitTag(src, ScratchReg); 1.371 + return testUndefined(cond, ScratchReg); 1.372 + } 1.373 + Condition testInt32(Condition cond, const Address &src) { 1.374 + splitTag(src, ScratchReg); 1.375 + return testInt32(cond, ScratchReg); 1.376 + } 1.377 + Condition testBoolean(Condition cond, const Address &src) { 1.378 + splitTag(src, ScratchReg); 1.379 + return testBoolean(cond, ScratchReg); 1.380 + } 1.381 + Condition testDouble(Condition cond, const Address &src) { 1.382 + splitTag(src, ScratchReg); 1.383 + return testDouble(cond, ScratchReg); 1.384 + } 1.385 + Condition testNumber(Condition cond, const Address &src) { 1.386 + splitTag(src, ScratchReg); 1.387 + return testNumber(cond, ScratchReg); 1.388 + } 1.389 + Condition testNull(Condition cond, const Address &src) { 1.390 + splitTag(src, ScratchReg); 1.391 + return testNull(cond, ScratchReg); 1.392 + } 1.393 + Condition testString(Condition cond, const Address &src) { 1.394 + splitTag(src, ScratchReg); 1.395 + return testString(cond, ScratchReg); 1.396 + } 1.397 + Condition testObject(Condition cond, const Address &src) { 1.398 + splitTag(src, ScratchReg); 1.399 + return testObject(cond, ScratchReg); 1.400 + } 1.401 + Condition testPrimitive(Condition cond, const Address &src) { 1.402 + splitTag(src, ScratchReg); 1.403 + return testPrimitive(cond, ScratchReg); 1.404 + } 1.405 + Condition testGCThing(Condition cond, const Address &src) { 1.406 + splitTag(src, ScratchReg); 1.407 + return testGCThing(cond, ScratchReg); 1.408 + } 1.409 + Condition testMagic(Condition cond, const Address &src) { 1.410 + splitTag(src, ScratchReg); 1.411 + return testMagic(cond, ScratchReg); 1.412 + } 1.413 + 1.414 + 1.415 + Condition testUndefined(Condition cond, const BaseIndex &src) { 1.416 + splitTag(src, ScratchReg); 1.417 + return testUndefined(cond, ScratchReg); 1.418 + } 1.419 + Condition testNull(Condition cond, const BaseIndex &src) { 1.420 + splitTag(src, ScratchReg); 1.421 + return testNull(cond, ScratchReg); 1.422 + } 1.423 + Condition testBoolean(Condition cond, const BaseIndex &src) { 1.424 + splitTag(src, ScratchReg); 1.425 + return testBoolean(cond, ScratchReg); 1.426 + } 1.427 + Condition testString(Condition cond, const BaseIndex &src) { 1.428 + splitTag(src, ScratchReg); 1.429 + return testString(cond, ScratchReg); 1.430 + } 1.431 + Condition testInt32(Condition cond, const BaseIndex &src) { 1.432 + splitTag(src, ScratchReg); 1.433 + return testInt32(cond, ScratchReg); 1.434 + } 1.435 + Condition testObject(Condition cond, const BaseIndex &src) { 1.436 + splitTag(src, ScratchReg); 1.437 + return testObject(cond, ScratchReg); 1.438 + } 1.439 + Condition testDouble(Condition cond, const BaseIndex &src) { 1.440 + splitTag(src, ScratchReg); 1.441 + return testDouble(cond, ScratchReg); 1.442 + } 1.443 + Condition testMagic(Condition cond, const BaseIndex &src) { 1.444 + splitTag(src, ScratchReg); 1.445 + return testMagic(cond, ScratchReg); 1.446 + } 1.447 + Condition testGCThing(Condition cond, const BaseIndex &src) { 1.448 + splitTag(src, ScratchReg); 1.449 + return testGCThing(cond, ScratchReg); 1.450 + } 1.451 + 1.452 + Condition isMagic(Condition cond, const ValueOperand &src, JSWhyMagic why) { 1.453 + uint64_t magic = MagicValue(why).asRawBits(); 1.454 + cmpPtr(src.valueReg(), ImmWord(magic)); 1.455 + return cond; 1.456 + } 1.457 + 1.458 + void cmpPtr(const Register &lhs, const ImmWord rhs) { 1.459 + JS_ASSERT(lhs != ScratchReg); 1.460 + mov(rhs, ScratchReg); 1.461 + cmpq(lhs, ScratchReg); 1.462 + } 1.463 + void cmpPtr(const Register &lhs, const ImmPtr rhs) { 1.464 + cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 1.465 + } 1.466 + void cmpPtr(const Register &lhs, const ImmGCPtr rhs) { 1.467 + JS_ASSERT(lhs != ScratchReg); 1.468 + movq(rhs, ScratchReg); 1.469 + cmpq(lhs, ScratchReg); 1.470 + } 1.471 + void cmpPtr(const Register &lhs, const Imm32 rhs) { 1.472 + cmpq(lhs, rhs); 1.473 + } 1.474 + void cmpPtr(const Operand &lhs, const ImmGCPtr rhs) { 1.475 + movq(rhs, ScratchReg); 1.476 + cmpq(lhs, ScratchReg); 1.477 + } 1.478 + void cmpPtr(const Operand &lhs, const ImmWord rhs) { 1.479 + if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) { 1.480 + cmpq(lhs, Imm32((int32_t)rhs.value)); 1.481 + } else { 1.482 + mov(rhs, ScratchReg); 1.483 + cmpq(lhs, ScratchReg); 1.484 + } 1.485 + } 1.486 + void cmpPtr(const Operand &lhs, const ImmPtr rhs) { 1.487 + cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 1.488 + } 1.489 + void cmpPtr(const Address &lhs, const ImmGCPtr rhs) { 1.490 + cmpPtr(Operand(lhs), rhs); 1.491 + } 1.492 + void cmpPtr(const Address &lhs, const ImmWord rhs) { 1.493 + cmpPtr(Operand(lhs), rhs); 1.494 + } 1.495 + void cmpPtr(const Address &lhs, const ImmPtr rhs) { 1.496 + cmpPtr(lhs, ImmWord(uintptr_t(rhs.value))); 1.497 + } 1.498 + void cmpPtr(const Operand &lhs, const Register &rhs) { 1.499 + cmpq(lhs, rhs); 1.500 + } 1.501 + void cmpPtr(const Operand &lhs, const Imm32 rhs) { 1.502 + cmpq(lhs, rhs); 1.503 + } 1.504 + void cmpPtr(const Address &lhs, const Register &rhs) { 1.505 + cmpPtr(Operand(lhs), rhs); 1.506 + } 1.507 + void cmpPtr(const Register &lhs, const Register &rhs) { 1.508 + return cmpq(lhs, rhs); 1.509 + } 1.510 + void testPtr(const Register &lhs, const Register &rhs) { 1.511 + testq(lhs, rhs); 1.512 + } 1.513 + 1.514 + template <typename T1, typename T2> 1.515 + void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, const Register &dest) 1.516 + { 1.517 + cmpPtr(lhs, rhs); 1.518 + emitSet(cond, dest); 1.519 + } 1.520 + 1.521 + ///////////////////////////////////////////////////////////////// 1.522 + // Common interface. 1.523 + ///////////////////////////////////////////////////////////////// 1.524 + void reserveStack(uint32_t amount) { 1.525 + if (amount) 1.526 + subq(Imm32(amount), StackPointer); 1.527 + framePushed_ += amount; 1.528 + } 1.529 + void freeStack(uint32_t amount) { 1.530 + JS_ASSERT(amount <= framePushed_); 1.531 + if (amount) 1.532 + addq(Imm32(amount), StackPointer); 1.533 + framePushed_ -= amount; 1.534 + } 1.535 + void freeStack(Register amount) { 1.536 + addq(amount, StackPointer); 1.537 + } 1.538 + 1.539 + void addPtr(const Register &src, const Register &dest) { 1.540 + addq(src, dest); 1.541 + } 1.542 + void addPtr(Imm32 imm, const Register &dest) { 1.543 + addq(imm, dest); 1.544 + } 1.545 + void addPtr(Imm32 imm, const Address &dest) { 1.546 + addq(imm, Operand(dest)); 1.547 + } 1.548 + void addPtr(Imm32 imm, const Operand &dest) { 1.549 + addq(imm, dest); 1.550 + } 1.551 + void addPtr(ImmWord imm, const Register &dest) { 1.552 + JS_ASSERT(dest != ScratchReg); 1.553 + if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { 1.554 + addq(Imm32((int32_t)imm.value), dest); 1.555 + } else { 1.556 + mov(imm, ScratchReg); 1.557 + addq(ScratchReg, dest); 1.558 + } 1.559 + } 1.560 + void addPtr(ImmPtr imm, const Register &dest) { 1.561 + addPtr(ImmWord(uintptr_t(imm.value)), dest); 1.562 + } 1.563 + void addPtr(const Address &src, const Register &dest) { 1.564 + addq(Operand(src), dest); 1.565 + } 1.566 + void subPtr(Imm32 imm, const Register &dest) { 1.567 + subq(imm, dest); 1.568 + } 1.569 + void subPtr(const Register &src, const Register &dest) { 1.570 + subq(src, dest); 1.571 + } 1.572 + void subPtr(const Address &addr, const Register &dest) { 1.573 + subq(Operand(addr), dest); 1.574 + } 1.575 + void subPtr(const Register &src, const Address &dest) { 1.576 + subq(src, Operand(dest)); 1.577 + } 1.578 + 1.579 + void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { 1.580 + if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) { 1.581 + branch32(cond, Operand(lhs), rhs, label); 1.582 + } else { 1.583 + mov(ImmPtr(lhs.addr), ScratchReg); 1.584 + branch32(cond, Address(ScratchReg, 0), rhs, label); 1.585 + } 1.586 + } 1.587 + void branch32(Condition cond, const AbsoluteAddress &lhs, Register rhs, Label *label) { 1.588 + if (JSC::X86Assembler::isAddressImmediate(lhs.addr)) { 1.589 + branch32(cond, Operand(lhs), rhs, label); 1.590 + } else { 1.591 + mov(ImmPtr(lhs.addr), ScratchReg); 1.592 + branch32(cond, Address(ScratchReg, 0), rhs, label); 1.593 + } 1.594 + } 1.595 + 1.596 + // Specialization for AbsoluteAddress. 1.597 + void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { 1.598 + JS_ASSERT(ptr != ScratchReg); 1.599 + if (JSC::X86Assembler::isAddressImmediate(addr.addr)) { 1.600 + branchPtr(cond, Operand(addr), ptr, label); 1.601 + } else { 1.602 + mov(ImmPtr(addr.addr), ScratchReg); 1.603 + branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label); 1.604 + } 1.605 + } 1.606 + void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, Label *label) { 1.607 + JS_ASSERT(ptr != ScratchReg); 1.608 + mov(AsmJSImmPtr(addr.kind()), ScratchReg); 1.609 + branchPtr(cond, Operand(ScratchReg, 0x0), ptr, label); 1.610 + } 1.611 + 1.612 + void branchPrivatePtr(Condition cond, Address lhs, ImmPtr ptr, Label *label) { 1.613 + branchPtr(cond, lhs, ImmWord(uintptr_t(ptr.value) >> 1), label); 1.614 + } 1.615 + 1.616 + void branchPrivatePtr(Condition cond, Address lhs, Register ptr, Label *label) { 1.617 + if (ptr != ScratchReg) 1.618 + movePtr(ptr, ScratchReg); 1.619 + rshiftPtr(Imm32(1), ScratchReg); 1.620 + branchPtr(cond, lhs, ScratchReg, label); 1.621 + } 1.622 + 1.623 + template <typename T, typename S> 1.624 + void branchPtr(Condition cond, T lhs, S ptr, Label *label) { 1.625 + cmpPtr(Operand(lhs), ptr); 1.626 + j(cond, label); 1.627 + } 1.628 + 1.629 + CodeOffsetJump jumpWithPatch(RepatchLabel *label) { 1.630 + JmpSrc src = jmpSrc(label); 1.631 + return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED)); 1.632 + } 1.633 + 1.634 + CodeOffsetJump jumpWithPatch(RepatchLabel *label, Condition cond) { 1.635 + JmpSrc src = jSrc(cond, label); 1.636 + return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED)); 1.637 + } 1.638 + 1.639 + template <typename S, typename T> 1.640 + CodeOffsetJump branchPtrWithPatch(Condition cond, S lhs, T ptr, RepatchLabel *label) { 1.641 + cmpPtr(lhs, ptr); 1.642 + return jumpWithPatch(label, cond); 1.643 + } 1.644 + void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { 1.645 + cmpPtr(lhs, rhs); 1.646 + j(cond, label); 1.647 + } 1.648 + void branchTestPtr(Condition cond, Register lhs, Register rhs, Label *label) { 1.649 + testq(lhs, rhs); 1.650 + j(cond, label); 1.651 + } 1.652 + void branchTestPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { 1.653 + testq(lhs, imm); 1.654 + j(cond, label); 1.655 + } 1.656 + void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { 1.657 + testq(Operand(lhs), imm); 1.658 + j(cond, label); 1.659 + } 1.660 + void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { 1.661 + subPtr(imm, lhs); 1.662 + j(cond, label); 1.663 + } 1.664 + 1.665 + void movePtr(const Register &src, const Register &dest) { 1.666 + movq(src, dest); 1.667 + } 1.668 + void movePtr(const Register &src, const Operand &dest) { 1.669 + movq(src, dest); 1.670 + } 1.671 + void movePtr(ImmWord imm, Register dest) { 1.672 + mov(imm, dest); 1.673 + } 1.674 + void movePtr(ImmPtr imm, Register dest) { 1.675 + mov(imm, dest); 1.676 + } 1.677 + void movePtr(AsmJSImmPtr imm, const Register &dest) { 1.678 + mov(imm, dest); 1.679 + } 1.680 + void movePtr(ImmGCPtr imm, Register dest) { 1.681 + movq(imm, dest); 1.682 + } 1.683 + void loadPtr(const AbsoluteAddress &address, Register dest) { 1.684 + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { 1.685 + movq(Operand(address), dest); 1.686 + } else { 1.687 + mov(ImmPtr(address.addr), ScratchReg); 1.688 + loadPtr(Address(ScratchReg, 0x0), dest); 1.689 + } 1.690 + } 1.691 + void loadPtr(const Address &address, Register dest) { 1.692 + movq(Operand(address), dest); 1.693 + } 1.694 + void loadPtr(const Operand &src, Register dest) { 1.695 + movq(src, dest); 1.696 + } 1.697 + void loadPtr(const BaseIndex &src, Register dest) { 1.698 + movq(Operand(src), dest); 1.699 + } 1.700 + void loadPrivate(const Address &src, Register dest) { 1.701 + loadPtr(src, dest); 1.702 + shlq(Imm32(1), dest); 1.703 + } 1.704 + void load32(const AbsoluteAddress &address, Register dest) { 1.705 + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { 1.706 + movl(Operand(address), dest); 1.707 + } else { 1.708 + mov(ImmPtr(address.addr), ScratchReg); 1.709 + load32(Address(ScratchReg, 0x0), dest); 1.710 + } 1.711 + } 1.712 + void storePtr(ImmWord imm, const Address &address) { 1.713 + if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) { 1.714 + movq(Imm32((int32_t)imm.value), Operand(address)); 1.715 + } else { 1.716 + mov(imm, ScratchReg); 1.717 + movq(ScratchReg, Operand(address)); 1.718 + } 1.719 + } 1.720 + void storePtr(ImmPtr imm, const Address &address) { 1.721 + storePtr(ImmWord(uintptr_t(imm.value)), address); 1.722 + } 1.723 + void storePtr(ImmGCPtr imm, const Address &address) { 1.724 + movq(imm, ScratchReg); 1.725 + movq(ScratchReg, Operand(address)); 1.726 + } 1.727 + void storePtr(Register src, const Address &address) { 1.728 + movq(src, Operand(address)); 1.729 + } 1.730 + void storePtr(Register src, const Operand &dest) { 1.731 + movq(src, dest); 1.732 + } 1.733 + void storePtr(const Register &src, const AbsoluteAddress &address) { 1.734 + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { 1.735 + movq(src, Operand(address)); 1.736 + } else { 1.737 + mov(ImmPtr(address.addr), ScratchReg); 1.738 + storePtr(src, Address(ScratchReg, 0x0)); 1.739 + } 1.740 + } 1.741 + void store32(const Register &src, const AbsoluteAddress &address) { 1.742 + if (JSC::X86Assembler::isAddressImmediate(address.addr)) { 1.743 + movl(src, Operand(address)); 1.744 + } else { 1.745 + mov(ImmPtr(address.addr), ScratchReg); 1.746 + store32(src, Address(ScratchReg, 0x0)); 1.747 + } 1.748 + } 1.749 + void rshiftPtr(Imm32 imm, Register dest) { 1.750 + shrq(imm, dest); 1.751 + } 1.752 + void lshiftPtr(Imm32 imm, Register dest) { 1.753 + shlq(imm, dest); 1.754 + } 1.755 + void xorPtr(Imm32 imm, Register dest) { 1.756 + xorq(imm, dest); 1.757 + } 1.758 + void xorPtr(Register src, Register dest) { 1.759 + xorq(src, dest); 1.760 + } 1.761 + void orPtr(Imm32 imm, Register dest) { 1.762 + orq(imm, dest); 1.763 + } 1.764 + void orPtr(Register src, Register dest) { 1.765 + orq(src, dest); 1.766 + } 1.767 + void andPtr(Imm32 imm, Register dest) { 1.768 + andq(imm, dest); 1.769 + } 1.770 + void andPtr(Register src, Register dest) { 1.771 + andq(src, dest); 1.772 + } 1.773 + 1.774 + void splitTag(Register src, Register dest) { 1.775 + if (src != dest) 1.776 + movq(src, dest); 1.777 + shrq(Imm32(JSVAL_TAG_SHIFT), dest); 1.778 + } 1.779 + void splitTag(const ValueOperand &operand, const Register &dest) { 1.780 + splitTag(operand.valueReg(), dest); 1.781 + } 1.782 + void splitTag(const Operand &operand, const Register &dest) { 1.783 + movq(operand, dest); 1.784 + shrq(Imm32(JSVAL_TAG_SHIFT), dest); 1.785 + } 1.786 + void splitTag(const Address &operand, const Register &dest) { 1.787 + splitTag(Operand(operand), dest); 1.788 + } 1.789 + void splitTag(const BaseIndex &operand, const Register &dest) { 1.790 + splitTag(Operand(operand), dest); 1.791 + } 1.792 + 1.793 + // Extracts the tag of a value and places it in ScratchReg. 1.794 + Register splitTagForTest(const ValueOperand &value) { 1.795 + splitTag(value, ScratchReg); 1.796 + return ScratchReg; 1.797 + } 1.798 + void cmpTag(const ValueOperand &operand, ImmTag tag) { 1.799 + Register reg = splitTagForTest(operand); 1.800 + cmpl(reg, tag); 1.801 + } 1.802 + 1.803 + void branchTestUndefined(Condition cond, Register tag, Label *label) { 1.804 + cond = testUndefined(cond, tag); 1.805 + j(cond, label); 1.806 + } 1.807 + void branchTestInt32(Condition cond, Register tag, Label *label) { 1.808 + cond = testInt32(cond, tag); 1.809 + j(cond, label); 1.810 + } 1.811 + void branchTestDouble(Condition cond, Register tag, Label *label) { 1.812 + cond = testDouble(cond, tag); 1.813 + j(cond, label); 1.814 + } 1.815 + void branchTestBoolean(Condition cond, Register tag, Label *label) { 1.816 + cond = testBoolean(cond, tag); 1.817 + j(cond, label); 1.818 + } 1.819 + void branchTestNull(Condition cond, Register tag, Label *label) { 1.820 + cond = testNull(cond, tag); 1.821 + j(cond, label); 1.822 + } 1.823 + void branchTestString(Condition cond, Register tag, Label *label) { 1.824 + cond = testString(cond, tag); 1.825 + j(cond, label); 1.826 + } 1.827 + void branchTestObject(Condition cond, Register tag, Label *label) { 1.828 + cond = testObject(cond, tag); 1.829 + j(cond, label); 1.830 + } 1.831 + void branchTestNumber(Condition cond, Register tag, Label *label) { 1.832 + cond = testNumber(cond, tag); 1.833 + j(cond, label); 1.834 + } 1.835 + 1.836 + // x64 can test for certain types directly from memory when the payload 1.837 + // of the type is limited to 32 bits. This avoids loading into a register, 1.838 + // accesses half as much memory, and removes a right-shift. 1.839 + void branchTestUndefined(Condition cond, const Operand &operand, Label *label) { 1.840 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.841 + cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED)))); 1.842 + j(cond, label); 1.843 + } 1.844 + void branchTestUndefined(Condition cond, const Address &address, Label *label) { 1.845 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.846 + branchTestUndefined(cond, Operand(address), label); 1.847 + } 1.848 + void branchTestInt32(Condition cond, const Operand &operand, Label *label) { 1.849 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.850 + cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32)))); 1.851 + j(cond, label); 1.852 + } 1.853 + void branchTestInt32(Condition cond, const Address &address, Label *label) { 1.854 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.855 + branchTestInt32(cond, Operand(address), label); 1.856 + } 1.857 + void branchTestDouble(Condition cond, const Operand &operand, Label *label) { 1.858 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.859 + splitTag(operand, ScratchReg); 1.860 + branchTestDouble(cond, ScratchReg, label); 1.861 + } 1.862 + void branchTestDouble(Condition cond, const Address &address, Label *label) { 1.863 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.864 + branchTestDouble(cond, Operand(address), label); 1.865 + } 1.866 + void branchTestBoolean(Condition cond, const Operand &operand, Label *label) { 1.867 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.868 + cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN)))); 1.869 + j(cond, label); 1.870 + } 1.871 + void branchTestNull(Condition cond, const Operand &operand, Label *label) { 1.872 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.873 + cmpl(ToUpper32(operand), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL)))); 1.874 + j(cond, label); 1.875 + } 1.876 + 1.877 + // Perform a type-test on a full Value loaded into a register. 1.878 + // Clobbers the ScratchReg. 1.879 + void branchTestUndefined(Condition cond, const ValueOperand &src, Label *label) { 1.880 + cond = testUndefined(cond, src); 1.881 + j(cond, label); 1.882 + } 1.883 + void branchTestInt32(Condition cond, const ValueOperand &src, Label *label) { 1.884 + splitTag(src, ScratchReg); 1.885 + branchTestInt32(cond, ScratchReg, label); 1.886 + } 1.887 + void branchTestBoolean(Condition cond, const ValueOperand &src, Label *label) { 1.888 + splitTag(src, ScratchReg); 1.889 + branchTestBoolean(cond, ScratchReg, label); 1.890 + } 1.891 + void branchTestDouble(Condition cond, const ValueOperand &src, Label *label) { 1.892 + cond = testDouble(cond, src); 1.893 + j(cond, label); 1.894 + } 1.895 + void branchTestNull(Condition cond, const ValueOperand &src, Label *label) { 1.896 + cond = testNull(cond, src); 1.897 + j(cond, label); 1.898 + } 1.899 + void branchTestString(Condition cond, const ValueOperand &src, Label *label) { 1.900 + cond = testString(cond, src); 1.901 + j(cond, label); 1.902 + } 1.903 + void branchTestObject(Condition cond, const ValueOperand &src, Label *label) { 1.904 + cond = testObject(cond, src); 1.905 + j(cond, label); 1.906 + } 1.907 + void branchTestNumber(Condition cond, const ValueOperand &src, Label *label) { 1.908 + cond = testNumber(cond, src); 1.909 + j(cond, label); 1.910 + } 1.911 + 1.912 + // Perform a type-test on a Value addressed by BaseIndex. 1.913 + // Clobbers the ScratchReg. 1.914 + void branchTestUndefined(Condition cond, const BaseIndex &address, Label *label) { 1.915 + cond = testUndefined(cond, address); 1.916 + j(cond, label); 1.917 + } 1.918 + void branchTestInt32(Condition cond, const BaseIndex &address, Label *label) { 1.919 + splitTag(address, ScratchReg); 1.920 + branchTestInt32(cond, ScratchReg, label); 1.921 + } 1.922 + void branchTestBoolean(Condition cond, const BaseIndex &address, Label *label) { 1.923 + splitTag(address, ScratchReg); 1.924 + branchTestBoolean(cond, ScratchReg, label); 1.925 + } 1.926 + void branchTestDouble(Condition cond, const BaseIndex &address, Label *label) { 1.927 + cond = testDouble(cond, address); 1.928 + j(cond, label); 1.929 + } 1.930 + void branchTestNull(Condition cond, const BaseIndex &address, Label *label) { 1.931 + cond = testNull(cond, address); 1.932 + j(cond, label); 1.933 + } 1.934 + void branchTestString(Condition cond, const BaseIndex &address, Label *label) { 1.935 + cond = testString(cond, address); 1.936 + j(cond, label); 1.937 + } 1.938 + void branchTestObject(Condition cond, const BaseIndex &address, Label *label) { 1.939 + cond = testObject(cond, address); 1.940 + j(cond, label); 1.941 + } 1.942 + 1.943 + template <typename T> 1.944 + void branchTestGCThing(Condition cond, const T &src, Label *label) { 1.945 + cond = testGCThing(cond, src); 1.946 + j(cond, label); 1.947 + } 1.948 + template <typename T> 1.949 + void branchTestPrimitive(Condition cond, const T &t, Label *label) { 1.950 + cond = testPrimitive(cond, t); 1.951 + j(cond, label); 1.952 + } 1.953 + template <typename T> 1.954 + void branchTestMagic(Condition cond, const T &t, Label *label) { 1.955 + cond = testMagic(cond, t); 1.956 + j(cond, label); 1.957 + } 1.958 + void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, 1.959 + Label *label) 1.960 + { 1.961 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.962 + // Test for magic 1.963 + Label notmagic; 1.964 + Condition testCond = testMagic(cond, val); 1.965 + j(InvertCondition(testCond), ¬magic); 1.966 + // Test magic value 1.967 + unboxMagic(val, ScratchReg); 1.968 + branch32(cond, ScratchReg, Imm32(static_cast<int32_t>(why)), label); 1.969 + bind(¬magic); 1.970 + } 1.971 + Condition testMagic(Condition cond, const ValueOperand &src) { 1.972 + splitTag(src, ScratchReg); 1.973 + return testMagic(cond, ScratchReg); 1.974 + } 1.975 + Condition testError(Condition cond, const ValueOperand &src) { 1.976 + return testMagic(cond, src); 1.977 + } 1.978 + void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label) { 1.979 + JS_ASSERT(value.valueReg() != ScratchReg); 1.980 + moveValue(v, ScratchReg); 1.981 + cmpq(value.valueReg(), ScratchReg); 1.982 + j(cond, label); 1.983 + } 1.984 + void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, 1.985 + Label *label) 1.986 + { 1.987 + JS_ASSERT(cond == Equal || cond == NotEqual); 1.988 + branchPtr(cond, valaddr, value.valueReg(), label); 1.989 + } 1.990 + 1.991 + void testNullSet(Condition cond, const ValueOperand &value, Register dest) { 1.992 + cond = testNull(cond, value); 1.993 + emitSet(cond, dest); 1.994 + } 1.995 + void testUndefinedSet(Condition cond, const ValueOperand &value, Register dest) { 1.996 + cond = testUndefined(cond, value); 1.997 + emitSet(cond, dest); 1.998 + } 1.999 + 1.1000 + void boxDouble(const FloatRegister &src, const ValueOperand &dest) { 1.1001 + movq(src, dest.valueReg()); 1.1002 + } 1.1003 + void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest) { 1.1004 + JS_ASSERT(src != dest.valueReg()); 1.1005 + boxValue(type, src, dest.valueReg()); 1.1006 + } 1.1007 + 1.1008 + // Note that the |dest| register here may be ScratchReg, so we shouldn't 1.1009 + // use it. 1.1010 + void unboxInt32(const ValueOperand &src, const Register &dest) { 1.1011 + movl(src.valueReg(), dest); 1.1012 + } 1.1013 + void unboxInt32(const Operand &src, const Register &dest) { 1.1014 + movl(src, dest); 1.1015 + } 1.1016 + void unboxInt32(const Address &src, const Register &dest) { 1.1017 + unboxInt32(Operand(src), dest); 1.1018 + } 1.1019 + void unboxDouble(const Address &src, const FloatRegister &dest) { 1.1020 + loadDouble(Operand(src), dest); 1.1021 + } 1.1022 + 1.1023 + void unboxArgObjMagic(const ValueOperand &src, const Register &dest) { 1.1024 + unboxArgObjMagic(Operand(src.valueReg()), dest); 1.1025 + } 1.1026 + void unboxArgObjMagic(const Operand &src, const Register &dest) { 1.1027 + mov(ImmWord(0), dest); 1.1028 + } 1.1029 + void unboxArgObjMagic(const Address &src, const Register &dest) { 1.1030 + unboxArgObjMagic(Operand(src), dest); 1.1031 + } 1.1032 + 1.1033 + void unboxBoolean(const ValueOperand &src, const Register &dest) { 1.1034 + movl(src.valueReg(), dest); 1.1035 + } 1.1036 + void unboxBoolean(const Operand &src, const Register &dest) { 1.1037 + movl(src, dest); 1.1038 + } 1.1039 + void unboxBoolean(const Address &src, const Register &dest) { 1.1040 + unboxBoolean(Operand(src), dest); 1.1041 + } 1.1042 + 1.1043 + void unboxMagic(const ValueOperand &src, const Register &dest) { 1.1044 + movl(src.valueReg(), dest); 1.1045 + } 1.1046 + 1.1047 + void unboxDouble(const ValueOperand &src, const FloatRegister &dest) { 1.1048 + movq(src.valueReg(), dest); 1.1049 + } 1.1050 + void unboxPrivate(const ValueOperand &src, const Register dest) { 1.1051 + movq(src.valueReg(), dest); 1.1052 + shlq(Imm32(1), dest); 1.1053 + } 1.1054 + 1.1055 + void notBoolean(const ValueOperand &val) { 1.1056 + xorq(Imm32(1), val.valueReg()); 1.1057 + } 1.1058 + 1.1059 + // Unbox any non-double value into dest. Prefer unboxInt32 or unboxBoolean 1.1060 + // instead if the source type is known. 1.1061 + void unboxNonDouble(const ValueOperand &src, const Register &dest) { 1.1062 + // In a non-trivial coupling, we're not permitted to use ScratchReg when 1.1063 + // src and dest are different registers, because of how extractObject is 1.1064 + // implemented. 1.1065 + if (src.valueReg() == dest) { 1.1066 + mov(ImmWord(JSVAL_PAYLOAD_MASK), ScratchReg); 1.1067 + andq(ScratchReg, dest); 1.1068 + } else { 1.1069 + mov(ImmWord(JSVAL_PAYLOAD_MASK), dest); 1.1070 + andq(src.valueReg(), dest); 1.1071 + } 1.1072 + } 1.1073 + void unboxNonDouble(const Operand &src, const Register &dest) { 1.1074 + // Explicitly permits |dest| to be used in |src|. 1.1075 + JS_ASSERT(dest != ScratchReg); 1.1076 + mov(ImmWord(JSVAL_PAYLOAD_MASK), ScratchReg); 1.1077 + movq(src, dest); 1.1078 + andq(ScratchReg, dest); 1.1079 + } 1.1080 + 1.1081 + void unboxString(const ValueOperand &src, const Register &dest) { unboxNonDouble(src, dest); } 1.1082 + void unboxString(const Operand &src, const Register &dest) { unboxNonDouble(src, dest); } 1.1083 + 1.1084 + void unboxObject(const ValueOperand &src, const Register &dest) { unboxNonDouble(src, dest); } 1.1085 + void unboxObject(const Operand &src, const Register &dest) { unboxNonDouble(src, dest); } 1.1086 + 1.1087 + // Extended unboxing API. If the payload is already in a register, returns 1.1088 + // that register. Otherwise, provides a move to the given scratch register, 1.1089 + // and returns that. 1.1090 + Register extractObject(const Address &address, Register scratch) { 1.1091 + JS_ASSERT(scratch != ScratchReg); 1.1092 + loadPtr(address, ScratchReg); 1.1093 + // We have a special coupling with unboxObject. As long as the registers 1.1094 + // aren't equal, it doesn't use ScratchReg. 1.1095 + unboxObject(ValueOperand(ScratchReg), scratch); 1.1096 + return scratch; 1.1097 + } 1.1098 + Register extractObject(const ValueOperand &value, Register scratch) { 1.1099 + JS_ASSERT(scratch != ScratchReg); 1.1100 + unboxObject(value, scratch); 1.1101 + return scratch; 1.1102 + } 1.1103 + Register extractInt32(const ValueOperand &value, Register scratch) { 1.1104 + JS_ASSERT(scratch != ScratchReg); 1.1105 + unboxInt32(value, scratch); 1.1106 + return scratch; 1.1107 + } 1.1108 + Register extractBoolean(const ValueOperand &value, Register scratch) { 1.1109 + JS_ASSERT(scratch != ScratchReg); 1.1110 + unboxBoolean(value, scratch); 1.1111 + return scratch; 1.1112 + } 1.1113 + Register extractTag(const Address &address, Register scratch) { 1.1114 + JS_ASSERT(scratch != ScratchReg); 1.1115 + loadPtr(address, scratch); 1.1116 + splitTag(scratch, scratch); 1.1117 + return scratch; 1.1118 + } 1.1119 + Register extractTag(const ValueOperand &value, Register scratch) { 1.1120 + JS_ASSERT(scratch != ScratchReg); 1.1121 + splitTag(value, scratch); 1.1122 + return scratch; 1.1123 + } 1.1124 + 1.1125 + void unboxValue(const ValueOperand &src, AnyRegister dest) { 1.1126 + if (dest.isFloat()) { 1.1127 + Label notInt32, end; 1.1128 + branchTestInt32(Assembler::NotEqual, src, ¬Int32); 1.1129 + convertInt32ToDouble(src.valueReg(), dest.fpu()); 1.1130 + jump(&end); 1.1131 + bind(¬Int32); 1.1132 + unboxDouble(src, dest.fpu()); 1.1133 + bind(&end); 1.1134 + } else { 1.1135 + unboxNonDouble(src, dest.gpr()); 1.1136 + } 1.1137 + } 1.1138 + 1.1139 + // These two functions use the low 32-bits of the full value register. 1.1140 + void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { 1.1141 + convertInt32ToDouble(operand.valueReg(), dest); 1.1142 + } 1.1143 + void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest) { 1.1144 + convertInt32ToDouble(operand.valueReg(), dest); 1.1145 + } 1.1146 + 1.1147 + void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { 1.1148 + convertInt32ToFloat32(operand.valueReg(), dest); 1.1149 + } 1.1150 + void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) { 1.1151 + convertInt32ToFloat32(operand.valueReg(), dest); 1.1152 + } 1.1153 + 1.1154 + void loadConstantDouble(double d, const FloatRegister &dest); 1.1155 + void loadConstantFloat32(float f, const FloatRegister &dest); 1.1156 + 1.1157 + void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) { 1.1158 + cvttsd2sq(src, dest); 1.1159 + 1.1160 + // cvttsd2sq returns 0x8000000000000000 on failure. Test for it by 1.1161 + // subtracting 1 and testing overflow (this avoids the need to 1.1162 + // materialize that value in a register). 1.1163 + cmpq(dest, Imm32(1)); 1.1164 + j(Assembler::Overflow, fail); 1.1165 + 1.1166 + movl(dest, dest); // Zero upper 32-bits. 1.1167 + } 1.1168 + void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail) { 1.1169 + cvttss2sq(src, dest); 1.1170 + 1.1171 + // Same trick as for Doubles 1.1172 + cmpq(dest, Imm32(1)); 1.1173 + j(Assembler::Overflow, fail); 1.1174 + 1.1175 + movl(dest, dest); // Zero upper 32-bits. 1.1176 + } 1.1177 + 1.1178 + Condition testInt32Truthy(bool truthy, const ValueOperand &operand) { 1.1179 + testl(operand.valueReg(), operand.valueReg()); 1.1180 + return truthy ? NonZero : Zero; 1.1181 + } 1.1182 + void branchTestInt32Truthy(bool truthy, const ValueOperand &operand, Label *label) { 1.1183 + Condition cond = testInt32Truthy(truthy, operand); 1.1184 + j(cond, label); 1.1185 + } 1.1186 + void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) { 1.1187 + testl(operand.valueReg(), operand.valueReg()); 1.1188 + j(truthy ? NonZero : Zero, label); 1.1189 + } 1.1190 + Condition testStringTruthy(bool truthy, const ValueOperand &value) { 1.1191 + unboxString(value, ScratchReg); 1.1192 + 1.1193 + Operand lengthAndFlags(ScratchReg, JSString::offsetOfLengthAndFlags()); 1.1194 + testq(lengthAndFlags, Imm32(-1 << JSString::LENGTH_SHIFT)); 1.1195 + return truthy ? Assembler::NonZero : Assembler::Zero; 1.1196 + } 1.1197 + void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) { 1.1198 + Condition cond = testStringTruthy(truthy, value); 1.1199 + j(cond, label); 1.1200 + } 1.1201 + 1.1202 + void loadInt32OrDouble(const Operand &operand, const FloatRegister &dest) { 1.1203 + Label notInt32, end; 1.1204 + branchTestInt32(Assembler::NotEqual, operand, ¬Int32); 1.1205 + convertInt32ToDouble(operand, dest); 1.1206 + jump(&end); 1.1207 + bind(¬Int32); 1.1208 + loadDouble(operand, dest); 1.1209 + bind(&end); 1.1210 + } 1.1211 + 1.1212 + template <typename T> 1.1213 + void loadUnboxedValue(const T &src, MIRType type, AnyRegister dest) { 1.1214 + if (dest.isFloat()) 1.1215 + loadInt32OrDouble(Operand(src), dest.fpu()); 1.1216 + else if (type == MIRType_Int32 || type == MIRType_Boolean) 1.1217 + movl(Operand(src), dest.gpr()); 1.1218 + else 1.1219 + unboxNonDouble(Operand(src), dest.gpr()); 1.1220 + } 1.1221 + 1.1222 + void loadInstructionPointerAfterCall(const Register &dest) { 1.1223 + loadPtr(Address(StackPointer, 0x0), dest); 1.1224 + } 1.1225 + 1.1226 + void convertUInt32ToDouble(const Register &src, const FloatRegister &dest) { 1.1227 + cvtsq2sd(src, dest); 1.1228 + } 1.1229 + 1.1230 + void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest) { 1.1231 + cvtsq2ss(src, dest); 1.1232 + } 1.1233 + 1.1234 + void inc64(AbsoluteAddress dest) { 1.1235 + if (JSC::X86Assembler::isAddressImmediate(dest.addr)) { 1.1236 + addPtr(Imm32(1), Operand(dest)); 1.1237 + } else { 1.1238 + mov(ImmPtr(dest.addr), ScratchReg); 1.1239 + addPtr(Imm32(1), Address(ScratchReg, 0)); 1.1240 + } 1.1241 + } 1.1242 + 1.1243 + // If source is a double, load it into dest. If source is int32, 1.1244 + // convert it to double. Else, branch to failure. 1.1245 + void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure) { 1.1246 + Label isDouble, done; 1.1247 + Register tag = splitTagForTest(source); 1.1248 + branchTestDouble(Assembler::Equal, tag, &isDouble); 1.1249 + branchTestInt32(Assembler::NotEqual, tag, failure); 1.1250 + 1.1251 + unboxInt32(source, ScratchReg); 1.1252 + convertInt32ToDouble(ScratchReg, dest); 1.1253 + jump(&done); 1.1254 + 1.1255 + bind(&isDouble); 1.1256 + unboxDouble(source, dest); 1.1257 + 1.1258 + bind(&done); 1.1259 + } 1.1260 + 1.1261 + // Setup a call to C/C++ code, given the number of general arguments it 1.1262 + // takes. Note that this only supports cdecl. 1.1263 + // 1.1264 + // In order for alignment to work correctly, the MacroAssembler must have a 1.1265 + // consistent view of the stack displacement. It is okay to call "push" 1.1266 + // manually, however, if the stack alignment were to change, the macro 1.1267 + // assembler should be notified before starting a call. 1.1268 + void setupAlignedABICall(uint32_t args); 1.1269 + 1.1270 + // Sets up an ABI call for when the alignment is not known. This may need a 1.1271 + // scratch register. 1.1272 + void setupUnalignedABICall(uint32_t args, const Register &scratch); 1.1273 + 1.1274 + // Arguments must be assigned to a C/C++ call in order. They are moved 1.1275 + // in parallel immediately before performing the call. This process may 1.1276 + // temporarily use more stack, in which case esp-relative addresses will be 1.1277 + // automatically adjusted. It is extremely important that esp-relative 1.1278 + // addresses are computed *after* setupABICall(). Furthermore, no 1.1279 + // operations should be emitted while setting arguments. 1.1280 + void passABIArg(const MoveOperand &from, MoveOp::Type type); 1.1281 + void passABIArg(const Register ®); 1.1282 + void passABIArg(const FloatRegister ®, MoveOp::Type type); 1.1283 + 1.1284 + private: 1.1285 + void callWithABIPre(uint32_t *stackAdjust); 1.1286 + void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); 1.1287 + 1.1288 + public: 1.1289 + // Emits a call to a C/C++ function, resolving all argument moves. 1.1290 + void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); 1.1291 + void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL); 1.1292 + void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL); 1.1293 + 1.1294 + void handleFailureWithHandler(void *handler); 1.1295 + void handleFailureWithHandlerTail(); 1.1296 + 1.1297 + void makeFrameDescriptor(Register frameSizeReg, FrameType type) { 1.1298 + shlq(Imm32(FRAMESIZE_SHIFT), frameSizeReg); 1.1299 + orq(Imm32(type), frameSizeReg); 1.1300 + } 1.1301 + 1.1302 + // Save an exit frame (which must be aligned to the stack pointer) to 1.1303 + // ThreadData::ionTop of the main thread. 1.1304 + void linkExitFrame() { 1.1305 + storePtr(StackPointer, 1.1306 + AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop())); 1.1307 + } 1.1308 + 1.1309 + void callWithExitFrame(JitCode *target, Register dynStack) { 1.1310 + addPtr(Imm32(framePushed()), dynStack); 1.1311 + makeFrameDescriptor(dynStack, JitFrame_IonJS); 1.1312 + Push(dynStack); 1.1313 + call(target); 1.1314 + } 1.1315 + 1.1316 + // Save an exit frame to the thread data of the current thread, given a 1.1317 + // register that holds a PerThreadData *. 1.1318 + void linkParallelExitFrame(const Register &pt) { 1.1319 + storePtr(StackPointer, Address(pt, offsetof(PerThreadData, ionTop))); 1.1320 + } 1.1321 + 1.1322 + // See CodeGeneratorX64 calls to noteAsmJSGlobalAccess. 1.1323 + void patchAsmJSGlobalAccess(CodeOffsetLabel patchAt, uint8_t *code, uint8_t *globalData, 1.1324 + unsigned globalDataOffset) 1.1325 + { 1.1326 + uint8_t *nextInsn = code + patchAt.offset(); 1.1327 + JS_ASSERT(nextInsn <= globalData); 1.1328 + uint8_t *target = globalData + globalDataOffset; 1.1329 + ((int32_t *)nextInsn)[-1] = target - nextInsn; 1.1330 + } 1.1331 + void memIntToValue(Address Source, Address Dest) { 1.1332 + load32(Source, ScratchReg); 1.1333 + storeValue(JSVAL_TYPE_INT32, ScratchReg, Dest); 1.1334 + } 1.1335 + 1.1336 +#ifdef JSGC_GENERATIONAL 1.1337 + void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); 1.1338 + void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); 1.1339 +#endif 1.1340 +}; 1.1341 + 1.1342 +typedef MacroAssemblerX64 MacroAssemblerSpecific; 1.1343 + 1.1344 +} // namespace jit 1.1345 +} // namespace js 1.1346 + 1.1347 +#endif /* jit_x64_MacroAssembler_x64_h */