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