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

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

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

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial