1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
24 * David Anderson <danderson@mozilla.com>
25 * David Mandelin <dmandelin@mozilla.com>
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.
39 * ***** END LICENSE BLOCK ***** */
41 #if !defined jsjaeger_assembler_h__ && defined JS_METHODJIT && defined JS_NUNBOX32
42 #define jsjaeger_assembler_h__
44 #include "assembler/assembler/MacroAssembler.h"
45 #include "methodjit/CodeGenIncludes.h"
46 #include "methodjit/RematInfo.h"
51 /* Don't use ImmTag. Use ImmType instead. */
52 struct ImmTag : JSC::MacroAssembler::Imm32
54 ImmTag(JSValueTag mask)
59 struct ImmType : ImmTag
61 ImmType(JSValueType type)
62 : ImmTag(JSVAL_TYPE_TO_TAG(type))
66 struct ImmPayload : JSC::MacroAssembler::Imm32
68 ImmPayload(uint32 payload)
73 class NunboxAssembler : public JSC::MacroAssembler
75 static const uint32 PAYLOAD_OFFSET = 0;
76 static const uint32 TAG_OFFSET = 4;
79 static const JSC::MacroAssembler::Scale JSVAL_SCALE = JSC::MacroAssembler::TimesEight;
82 T payloadOf(T address) {
83 JS_ASSERT(PAYLOAD_OFFSET == 0);
87 Address tagOf(Address address) {
88 return Address(address.base, address.offset + TAG_OFFSET);
91 BaseIndex tagOf(BaseIndex address) {
92 return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
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);
102 loadTypeTag(address, typeReg);
103 loadPayload(address, dataReg);
107 template <typename T>
108 void loadTypeTag(T address, RegisterID reg) {
109 load32(tagOf(address), reg);
112 template <typename T>
113 void storeTypeTag(ImmTag imm, T address) {
114 store32(imm, tagOf(address));
117 template <typename T>
118 void storeTypeTag(RegisterID reg, T address) {
119 store32(reg, tagOf(address));
122 template <typename T>
123 void loadPayload(T address, RegisterID reg) {
124 load32(payloadOf(address), reg);
127 template <typename T>
128 void storePayload(RegisterID reg, T address) {
129 store32(reg, payloadOf(address));
132 template <typename T>
133 void storePayload(ImmPayload imm, T address) {
134 store32(imm, payloadOf(address));
137 bool addressUsesRegister(BaseIndex address, RegisterID reg) {
138 return (address.base == reg) || (address.index == reg);
141 bool addressUsesRegister(Address address, RegisterID reg) {
142 return address.base == reg;
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);
151 loadPayload(address, payload);
155 void loadValueAsComponents(const Value &val, RegisterID type, RegisterID payload) {
157 jv.asBits = JSVAL_BITS(Jsvalify(val));
159 move(ImmTag(jv.s.tag), type);
160 move(Imm32(jv.s.payload.u32), payload);
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'
169 * The data register is guaranteed to be clobbered last. (This makes the
170 * base register for the address reusable as 'dreg'.)
172 Label loadValueWithAddressOffsetPatch(Address address, RegisterID treg, RegisterID dreg) {
173 JS_ASSERT(address.base != treg); /* treg is clobbered first. */
175 Label start = label();
176 #if defined JS_CPU_X86
178 * On x86 there are two loads to patch and they both encode the offset
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);
188 #elif defined JS_CPU_ARM
190 * On ARM, the first instruction loads the offset from a literal pool, so the label
191 * returned points at that instruction.
193 DataLabel32 load = load64WithAddressOffsetPatch(address, treg, dreg);
194 JS_ASSERT(differenceBetween(start, load) == 0);
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'
206 DataLabel32 storeValueWithAddressOffsetPatch(RegisterID treg, RegisterID dreg, Address address) {
207 DataLabel32 start = dataLabel32();
208 #if defined JS_CPU_X86
210 * On x86 there are two stores to patch and they both encode the offset
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);
220 #elif defined JS_CPU_ARM
221 return store64WithAddressOffsetPatch(treg, dreg, address);
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);
236 #elif defined JS_CPU_ARM
237 return store64WithAddressOffsetPatch(type, dreg, address);
241 /* Overloaded for storing constant type and data. */
242 DataLabel32 storeValueWithAddressOffsetPatch(const Value &v, Address address) {
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);
256 #elif defined JS_CPU_ARM
257 return store64WithAddressOffsetPatch(type, payload, address);
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);
270 RegisterID type(vr.typeReg());
271 RegisterID data(vr.dataReg());
272 return storeValueWithAddressOffsetPatch(type, data, address);
277 * Stores type first, then payload.
279 template <typename T>
280 Label storeValue(const Value &v, T address) {
282 jv.asBits = JSVAL_BITS(Jsvalify(v));
284 store32(ImmTag(jv.s.tag), tagOf(address));
286 store32(Imm32(jv.s.payload.u32), payloadOf(address));
290 template <typename T>
291 void storeValueFromComponents(RegisterID type, RegisterID payload, T address) {
292 storeTypeTag(type, address);
293 storePayload(payload, address);
296 template <typename T>
297 void storeValueFromComponents(ImmType type, RegisterID payload, T address) {
298 storeTypeTag(type, address);
299 storePayload(payload, address);
302 template <typename T>
303 Label storeValue(const ValueRemat &vr, T address) {
304 if (vr.isConstant()) {
305 return storeValue(vr.value(), address);
307 if (vr.isTypeKnown())
308 storeTypeTag(ImmType(vr.knownType()), address);
310 storeTypeTag(vr.typeReg(), address);
312 storePayload(vr.dataReg(), address);
317 template <typename T>
318 Jump guardNotHole(T address) {
319 return branch32(Equal, tagOf(address), ImmType(JSVAL_TYPE_MAGIC));
322 void loadPrivate(Address privAddr, RegisterID to) {
323 loadPtr(privAddr, to);
326 void loadObjPrivate(RegisterID base, RegisterID to) {
327 Address priv(base, offsetof(JSObject, privateData));
331 Jump testNull(Condition cond, RegisterID reg) {
332 return branch32(cond, reg, ImmTag(JSVAL_TAG_NULL));
335 Jump testNull(Condition cond, Address address) {
336 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_NULL));
339 Jump testUndefined(Condition cond, RegisterID reg) {
340 return branch32(cond, reg, ImmTag(JSVAL_TAG_UNDEFINED));
343 Jump testUndefined(Condition cond, Address address) {
344 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_UNDEFINED));
347 Jump testInt32(Condition cond, RegisterID reg) {
348 return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
351 Jump testInt32(Condition cond, Address address) {
352 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
355 Jump testNumber(Condition cond, RegisterID reg) {
356 cond = (cond == Equal) ? BelowOrEqual : Above;
357 return branch32(cond, reg, ImmTag(JSVAL_TAG_INT32));
360 Jump testNumber(Condition cond, Address address) {
361 cond = (cond == Equal) ? BelowOrEqual : Above;
362 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_INT32));
365 Jump testPrimitive(Condition cond, RegisterID reg) {
366 cond = (cond == NotEqual) ? AboveOrEqual : Below;
367 return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
370 Jump testPrimitive(Condition cond, Address address) {
371 cond = (cond == NotEqual) ? AboveOrEqual : Below;
372 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
375 Jump testObject(Condition cond, RegisterID reg) {
376 return branch32(cond, reg, ImmTag(JSVAL_TAG_OBJECT));
379 Jump testObject(Condition cond, Address address) {
380 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_OBJECT));
383 Jump testDouble(Condition cond, RegisterID reg) {
388 opcond = AboveOrEqual;
389 return branch32(opcond, reg, ImmTag(JSVAL_TAG_CLEAR));
392 Jump testDouble(Condition cond, Address address) {
397 opcond = AboveOrEqual;
398 return branch32(opcond, tagOf(address), ImmTag(JSVAL_TAG_CLEAR));
401 Jump testBoolean(Condition cond, RegisterID reg) {
402 return branch32(cond, reg, ImmTag(JSVAL_TAG_BOOLEAN));
405 Jump testBoolean(Condition cond, Address address) {
406 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_BOOLEAN));
409 Jump testString(Condition cond, RegisterID reg) {
410 return branch32(cond, reg, ImmTag(JSVAL_TAG_STRING));
413 Jump testString(Condition cond, Address address) {
414 return branch32(cond, tagOf(address), ImmTag(JSVAL_TAG_STRING));
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);
423 m_assembler.movd_rr(lo, fpReg);
424 m_assembler.movd_rr(hi, FPRegisters::Temp0);
425 m_assembler.unpcklps_rr(FPRegisters::Temp0, fpReg);
430 void breakDouble(FPRegisterID srcDest, RegisterID typeReg, RegisterID dataReg) {
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);
439 JS_NOT_REACHED("implement this - push double, pop pop is easiest");
443 void loadStaticDouble(const double *dp, FPRegisterID dest, RegisterID scratch) {
444 move(ImmPtr(dp), scratch);
445 loadDouble(Address(scratch), dest);
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);
457 typedef NunboxAssembler ValueAssembler;
459 } /* namespace mjit */