PageRenderTime 52ms CodeModel.GetById 20ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 1ms

/js/src/methodjit/NunboxAssembler.h

http://github.com/zpao/v8monkey
C Header | 536 lines | 380 code | 66 blank | 90 comment | 46 complexity | bcfa4e3e8b54fbc49deb898c40954945 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 * vim: set ts=4 sw=4 et tw=99:
  3 *
  4 * ***** BEGIN LICENSE BLOCK *****
  5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6 *
  7 * The contents of this file are subject to the Mozilla Public License Version
  8 * 1.1 (the "License"); you may not use this file except in compliance with
  9 * the License. You may obtain a copy of the License at
 10 * http://www.mozilla.org/MPL/
 11 *
 12 * Software distributed under the License is distributed on an "AS IS" basis,
 13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 14 * for the specific language governing rights and limitations under the
 15 * License.
 16 *
 17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
 18 * May 28, 2008.
 19 *
 20 * The Initial Developer of the Original Code is
 21 *   Brendan Eich <brendan@mozilla.org>
 22 *
 23 * Contributor(s):
 24 *   David Anderson <danderson@mozilla.com>
 25 *   David Mandelin <dmandelin@mozilla.com>
 26 *
 27 * Alternatively, the contents of this file may be used under the terms of
 28 * either of the GNU General Public License Version 2 or later (the "GPL"),
 29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 30 * in which case the provisions of the GPL or the LGPL are applicable instead
 31 * of those above. If you wish to allow use of your version of this file only
 32 * under the terms of either the GPL or the LGPL, and not to allow others to
 33 * use your version of this file under the terms of the MPL, indicate your
 34 * decision by deleting the provisions above and replace them with the notice
 35 * and other provisions required by the GPL or the LGPL. If you do not delete
 36 * the provisions above, a recipient may use your version of this file under
 37 * the terms of any one of the MPL, the GPL or the LGPL.
 38 *
 39 * ***** END LICENSE BLOCK ***** */
 40
 41#if !defined jsjaeger_assembler_h__ && defined JS_METHODJIT && defined JS_NUNBOX32
 42#define jsjaeger_assembler_h__
 43
 44#include "assembler/assembler/MacroAssembler.h"
 45#include "methodjit/CodeGenIncludes.h"
 46#include "methodjit/RematInfo.h"
 47
 48namespace js {
 49namespace mjit {
 50
 51/* Don't use ImmTag. Use ImmType instead. */
 52struct ImmTag : JSC::MacroAssembler::Imm32
 53{
 54    ImmTag(JSValueTag mask)
 55      : Imm32(int32_t(mask))
 56    { }
 57};
 58
 59struct ImmType : ImmTag
 60{
 61    ImmType(JSValueType type)
 62      : ImmTag(JSVAL_TYPE_TO_TAG(type))
 63    {
 64        JS_ASSERT(type > JSVAL_TYPE_DOUBLE);
 65    }
 66};
 67
 68struct ImmPayload : JSC::MacroAssembler::Imm32
 69{
 70    ImmPayload(uint32_t payload)
 71      : Imm32(payload)
 72    { }
 73};
 74
 75class NunboxAssembler : public JSC::MacroAssembler
 76{
 77  public:
 78#ifdef IS_BIG_ENDIAN
 79    static const uint32_t PAYLOAD_OFFSET = 4;
 80    static const uint32_t TAG_OFFSET     = 0;
 81#else
 82    static const uint32_t PAYLOAD_OFFSET = 0;
 83    static const uint32_t TAG_OFFSET     = 4;
 84#endif
 85
 86  public:
 87    static const JSC::MacroAssembler::Scale JSVAL_SCALE = JSC::MacroAssembler::TimesEight;
 88
 89    Address payloadOf(Address address) {
 90        return Address(address.base, address.offset + PAYLOAD_OFFSET);
 91    }
 92  
 93    BaseIndex payloadOf(BaseIndex address) {
 94        return BaseIndex(address.base, address.index, address.scale, address.offset + PAYLOAD_OFFSET);
 95    }
 96
 97    Address tagOf(Address address) {
 98        return Address(address.base, address.offset + TAG_OFFSET);
 99    }
100
101    BaseIndex tagOf(BaseIndex address) {
102        return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
103    }
104
105    void loadInlineSlot(RegisterID objReg, uint32_t slot,
106                        RegisterID typeReg, RegisterID dataReg) {
107        Address address(objReg, JSObject::getFixedSlotOffset(slot));
108        if (objReg == typeReg) {
109            loadPayload(address, dataReg);
110            loadTypeTag(address, typeReg);
111        } else {
112            loadTypeTag(address, typeReg);
113            loadPayload(address, dataReg);
114        }
115    }
116
117    template <typename T>
118    void loadTypeTag(T address, RegisterID reg) {
119        load32(tagOf(address), reg);
120    }
121
122    template <typename T>
123    void storeTypeTag(ImmTag imm, T address) {
124        store32(imm, tagOf(address));
125    }
126
127    template <typename T>
128    void storeTypeTag(RegisterID reg, T address) {
129        store32(reg, tagOf(address));
130    }
131
132    template <typename T>
133    void loadPayload(T address, RegisterID reg) {
134        load32(payloadOf(address), reg);
135    }
136
137    template <typename T>
138    void storePayload(RegisterID reg, T address) {
139        store32(reg, payloadOf(address));
140    }
141
142    template <typename T>
143    void storePayload(ImmPayload imm, T address) {
144        store32(imm, payloadOf(address));
145    }
146
147    bool addressUsesRegister(BaseIndex address, RegisterID reg) {
148        return (address.base == reg) || (address.index == reg);
149    }
150
151    bool addressUsesRegister(Address address, RegisterID reg) {
152        return address.base == reg;
153    }
154
155    /* Loads type first, then payload, returning label after type load. */
156    template <typename T>
157    Label loadValueAsComponents(T address, RegisterID type, RegisterID payload) {
158        JS_ASSERT(!addressUsesRegister(address, type));
159        loadTypeTag(address, type);
160        Label l = label();
161        loadPayload(address, payload);
162        return l;
163    }
164
165    void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) {
166        jsval_layout jv = JSVAL_TO_IMPL(val);
167        move(ImmTag(jv.s.tag), type);
168        move(Imm32(jv.s.payload.u32), payload);
169    }
170
171    void loadValuePayload(const Value &val, RegisterID payload) {
172        jsval_layout jv = JSVAL_TO_IMPL(val);
173        move(Imm32(jv.s.payload.u32), payload);
174    }
175
176    /*
177     * Load a (64b) js::Value from 'address' into 'type' and 'payload', and
178     * return a label which can be used by
179     * ICRepatcher::patchAddressOffsetForValueLoad to patch the address'
180     * offset.
181     *
182     * The data register is guaranteed to be clobbered last. (This makes the
183     * base register for the address reusable as 'dreg'.)
184     */
185    Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) {
186        JS_ASSERT(address.base != treg); /* treg is clobbered first. */
187
188        Label start = label();
189#if defined JS_CPU_X86
190        /*
191         * On x86 there are two loads to patch and they both encode the offset
192         * in-line.
193         */
194        loadTypeTag(address, treg);
195        DBGLABEL_NOMASM(endType);
196        loadPayload(address, dreg);
197        DBGLABEL_NOMASM(endPayload);
198        JS_ASSERT(differenceBetween(start, endType) == 6);
199        JS_ASSERT(differenceBetween(endType, endPayload) == 6);
200        return start;
201#elif defined JS_CPU_ARM || defined JS_CPU_SPARC
202        /* 
203         * On ARM, the first instruction loads the offset from a literal pool, so the label
204         * returned points at that instruction.
205         */
206        DataLabel32 load = load64WithAddressOffsetPatch(address, treg, dreg);
207        JS_ASSERT(differenceBetween(start, load) == 0);
208        (void) load;
209        return start;
210#elif defined JS_CPU_MIPS
211        /*
212         * On MIPS there are LUI/ORI to patch.
213         */
214        load64WithPatch(address, treg, dreg, TAG_OFFSET, PAYLOAD_OFFSET);
215        return start;
216#endif
217    }
218
219    /*
220     * Store a (64b) js::Value from type |treg| and payload |dreg| into |address|, and
221     * return a label which can be used by
222     * ICRepatcher::patchAddressOffsetForValueStore to patch the address'
223     * offset.
224     */
225    DataLabel32 storeValueWithAddressOffsetPatch(RegisterID treg, RegisterID dreg, Address address) {
226        DataLabel32 start = dataLabel32();
227#if defined JS_CPU_X86
228        /*
229         * On x86 there are two stores to patch and they both encode the offset
230         * in-line.
231         */
232        storeTypeTag(treg, address);
233        DBGLABEL_NOMASM(endType);
234        storePayload(dreg, address);
235        DBGLABEL_NOMASM(endPayload);
236        JS_ASSERT(differenceBetween(start, endType) == 6);
237        JS_ASSERT(differenceBetween(endType, endPayload) == 6);
238        return start;
239#elif defined JS_CPU_ARM || defined JS_CPU_SPARC
240        return store64WithAddressOffsetPatch(treg, dreg, address);
241#elif defined JS_CPU_MIPS
242        /*
243         * On MIPS there are LUI/ORI to patch.
244         */
245        store64WithPatch(address, treg, dreg, TAG_OFFSET, PAYLOAD_OFFSET);
246        return start;
247#endif
248    }
249
250    /* Overloaded for storing a constant type. */
251    DataLabel32 storeValueWithAddressOffsetPatch(ImmType type, RegisterID dreg, Address address) {
252        DataLabel32 start = dataLabel32();
253#if defined JS_CPU_X86
254        storeTypeTag(type, address);
255        DBGLABEL_NOMASM(endType);
256        storePayload(dreg, address);
257        DBGLABEL_NOMASM(endPayload);
258        JS_ASSERT(differenceBetween(start, endType) == 10);
259        JS_ASSERT(differenceBetween(endType, endPayload) == 6);
260        return start;
261#elif defined JS_CPU_ARM || defined JS_CPU_SPARC
262        return store64WithAddressOffsetPatch(type, dreg, address);
263#elif defined JS_CPU_MIPS
264        /*
265         * On MIPS there are LUI/ORI to patch.
266         */
267        store64WithPatch(address, type, dreg, TAG_OFFSET, PAYLOAD_OFFSET);
268        return start;
269#endif
270    }
271
272    /* Overloaded for storing constant type and data. */
273    DataLabel32 storeValueWithAddressOffsetPatch(const Value &v, Address address) {
274        jsval_layout jv = JSVAL_TO_IMPL(v);
275        ImmTag type(jv.s.tag);
276        Imm32 payload(jv.s.payload.u32);
277        DataLabel32 start = dataLabel32();
278#if defined JS_CPU_X86
279        store32(type, tagOf(address));
280        DBGLABEL_NOMASM(endType);
281        store32(payload, payloadOf(address));
282        DBGLABEL_NOMASM(endPayload);
283        JS_ASSERT(differenceBetween(start, endType) == 10);
284        JS_ASSERT(differenceBetween(endType, endPayload) == 10);
285        return start;
286#elif defined JS_CPU_ARM || defined JS_CPU_SPARC
287        return store64WithAddressOffsetPatch(type, payload, address);
288#elif defined JS_CPU_MIPS
289        /*
290         * On MIPS there are LUI/ORI to patch.
291         */
292        store64WithPatch(address, type, payload, TAG_OFFSET, PAYLOAD_OFFSET);
293        return start;
294#endif
295    }
296
297    /* Overloaded for store with value remat info. */
298    DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
299        JS_ASSERT(!vr.isFPRegister());
300        if (vr.isConstant()) {
301            return storeValueWithAddressOffsetPatch(vr.value(), address);
302        } else if (vr.isTypeKnown()) {
303            ImmType type(vr.knownType());
304            RegisterID data(vr.dataReg());
305            return storeValueWithAddressOffsetPatch(type, data, address);
306        } else {
307            RegisterID type(vr.typeReg());
308            RegisterID data(vr.dataReg());
309            return storeValueWithAddressOffsetPatch(type, data, address);
310        }
311    }
312
313    /*
314     * Stores type first, then payload.
315     */
316    template <typename T>
317    Label storeValue(const Value &v, T address) {
318        jsval_layout jv = JSVAL_TO_IMPL(v);
319        store32(ImmTag(jv.s.tag), tagOf(address));
320        Label l = label();
321        store32(Imm32(jv.s.payload.u32), payloadOf(address));
322        return l;
323    }
324
325    template <typename T>
326    void storeValueFromComponents(RegisterID type, RegisterID payload, T address) {
327        storeTypeTag(type, address);
328        storePayload(payload, address);
329    }
330
331    template <typename T>
332    void storeValueFromComponents(ImmType type, RegisterID payload, T address) {
333        storeTypeTag(type, address);
334        storePayload(payload, address);
335    }
336
337    template <typename T>
338    Label storeValue(const ValueRemat &vr, T address) {
339        if (vr.isConstant()) {
340            return storeValue(vr.value(), address);
341        } else if (vr.isFPRegister()) {
342            Label l = label();
343            storeDouble(vr.fpReg(), address);
344            return l;
345        } else {
346            if (vr.isTypeKnown())
347                storeTypeTag(ImmType(vr.knownType()), address);
348            else
349                storeTypeTag(vr.typeReg(), address);
350            Label l = label();
351            storePayload(vr.dataReg(), address);
352            return l;
353        }
354    }
355
356    template <typename T>
357    Jump guardNotHole(T address) {
358        return branch32(Equal, tagOf(address), ImmType(JSVAL_TYPE_MAGIC));
359    }
360
361    void loadPrivate(Address privAddr, RegisterID to) {
362        loadPtr(payloadOf(privAddr), to);
363    }
364
365    void loadObjPrivate(RegisterID base, RegisterID to, uint32_t nfixed) {
366        Address priv(base, JSObject::getPrivateDataOffset(nfixed));
367        loadPtr(priv, to);
368    }
369
370    Jump testNull(Condition cond, RegisterID reg) {
371        return branch32(cond, reg, ImmTag(JSVAL_TAG_NULL));
372    }
373
374    Jump testNull(Condition cond, Address address) {
375        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_NULL));
376    }
377
378    Jump testUndefined(Condition cond, RegisterID reg) {
379        return branch32(cond, reg, ImmTag(JSVAL_TAG_UNDEFINED));
380    }
381
382    Jump testUndefined(Condition cond, Address address) {
383        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
384    }
385
386    Jump testInt32(Condition cond, RegisterID reg) {
387        return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
388    }
389
390    Jump testInt32(Condition cond, Address address) {
391        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
392    }
393
394    Jump testNumber(Condition cond, RegisterID reg) {
395        cond = (cond == Equal) ? BelowOrEqual : Above;
396        return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
397    }
398
399    Jump testNumber(Condition cond, Address address) {
400        cond = (cond == Equal) ? BelowOrEqual : Above;
401        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
402    }
403
404    Jump testPrimitive(Condition cond, RegisterID reg) {
405        cond = (cond == NotEqual) ? AboveOrEqual : Below;
406        return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
407    }
408
409    Jump testPrimitive(Condition cond, Address address) {
410        cond = (cond == NotEqual) ? AboveOrEqual : Below;
411        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
412    }
413
414    Jump testObject(Condition cond, RegisterID reg) {
415        return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
416    }
417
418    Jump testObject(Condition cond, Address address) {
419        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
420    }
421
422    Jump testGCThing(RegisterID reg) {
423        return branch32(AboveOrEqual, reg, ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
424    }
425
426    Jump testGCThing(Address address) {
427        return branch32(AboveOrEqual, tagOf(address), ImmTag(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
428    }
429
430    Jump testDouble(Condition cond, RegisterID reg) {
431        Condition opcond;
432        if (cond == Equal)
433            opcond = Below;
434        else
435            opcond = AboveOrEqual;
436        return branch32(opcond, reg, ImmTag(JSVAL_TAG_CLEAR));
437    }
438
439    Jump testDouble(Condition cond, Address address) {
440        Condition opcond;
441        if (cond == Equal)
442            opcond = Below;
443        else
444            opcond = AboveOrEqual;
445        return branch32(opcond, tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
446    }
447
448    Jump testBoolean(Condition cond, RegisterID reg) {
449        return branch32(cond, reg, ImmTag(JSVAL_TAG_BOOLEAN));
450    }
451
452    Jump testBoolean(Condition cond, Address address) {
453        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
454    }
455
456    Jump testString(Condition cond, RegisterID reg) {
457        return branch32(cond, reg, ImmTag(JSVAL_TAG_STRING));
458    }
459
460    Jump testString(Condition cond, Address address) {
461        return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_STRING));
462    }
463
464    void compareValue(Address one, Address two, RegisterID T0, RegisterID T1,
465                      Vector<Jump> *mismatches) {
466        loadValueAsComponents(one, T0, T1);
467        mismatches->append(branch32(NotEqual, T0, tagOf(two)));
468        mismatches->append(branch32(NotEqual, T1, payloadOf(two)));
469    }
470
471#ifdef JS_CPU_X86
472    void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) {
473        if (MacroAssemblerX86Common::getSSEState() >= HasSSE4_1) {
474            m_assembler.movd_rr(lo, fpReg);
475            m_assembler.pinsrd_rr(hi, fpReg);
476        } else {
477            m_assembler.movd_rr(lo, fpReg);
478            m_assembler.movd_rr(hi, Registers::FPConversionTemp);
479            m_assembler.unpcklps_rr(Registers::FPConversionTemp, fpReg);
480        }
481    }
482#endif
483
484    void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
485#ifdef JS_CPU_X86
486        // Move the low 32-bits of the 128-bit XMM register into dataReg.
487        // Then, right shift the 128-bit XMM register by 4 bytes.
488        // Finally, move the new low 32-bits of the 128-bit XMM register into typeReg.
489        m_assembler.movd_rr(srcDest, dataReg);
490        m_assembler.psrldq_rr(srcDest, 4);
491        m_assembler.movd_rr(srcDest, typeReg);
492#elif defined JS_CPU_SPARC
493        breakDoubleTo32(srcDest, typeReg, dataReg);
494#elif defined JS_CPU_ARM
495        // Yes, we are backwards from SPARC.
496        fastStoreDouble(srcDest, dataReg, typeReg);
497#elif defined JS_CPU_MIPS
498#if defined(IS_LITTLE_ENDIAN)
499        fastStoreDouble(srcDest, dataReg, typeReg);
500#else
501        fastStoreDouble(srcDest, typeReg, dataReg);
502#endif
503#else
504        JS_NOT_REACHED("implement this - push double, pop pop is easiest");
505#endif
506    }
507
508    void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) {
509        move(ImmPtr(dp), scratch);
510        loadDouble(Address(scratch), dest);
511    }
512
513    template <typename T>
514    Jump fastArrayLoadSlot(T address, bool holeCheck,
515                           MaybeRegisterID typeReg, RegisterID dataReg)
516    {
517        Jump notHole;
518        if (typeReg.isSet()) {
519            loadTypeTag(address, typeReg.reg());
520            if (holeCheck)
521                notHole = branch32(Equal, typeReg.reg(), ImmType(JSVAL_TYPE_MAGIC));
522        } else if (holeCheck) {
523            notHole = branch32(Equal, tagOf(address), ImmType(JSVAL_TYPE_MAGIC));
524        }
525        loadPayload(address, dataReg);
526        return notHole;
527    }
528};
529
530typedef NunboxAssembler ValueAssembler;
531
532} /* namespace mjit */
533} /* namespace js */
534
535#endif
536