Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #ifndef JSInterfaceJIT_h
     27 #define JSInterfaceJIT_h
     28 
     29 #include "JITCode.h"
     30 #include "JITStubs.h"
     31 #include "JSValue.h"
     32 #include "MacroAssembler.h"
     33 #include "RegisterFile.h"
     34 #include <wtf/AlwaysInline.h>
     35 #include <wtf/Vector.h>
     36 
     37 namespace JSC {
     38     class JSInterfaceJIT : public MacroAssembler {
     39     public:
     40         // NOTES:
     41         //
     42         // regT0 has two special meanings.  The return value from a stub
     43         // call will always be in regT0, and by default (unless
     44         // a register is specified) emitPutVirtualRegister() will store
     45         // the value from regT0.
     46         //
     47         // regT3 is required to be callee-preserved.
     48         //
     49         // tempRegister2 is has no such dependencies.  It is important that
     50         // on x86/x86-64 it is ecx for performance reasons, since the
     51         // MacroAssembler will need to plant register swaps if it is not -
     52         // however the code will still function correctly.
     53 #if CPU(X86_64)
     54         static const RegisterID returnValueRegister = X86Registers::eax;
     55         static const RegisterID cachedResultRegister = X86Registers::eax;
     56         static const RegisterID firstArgumentRegister = X86Registers::edi;
     57 
     58         static const RegisterID timeoutCheckRegister = X86Registers::r12;
     59         static const RegisterID callFrameRegister = X86Registers::r13;
     60         static const RegisterID tagTypeNumberRegister = X86Registers::r14;
     61         static const RegisterID tagMaskRegister = X86Registers::r15;
     62 
     63         static const RegisterID regT0 = X86Registers::eax;
     64         static const RegisterID regT1 = X86Registers::edx;
     65         static const RegisterID regT2 = X86Registers::ecx;
     66         static const RegisterID regT3 = X86Registers::ebx;
     67 
     68         static const FPRegisterID fpRegT0 = X86Registers::xmm0;
     69         static const FPRegisterID fpRegT1 = X86Registers::xmm1;
     70         static const FPRegisterID fpRegT2 = X86Registers::xmm2;
     71         static const FPRegisterID fpRegT3 = X86Registers::xmm3;
     72 #elif CPU(X86)
     73         static const RegisterID returnValueRegister = X86Registers::eax;
     74         static const RegisterID cachedResultRegister = X86Registers::eax;
     75         // On x86 we always use fastcall conventions = but on
     76         // OS X if might make more sense to just use regparm.
     77         static const RegisterID firstArgumentRegister = X86Registers::ecx;
     78 
     79         static const RegisterID timeoutCheckRegister = X86Registers::esi;
     80         static const RegisterID callFrameRegister = X86Registers::edi;
     81 
     82         static const RegisterID regT0 = X86Registers::eax;
     83         static const RegisterID regT1 = X86Registers::edx;
     84         static const RegisterID regT2 = X86Registers::ecx;
     85         static const RegisterID regT3 = X86Registers::ebx;
     86 
     87         static const FPRegisterID fpRegT0 = X86Registers::xmm0;
     88         static const FPRegisterID fpRegT1 = X86Registers::xmm1;
     89         static const FPRegisterID fpRegT2 = X86Registers::xmm2;
     90         static const FPRegisterID fpRegT3 = X86Registers::xmm3;
     91 #elif CPU(ARM_THUMB2)
     92         static const RegisterID returnValueRegister = ARMRegisters::r0;
     93         static const RegisterID cachedResultRegister = ARMRegisters::r0;
     94         static const RegisterID firstArgumentRegister = ARMRegisters::r0;
     95 
     96         static const RegisterID regT0 = ARMRegisters::r0;
     97         static const RegisterID regT1 = ARMRegisters::r1;
     98         static const RegisterID regT2 = ARMRegisters::r2;
     99         static const RegisterID regT3 = ARMRegisters::r4;
    100 
    101         static const RegisterID callFrameRegister = ARMRegisters::r5;
    102         static const RegisterID timeoutCheckRegister = ARMRegisters::r6;
    103 
    104         static const FPRegisterID fpRegT0 = ARMRegisters::d0;
    105         static const FPRegisterID fpRegT1 = ARMRegisters::d1;
    106         static const FPRegisterID fpRegT2 = ARMRegisters::d2;
    107         static const FPRegisterID fpRegT3 = ARMRegisters::d3;
    108 #elif CPU(ARM_TRADITIONAL)
    109         static const RegisterID returnValueRegister = ARMRegisters::r0;
    110         static const RegisterID cachedResultRegister = ARMRegisters::r0;
    111         static const RegisterID firstArgumentRegister = ARMRegisters::r0;
    112 
    113         static const RegisterID timeoutCheckRegister = ARMRegisters::r5;
    114         static const RegisterID callFrameRegister = ARMRegisters::r4;
    115 
    116         static const RegisterID regT0 = ARMRegisters::r0;
    117         static const RegisterID regT1 = ARMRegisters::r1;
    118         static const RegisterID regT2 = ARMRegisters::r2;
    119         // Callee preserved
    120         static const RegisterID regT3 = ARMRegisters::r7;
    121 
    122         static const RegisterID regS0 = ARMRegisters::S0;
    123         // Callee preserved
    124         static const RegisterID regS1 = ARMRegisters::S1;
    125 
    126         static const RegisterID regStackPtr = ARMRegisters::sp;
    127         static const RegisterID regLink = ARMRegisters::lr;
    128 
    129         static const FPRegisterID fpRegT0 = ARMRegisters::d0;
    130         static const FPRegisterID fpRegT1 = ARMRegisters::d1;
    131         static const FPRegisterID fpRegT2 = ARMRegisters::d2;
    132         static const FPRegisterID fpRegT3 = ARMRegisters::d3;
    133 #elif CPU(MIPS)
    134         static const RegisterID returnValueRegister = MIPSRegisters::v0;
    135         static const RegisterID cachedResultRegister = MIPSRegisters::v0;
    136         static const RegisterID firstArgumentRegister = MIPSRegisters::a0;
    137 
    138         // regT0 must be v0 for returning a 32-bit value.
    139         static const RegisterID regT0 = MIPSRegisters::v0;
    140 
    141         // regT1 must be v1 for returning a pair of 32-bit value.
    142         static const RegisterID regT1 = MIPSRegisters::v1;
    143 
    144         static const RegisterID regT2 = MIPSRegisters::t4;
    145 
    146         // regT3 must be saved in the callee, so use an S register.
    147         static const RegisterID regT3 = MIPSRegisters::s2;
    148 
    149         static const RegisterID callFrameRegister = MIPSRegisters::s0;
    150         static const RegisterID timeoutCheckRegister = MIPSRegisters::s1;
    151 
    152         static const FPRegisterID fpRegT0 = MIPSRegisters::f4;
    153         static const FPRegisterID fpRegT1 = MIPSRegisters::f6;
    154         static const FPRegisterID fpRegT2 = MIPSRegisters::f8;
    155         static const FPRegisterID fpRegT3 = MIPSRegisters::f10;
    156 #elif CPU(SH4)
    157         static const RegisterID timeoutCheckRegister = SH4Registers::r8;
    158         static const RegisterID callFrameRegister = SH4Registers::fp;
    159 
    160         static const RegisterID regT0 = SH4Registers::r0;
    161         static const RegisterID regT1 = SH4Registers::r1;
    162         static const RegisterID regT2 = SH4Registers::r2;
    163         static const RegisterID regT3 = SH4Registers::r10;
    164         static const RegisterID regT4 = SH4Registers::r4;
    165         static const RegisterID regT5 = SH4Registers::r5;
    166         static const RegisterID regT6 = SH4Registers::r6;
    167         static const RegisterID regT7 = SH4Registers::r7;
    168         static const RegisterID firstArgumentRegister =regT4;
    169 
    170         static const RegisterID returnValueRegister = SH4Registers::r0;
    171         static const RegisterID cachedResultRegister = SH4Registers::r0;
    172 
    173         static const FPRegisterID fpRegT0  = SH4Registers::fr0;
    174         static const FPRegisterID fpRegT1  = SH4Registers::fr2;
    175         static const FPRegisterID fpRegT2  = SH4Registers::fr4;
    176         static const FPRegisterID fpRegT3  = SH4Registers::fr6;
    177         static const FPRegisterID fpRegT4  = SH4Registers::fr8;
    178         static const FPRegisterID fpRegT5  = SH4Registers::fr10;
    179         static const FPRegisterID fpRegT6  = SH4Registers::fr12;
    180         static const FPRegisterID fpRegT7  = SH4Registers::fr14;
    181 #else
    182 #error "JIT not supported on this platform."
    183 #endif
    184 
    185 #if USE(JSVALUE32_64)
    186         // Can't just propogate JSValue::Int32Tag as visual studio doesn't like it
    187         static const unsigned Int32Tag = 0xffffffff;
    188         COMPILE_ASSERT(Int32Tag == JSValue::Int32Tag, Int32Tag_out_of_sync);
    189 #else
    190         static const unsigned Int32Tag = TagTypeNumber >> 32;
    191 #endif
    192         inline Jump emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload);
    193         inline Jump emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst);
    194         inline Jump emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch);
    195 
    196         inline void storePtrWithWriteBarrier(TrustedImmPtr ptr, RegisterID /* owner */, Address dest)
    197         {
    198             storePtr(ptr, dest);
    199         }
    200 
    201 #if USE(JSVALUE32_64)
    202         inline Jump emitJumpIfNotJSCell(unsigned virtualRegisterIndex);
    203         inline Address tagFor(int index, RegisterID base = callFrameRegister);
    204 #endif
    205 
    206 #if USE(JSVALUE64)
    207         Jump emitJumpIfImmediateNumber(RegisterID reg);
    208         Jump emitJumpIfNotImmediateNumber(RegisterID reg);
    209         void emitFastArithImmToInt(RegisterID reg);
    210 #endif
    211 
    212         inline Address payloadFor(int index, RegisterID base = callFrameRegister);
    213         inline Address intPayloadFor(int index, RegisterID base = callFrameRegister);
    214         inline Address intTagFor(int index, RegisterID base = callFrameRegister);
    215         inline Address addressFor(int index, RegisterID base = callFrameRegister);
    216     };
    217 
    218     struct ThunkHelpers {
    219         static unsigned stringImplDataOffset() { return StringImpl::dataOffset(); }
    220         static unsigned jsStringLengthOffset() { return OBJECT_OFFSETOF(JSString, m_length); }
    221         static unsigned jsStringValueOffset() { return OBJECT_OFFSETOF(JSString, m_value); }
    222     };
    223 
    224 #if USE(JSVALUE32_64)
    225     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID payload)
    226     {
    227         loadPtr(payloadFor(virtualRegisterIndex), payload);
    228         return emitJumpIfNotJSCell(virtualRegisterIndex);
    229     }
    230 
    231     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotJSCell(unsigned virtualRegisterIndex)
    232     {
    233         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
    234         return branch32(NotEqual, tagFor(virtualRegisterIndex), TrustedImm32(JSValue::CellTag));
    235     }
    236 
    237     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
    238     {
    239         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
    240         loadPtr(payloadFor(virtualRegisterIndex), dst);
    241         return branch32(NotEqual, tagFor(static_cast<int>(virtualRegisterIndex)), TrustedImm32(JSValue::Int32Tag));
    242     }
    243 
    244     inline JSInterfaceJIT::Address JSInterfaceJIT::tagFor(int virtualRegisterIndex, RegisterID base)
    245     {
    246         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    247         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
    248     }
    249 
    250     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
    251     {
    252         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    253         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
    254     }
    255 
    256     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
    257     {
    258         return payloadFor(virtualRegisterIndex, base);
    259     }
    260 
    261     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
    262     {
    263         return tagFor(virtualRegisterIndex, base);
    264     }
    265 
    266     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
    267     {
    268         ASSERT(static_cast<int>(virtualRegisterIndex) < FirstConstantRegisterIndex);
    269         loadPtr(tagFor(virtualRegisterIndex), scratch);
    270         Jump isDouble = branch32(Below, scratch, TrustedImm32(JSValue::LowestTag));
    271         Jump notInt = branch32(NotEqual, scratch, TrustedImm32(JSValue::Int32Tag));
    272         loadPtr(payloadFor(virtualRegisterIndex), scratch);
    273         convertInt32ToDouble(scratch, dst);
    274         Jump done = jump();
    275         isDouble.link(this);
    276         loadDouble(addressFor(virtualRegisterIndex), dst);
    277         done.link(this);
    278         return notInt;
    279     }
    280 #endif
    281 
    282 #if USE(JSVALUE64)
    283     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfImmediateNumber(RegisterID reg)
    284     {
    285         return branchTestPtr(NonZero, reg, tagTypeNumberRegister);
    286     }
    287     ALWAYS_INLINE JSInterfaceJIT::Jump JSInterfaceJIT::emitJumpIfNotImmediateNumber(RegisterID reg)
    288     {
    289         return branchTestPtr(Zero, reg, tagTypeNumberRegister);
    290     }
    291     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadJSCell(unsigned virtualRegisterIndex, RegisterID dst)
    292     {
    293         loadPtr(addressFor(virtualRegisterIndex), dst);
    294         return branchTestPtr(NonZero, dst, tagMaskRegister);
    295     }
    296 
    297     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadInt32(unsigned virtualRegisterIndex, RegisterID dst)
    298     {
    299         loadPtr(addressFor(virtualRegisterIndex), dst);
    300         Jump result = branchPtr(Below, dst, tagTypeNumberRegister);
    301         zeroExtend32ToPtr(dst, dst);
    302         return result;
    303     }
    304 
    305     inline JSInterfaceJIT::Jump JSInterfaceJIT::emitLoadDouble(unsigned virtualRegisterIndex, FPRegisterID dst, RegisterID scratch)
    306     {
    307         loadPtr(addressFor(virtualRegisterIndex), scratch);
    308         Jump notNumber = emitJumpIfNotImmediateNumber(scratch);
    309         Jump notInt = branchPtr(Below, scratch, tagTypeNumberRegister);
    310         convertInt32ToDouble(scratch, dst);
    311         Jump done = jump();
    312         notInt.link(this);
    313         addPtr(tagTypeNumberRegister, scratch);
    314         movePtrToDouble(scratch, dst);
    315         done.link(this);
    316         return notNumber;
    317     }
    318 
    319     ALWAYS_INLINE void JSInterfaceJIT::emitFastArithImmToInt(RegisterID)
    320     {
    321     }
    322 
    323 #endif
    324 
    325 #if USE(JSVALUE64)
    326     inline JSInterfaceJIT::Address JSInterfaceJIT::payloadFor(int virtualRegisterIndex, RegisterID base)
    327     {
    328         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    329         return addressFor(virtualRegisterIndex, base);
    330     }
    331 
    332     inline JSInterfaceJIT::Address JSInterfaceJIT::intPayloadFor(int virtualRegisterIndex, RegisterID base)
    333     {
    334         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    335         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload));
    336     }
    337     inline JSInterfaceJIT::Address JSInterfaceJIT::intTagFor(int virtualRegisterIndex, RegisterID base)
    338     {
    339         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    340         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag));
    341     }
    342 #endif
    343 
    344     inline JSInterfaceJIT::Address JSInterfaceJIT::addressFor(int virtualRegisterIndex, RegisterID base)
    345     {
    346         ASSERT(virtualRegisterIndex < FirstConstantRegisterIndex);
    347         return Address(base, (static_cast<unsigned>(virtualRegisterIndex) * sizeof(Register)));
    348     }
    349 
    350 }
    351 
    352 #endif // JSInterfaceJIT_h
    353