js/src/jit/x64/MacroAssembler-x64.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.

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

mercurial