Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / NunboxAssembler.h
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
48 namespace js {
49 namespace mjit {
50
51 /* Don't use ImmTag. Use ImmType instead. */
52 struct ImmTag : JSC::MacroAssembler::Imm32
53 {
54     ImmTag(JSValueTag mask)
55       : Imm32(int32(mask))
56     { }
57 };
58
59 struct ImmType : ImmTag
60 {
61     ImmType(JSValueType type)
62       : ImmTag(JSVAL_TYPE_TO_TAG(type))
63     { }
64 };
65
66 struct ImmPayload : JSC::MacroAssembler::Imm32
67 {
68     ImmPayload(uint32 payload)
69       : Imm32(payload)
70     { }
71 };
72
73 class NunboxAssembler : public JSC::MacroAssembler
74 {
75     static const uint32 PAYLOAD_OFFSET = 0;
76     static const uint32 TAG_OFFSET     = 4;
77
78   public:
79     static const JSC::MacroAssembler::Scale JSVAL_SCALE = JSC::MacroAssembler::TimesEight;
80
81     template <typename T>
82     T payloadOf(T address) {
83         JS_ASSERT(PAYLOAD_OFFSET == 0);
84         return address;
85     }
86
87     Address tagOf(Address address) {
88         return Address(address.base, address.offset + TAG_OFFSET);
89     }
90
91     BaseIndex tagOf(BaseIndex address) {
92         return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
93     }
94
95     void loadInlineSlot(RegisterID objReg, uint32 slot,
96                         RegisterID typeReg, RegisterID dataReg) {
97         Address address(objReg, JSObject::getFixedSlotOffset(slot));
98         if (objReg == typeReg) {
99             loadPayload(address, dataReg);
100             loadTypeTag(address, typeReg);
101         } else {
102             loadTypeTag(address, typeReg);
103             loadPayload(address, dataReg);
104         }
105     }
106
107     template <typename T>
108     void loadTypeTag(T address, RegisterID reg) {
109         load32(tagOf(address), reg);
110     }
111
112     template <typename T>
113     void storeTypeTag(ImmTag imm, T address) {
114         store32(imm, tagOf(address));
115     }
116
117     template <typename T>
118     void storeTypeTag(RegisterID reg, T address) {
119         store32(reg, tagOf(address));
120     }
121
122     template <typename T>
123     void loadPayload(T address, RegisterID reg) {
124         load32(payloadOf(address), reg);
125     }
126
127     template <typename T>
128     void storePayload(RegisterID reg, T address) {
129         store32(reg, payloadOf(address));
130     }
131
132     template <typename T>
133     void storePayload(ImmPayload imm, T address) {
134         store32(imm, payloadOf(address));
135     }
136
137     bool addressUsesRegister(BaseIndex address, RegisterID reg) {
138         return (address.base == reg) || (address.index == reg);
139     }
140
141     bool addressUsesRegister(Address address, RegisterID reg) {
142         return address.base == reg;
143     }
144
145     /* Loads type first, then payload, returning label after type load. */
146     template <typename T>
147     Label loadValueAsComponents(T address, RegisterID type, RegisterID payload) {
148         JS_ASSERT(!addressUsesRegister(address, type));
149         loadTypeTag(address, type);
150         Label l = label();
151         loadPayload(address, payload);
152         return l;
153     }
154
155     void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) {
156         jsval_layout jv;
157         jv.asBits = JSVAL_BITS(Jsvalify(val));
158
159         move(ImmTag(jv.s.tag), type);
160         move(Imm32(jv.s.payload.u32), payload);
161     }
162
163     /*
164      * Load a (64b) js::Value from 'address' into 'type' and 'payload', and
165      * return a label which can be used by
166      * ICRepatcher::patchAddressOffsetForValueLoad to patch the address'
167      * offset.
168      *
169      * The data register is guaranteed to be clobbered last. (This makes the
170      * base register for the address reusable as 'dreg'.)
171      */
172     Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) {
173         JS_ASSERT(address.base != treg); /* treg is clobbered first. */
174
175         Label start = label();
176 #if defined JS_CPU_X86
177         /*
178          * On x86 there are two loads to patch and they both encode the offset
179          * in-line.
180          */
181         loadTypeTag(address, treg);
182         DBGLABEL_NOMASM(endType);
183         loadPayload(address, dreg);
184         DBGLABEL_NOMASM(endPayload);
185         JS_ASSERT(differenceBetween(start, endType) == 6);
186         JS_ASSERT(differenceBetween(endType, endPayload) == 6);
187         return start;
188 #elif defined JS_CPU_ARM
189         /* 
190          * On ARM, the first instruction loads the offset from a literal pool, so the label
191          * returned points at that instruction.
192          */
193         DataLabel32 load = load64WithAddressOffsetPatch(address, treg, dreg);
194         JS_ASSERT(differenceBetween(start, load) == 0);
195         (void) load;
196         return start;
197 #endif
198     }
199
200     /*
201      * Store a (64b) js::Value from type |treg| and payload |dreg| into |address|, and
202      * return a label which can be used by
203      * ICRepatcher::patchAddressOffsetForValueStore to patch the address'
204      * offset.
205      */
206     DataLabel32 storeValueWithAddressOffsetPatch(RegisterID treg, RegisterID dreg, Address address) {
207         DataLabel32 start = dataLabel32();
208 #if defined JS_CPU_X86
209         /*
210          * On x86 there are two stores to patch and they both encode the offset
211          * in-line.
212          */
213         storeTypeTag(treg, address);
214         DBGLABEL_NOMASM(endType);
215         storePayload(dreg, address);
216         DBGLABEL_NOMASM(endPayload);
217         JS_ASSERT(differenceBetween(start, endType) == 6);
218         JS_ASSERT(differenceBetween(endType, endPayload) == 6);
219         return start;
220 #elif defined JS_CPU_ARM
221         return store64WithAddressOffsetPatch(treg, dreg, address);
222 #endif
223     }
224
225     /* Overloaded for storing a constant type. */
226     DataLabel32 storeValueWithAddressOffsetPatch(ImmType type, RegisterID dreg, Address address) {
227         DataLabel32 start = dataLabel32();
228 #if defined JS_CPU_X86
229         storeTypeTag(type, address);
230         DBGLABEL_NOMASM(endType);
231         storePayload(dreg, address);
232         DBGLABEL_NOMASM(endPayload);
233         JS_ASSERT(differenceBetween(start, endType) == 10);
234         JS_ASSERT(differenceBetween(endType, endPayload) == 6);
235         return start;
236 #elif defined JS_CPU_ARM
237         return store64WithAddressOffsetPatch(type, dreg, address);
238 #endif
239     }
240
241     /* Overloaded for storing constant type and data. */
242     DataLabel32 storeValueWithAddressOffsetPatch(const Value &v, Address address) {
243         jsval_layout jv;
244         jv.asBits = JSVAL_BITS(Jsvalify(v));
245         ImmTag type(jv.s.tag);
246         Imm32 payload(jv.s.payload.u32);
247         DataLabel32 start = dataLabel32();
248 #if defined JS_CPU_X86
249         store32(type, tagOf(address));
250         DBGLABEL_NOMASM(endType);
251         store32(payload, payloadOf(address));
252         DBGLABEL_NOMASM(endPayload);
253         JS_ASSERT(differenceBetween(start, endType) == 10);
254         JS_ASSERT(differenceBetween(endType, endPayload) == 10);
255         return start;
256 #elif defined JS_CPU_ARM
257         return store64WithAddressOffsetPatch(type, payload, address);
258 #endif
259     }
260
261     /* Overloaded for store with value remat info. */
262     DataLabel32 storeValueWithAddressOffsetPatch(const ValueRemat &vr, Address address) {
263         if (vr.isConstant()) {
264             return storeValueWithAddressOffsetPatch(vr.value(), address);
265         } else if (vr.isTypeKnown()) {
266             ImmType type(vr.knownType());
267             RegisterID data(vr.dataReg());
268             return storeValueWithAddressOffsetPatch(type, data, address);
269         } else {
270             RegisterID type(vr.typeReg());
271             RegisterID data(vr.dataReg());
272             return storeValueWithAddressOffsetPatch(type, data, address);
273         }
274     }
275
276     /*
277      * Stores type first, then payload.
278      */
279     template <typename T>
280     Label storeValue(const Value &v, T address) {
281         jsval_layout jv;
282         jv.asBits = JSVAL_BITS(Jsvalify(v));
283
284         store32(ImmTag(jv.s.tag), tagOf(address));
285         Label l = label();
286         store32(Imm32(jv.s.payload.u32), payloadOf(address));
287         return l;
288     }
289
290     template <typename T>
291     void storeValueFromComponents(RegisterID type, RegisterID payload, T address) {
292         storeTypeTag(type, address);
293         storePayload(payload, address);
294     }
295
296     template <typename T>
297     void storeValueFromComponents(ImmType type, RegisterID payload, T address) {
298         storeTypeTag(type, address);
299         storePayload(payload, address);
300     }
301
302     template <typename T>
303     Label storeValue(const ValueRemat &vr, T address) {
304         if (vr.isConstant()) {
305             return storeValue(vr.value(), address);
306         } else {
307             if (vr.isTypeKnown())
308                 storeTypeTag(ImmType(vr.knownType()), address);
309             else
310                 storeTypeTag(vr.typeReg(), address);
311             Label l = label();
312             storePayload(vr.dataReg(), address);
313             return l;
314         }
315     }
316
317     template <typename T>
318     Jump guardNotHole(T address) {
319         return branch32(Equal, tagOf(address), ImmType(JSVAL_TYPE_MAGIC));
320     }
321
322     void loadPrivate(Address privAddr, RegisterID to) {
323         loadPtr(privAddr, to);
324     }
325
326     void loadObjPrivate(RegisterID base, RegisterID to) {
327         Address priv(base, offsetof(JSObject, privateData));
328         loadPtr(priv, to);
329     }
330
331     Jump testNull(Condition cond, RegisterID reg) {
332         return branch32(cond, reg, ImmTag(JSVAL_TAG_NULL));
333     }
334
335     Jump testNull(Condition cond, Address address) {
336         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_NULL));
337     }
338
339     Jump testUndefined(Condition cond, RegisterID reg) {
340         return branch32(cond, reg, ImmTag(JSVAL_TAG_UNDEFINED));
341     }
342
343     Jump testUndefined(Condition cond, Address address) {
344         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
345     }
346
347     Jump testInt32(Condition cond, RegisterID reg) {
348         return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
349     }
350
351     Jump testInt32(Condition cond, Address address) {
352         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
353     }
354
355     Jump testNumber(Condition cond, RegisterID reg) {
356         cond = (cond == Equal) ? BelowOrEqual : Above;
357         return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
358     }
359
360     Jump testNumber(Condition cond, Address address) {
361         cond = (cond == Equal) ? BelowOrEqual : Above;
362         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
363     }
364
365     Jump testPrimitive(Condition cond, RegisterID reg) {
366         cond = (cond == NotEqual) ? AboveOrEqual : Below;
367         return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
368     }
369
370     Jump testPrimitive(Condition cond, Address address) {
371         cond = (cond == NotEqual) ? AboveOrEqual : Below;
372         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
373     }
374
375     Jump testObject(Condition cond, RegisterID reg) {
376         return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
377     }
378
379     Jump testObject(Condition cond, Address address) {
380         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
381     }
382
383     Jump testDouble(Condition cond, RegisterID reg) {
384         Condition opcond;
385         if (cond == Equal)
386             opcond = Below;
387         else
388             opcond = AboveOrEqual;
389         return branch32(opcond, reg, ImmTag(JSVAL_TAG_CLEAR));
390     }
391
392     Jump testDouble(Condition cond, Address address) {
393         Condition opcond;
394         if (cond == Equal)
395             opcond = Below;
396         else
397             opcond = AboveOrEqual;
398         return branch32(opcond, tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
399     }
400
401     Jump testBoolean(Condition cond, RegisterID reg) {
402         return branch32(cond, reg, ImmTag(JSVAL_TAG_BOOLEAN));
403     }
404
405     Jump testBoolean(Condition cond, Address address) {
406         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
407     }
408
409     Jump testString(Condition cond, RegisterID reg) {
410         return branch32(cond, reg, ImmTag(JSVAL_TAG_STRING));
411     }
412
413     Jump testString(Condition cond, Address address) {
414         return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_STRING));
415     }
416
417 #ifdef JS_CPU_X86
418     void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) {
419         if (MacroAssemblerX86Common::getSSEState() >= HasSSE4_1) {
420             m_assembler.movd_rr(lo, fpReg);
421             m_assembler.pinsrd_rr(hi, fpReg);
422         } else {
423             m_assembler.movd_rr(lo, fpReg);
424             m_assembler.movd_rr(hi, FPRegisters::Temp0);
425             m_assembler.unpcklps_rr(FPRegisters::Temp0, fpReg);
426         }
427     }
428 #endif
429
430     void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
431 #ifdef JS_CPU_X86
432         // Move the low 32-bits of the 128-bit XMM register into dataReg.
433         // Then, right shift the 128-bit XMM register by 4 bytes.
434         // Finally, move the new low 32-bits of the 128-bit XMM register into typeReg.
435         m_assembler.movd_rr(srcDest, dataReg);
436         m_assembler.psrldq_rr(srcDest, 4);
437         m_assembler.movd_rr(srcDest, typeReg);
438 #else
439         JS_NOT_REACHED("implement this - push double, pop pop is easiest");
440 #endif
441     }
442
443     void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) {
444         move(ImmPtr(dp), scratch);
445         loadDouble(Address(scratch), dest);
446     }
447
448     template <typename T>
449     Jump fastArrayLoadSlot(T address, RegisterID typeReg, RegisterID dataReg) {
450         loadTypeTag(address, typeReg);
451         Jump notHole = branch32(Equal, typeReg, ImmType(JSVAL_TYPE_MAGIC));
452         loadPayload(address, dataReg);
453         return notHole;
454     }
455 };
456
457 typedef NunboxAssembler ValueAssembler;
458
459 } /* namespace mjit */
460 } /* namespace js */
461
462 #endif
463