Opnd.h 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. class Value;
  7. namespace IR {
  8. class IntConstOpnd;
  9. class Int64ConstOpnd;
  10. class FloatConstOpnd;
  11. class Simd128ConstOpnd;
  12. class HelperCallOpnd;
  13. class SymOpnd;
  14. class PropertySymOpnd;
  15. class RegOpnd;
  16. class ArrayRegOpnd;
  17. class AddrOpnd;
  18. class IndirOpnd;
  19. class LabelOpnd;
  20. class MemRefOpnd;
  21. class RegBVOpnd;
  22. enum OpndKind : BYTE {
  23. OpndKindInvalid,
  24. OpndKindIntConst,
  25. OpndKindInt64Const,
  26. OpndKindFloatConst,
  27. OpndKindSimd128Const,
  28. OpndKindHelperCall,
  29. OpndKindSym,
  30. OpndKindReg,
  31. OpndKindAddr,
  32. OpndKindIndir,
  33. OpndKindLabel,
  34. OpndKindMemRef,
  35. OpndKindRegBV
  36. };
  37. enum AddrOpndKind : BYTE {
  38. // The following address kinds are safe for relocatable JIT and regular
  39. // JIT
  40. AddrOpndKindConstantAddress,
  41. AddrOpndKindConstantVar, // a constant var value (null or tagged int)
  42. // NOTE: None of the following address kinds should be generated directly
  43. // or you WILL break relocatable JIT code. Each kind has a helper that
  44. // will generate correct code for relocatable code & non-relocatable code.
  45. // The only exception is places where it is KNOWN that we will never
  46. // generate the code in relocatable JIT.
  47. // use LoadScriptContextOpnd
  48. AddrOpndKindDynamicScriptContext,
  49. // use LoadVTableValueOpnd
  50. AddrOpndKindDynamicVtable,
  51. // use LoadLibraryValueOpnd
  52. AddrOpndKindDynamicCharStringCache,
  53. // use appropriate helper
  54. AddrOpndKindDynamicMisc,
  55. // no profiling in dynamic JIT
  56. AddrOpndKindDynamicFunctionBody,
  57. AddrOpndKindDynamicFunctionInfo,
  58. // use LoadRuntimeInlineCacheOpnd for runtime caches,
  59. // in relocatable JIT polymorphic inline caches aren't generated and can
  60. // be referenced directly (for now)
  61. AddrOpndKindDynamicInlineCache,
  62. // no bailouts in dynamic JIT
  63. AddrOpndKindDynamicBailOutRecord,
  64. // use appropriate helper
  65. AddrOpndKindDynamicVar,
  66. AddrOpndKindDynamicType,
  67. AddrOpndKindDynamicTypeHandler,
  68. AddrOpndKindDynamicFrameDisplay,
  69. AddrOpndKindDynamicGuardValueRef,
  70. AddrOpndKindDynamicArrayCallSiteInfo,
  71. AddrOpndKindDynamicFunctionBodyWeakRef,
  72. AddrOpndKindDynamicObjectTypeRef,
  73. AddrOpndKindDynamicTypeCheckGuard,
  74. AddrOpndKindDynamicRecyclerAllocatorEndAddressRef,
  75. AddrOpndKindDynamicRecyclerAllocatorFreeListRef,
  76. AddrOpndKindDynamicBailOutKindRef,
  77. AddrOpndKindDynamicAuxSlotArrayRef,
  78. AddrOpndKindDynamicPropertySlotRef,
  79. AddrOpndKindDynamicFunctionEnvironmentRef,
  80. AddrOpndKindDynamicIsInstInlineCacheFunctionRef,
  81. AddrOpndKindDynamicIsInstInlineCacheTypeRef,
  82. AddrOpndKindDynamicIsInstInlineCacheResultRef,
  83. AddrOpndKindSz,
  84. AddrOpndKindDynamicFloatRef,
  85. AddrOpndKindDynamicDoubleRef,
  86. AddrOpndKindDynamicNativeCodeDataRef,
  87. AddrOpndKindDynamicAuxBufferRef,
  88. AddrOpndKindForInCache,
  89. AddrOpndKindForInCacheType,
  90. AddrOpndKindForInCacheData,
  91. AddrOpndKindWriteBarrierCardTable,
  92. };
  93. ///---------------------------------------------------------------------------
  94. ///
  95. /// class Opnd
  96. ///
  97. /// IntConstOpnd ; int values
  98. /// FLoatConstOpnd ; float values
  99. /// HelperCallOpnd ; lib helper address (more convenient dumps than AddrOpnd)
  100. /// SymOpnd ; stack symbol operand (not enregistered)
  101. /// RegOpnd ; register operand
  102. /// AddrOpnd ; address or var operand (includes TaggedInt's)
  103. /// IndirOpnd ; indirections operand (also used for JS array references)
  104. /// LabelOpnd ; label operand
  105. /// MemRefOpnd ; direct memory reference at a given memory address.
  106. /// RegBVOpnd ; unsigned int bit field used to denote a bit field vector. Example: Registers to push in STM.
  107. ///
  108. ///---------------------------------------------------------------------------
  109. class Opnd
  110. {
  111. protected:
  112. Opnd() :
  113. m_inUse(false),
  114. m_isDead(false),
  115. m_isValueTypeFixed(false),
  116. canStoreTemp(false),
  117. isDiagHelperCallOpnd(false),
  118. isPropertySymOpnd(false)
  119. {
  120. #if DBG
  121. isFakeDst = false;
  122. isDeleted = false;
  123. #endif
  124. m_kind = (OpndKind)0;
  125. }
  126. Opnd(const Opnd& oldOpnd) :
  127. m_type(oldOpnd.m_type),
  128. m_isDead(false),
  129. m_inUse(false),
  130. m_isValueTypeFixed(false),
  131. canStoreTemp(oldOpnd.canStoreTemp)
  132. {
  133. #if DBG
  134. isFakeDst = false;
  135. isDeleted = false;
  136. #endif
  137. m_kind = oldOpnd.m_kind;
  138. // We will set isDeleted bit on a freed Opnd, this should not overlap with the next field of BVSparseNode
  139. // because BVSparseNode* are used to maintain freelist of memory of BVSparseNode size
  140. #if DBG
  141. typedef BVSparseNode<JitArenaAllocator> BVSparseNode;
  142. CompileAssert(
  143. offsetof(Opnd, isDeleted) > offsetof(BVSparseNode, next) + sizeof(BVSparseNode*) ||
  144. offsetof(Opnd, isDeleted) < offsetof(BVSparseNode, next) + sizeof(BVSparseNode*));
  145. #endif
  146. }
  147. public:
  148. bool IsConstOpnd() const;
  149. bool IsImmediateOpnd() const;
  150. bool IsMemoryOpnd() const;
  151. bool IsIntConstOpnd() const;
  152. IntConstOpnd * AsIntConstOpnd();
  153. const IntConstOpnd* AsIntConstOpnd() const;
  154. bool IsInt64ConstOpnd() const;
  155. Int64ConstOpnd * AsInt64ConstOpnd();
  156. const Int64ConstOpnd * AsInt64ConstOpnd() const;
  157. bool IsFloatConstOpnd() const;
  158. FloatConstOpnd * AsFloatConstOpnd();
  159. const FloatConstOpnd * AsFloatConstOpnd() const;
  160. bool IsSimd128ConstOpnd() const;
  161. Simd128ConstOpnd * AsSimd128ConstOpnd();
  162. const Simd128ConstOpnd * AsSimd128ConstOpnd() const;
  163. bool IsHelperCallOpnd() const;
  164. HelperCallOpnd * AsHelperCallOpnd();
  165. const HelperCallOpnd * AsHelperCallOpnd() const;
  166. bool IsSymOpnd() const;
  167. SymOpnd * AsSymOpnd();
  168. const SymOpnd * AsSymOpnd() const;
  169. PropertySymOpnd * AsPropertySymOpnd();
  170. const PropertySymOpnd * AsPropertySymOpnd() const;
  171. bool IsRegOpnd() const;
  172. RegOpnd * AsRegOpnd();
  173. const RegOpnd * AsRegOpnd() const;
  174. bool IsAddrOpnd() const;
  175. AddrOpnd * AsAddrOpnd();
  176. const AddrOpnd * AsAddrOpnd() const;
  177. bool IsIndirOpnd() const;
  178. IndirOpnd * AsIndirOpnd();
  179. const IndirOpnd * AsIndirOpnd() const;
  180. bool IsLabelOpnd() const;
  181. LabelOpnd * AsLabelOpnd();
  182. const LabelOpnd * AsLabelOpnd() const;
  183. bool IsMemRefOpnd() const;
  184. MemRefOpnd * AsMemRefOpnd();
  185. const MemRefOpnd * AsMemRefOpnd() const;
  186. bool IsRegBVOpnd() const;
  187. RegBVOpnd * AsRegBVOpnd();
  188. const RegBVOpnd * AsRegBVOpnd() const;
  189. OpndKind GetKind() const;
  190. Opnd * Copy(Func *func);
  191. Opnd * CloneDef(Func *func);
  192. Opnd * CloneUse(Func *func);
  193. StackSym * GetStackSym() const;
  194. Sym * GetSym() const;
  195. Opnd * UseWithNewType(IRType type, Func * func);
  196. bool IsEqual(Opnd *opnd);
  197. void Free(Func * func);
  198. bool IsInUse() const { return m_inUse; }
  199. Opnd * Use(Func * func);
  200. void UnUse();
  201. IRType GetType() const { return this->m_type; }
  202. void SetType(IRType type) { this->m_type = type; }
  203. bool IsSigned() const { return IRType_IsSignedInt(this->m_type); }
  204. bool IsUnsigned() const { return IRType_IsUnsignedInt(this->m_type); }
  205. int GetSize() const { return TySize[this->m_type]; }
  206. bool IsInt64() const { return IRType_IsInt64(this->m_type); }
  207. bool IsInt32() const { return this->m_type == TyInt32; }
  208. bool IsUInt32() const { return this->m_type == TyUint32; }
  209. bool IsFloat32() const { return this->m_type == TyFloat32; }
  210. bool IsFloat64() const { return this->m_type == TyFloat64; }
  211. bool IsFloat() const { return this->IsFloat32() || this->IsFloat64(); }
  212. bool IsSimd128() const { return IRType_IsSimd128(this->m_type); }
  213. bool IsSimd128F4() const { return this->m_type == TySimd128F4; }
  214. bool IsSimd128I4() const { return this->m_type == TySimd128I4; }
  215. bool IsSimd128I8() const { return this->m_type == TySimd128I8; }
  216. bool IsSimd128I16() const { return this->m_type == TySimd128I16; }
  217. bool IsSimd128U4() const { return this->m_type == TySimd128U4; }
  218. bool IsSimd128U8() const { return this->m_type == TySimd128U8; }
  219. bool IsSimd128U16() const { return this->m_type == TySimd128U16; }
  220. bool IsSimd128B4() const { return this->m_type == TySimd128B4; }
  221. bool IsSimd128B8() const { return this->m_type == TySimd128B8; }
  222. bool IsSimd128B16() const { return this->m_type == TySimd128B16; }
  223. bool IsSimd128D2() const { return this->m_type == TySimd128D2; }
  224. bool IsVar() const { return this->m_type == TyVar; }
  225. bool IsTaggedInt() const;
  226. bool IsTaggedValue() const;
  227. bool IsNotNumber() const;
  228. bool IsNotInt() const;
  229. bool IsNotTaggedValue() const;
  230. bool IsWriteBarrierTriggerableValue();
  231. void SetIsDead(const bool isDead = true) { this->m_isDead = isDead; }
  232. bool GetIsDead() { return this->m_isDead; }
  233. int64 GetImmediateValue(Func * func);
  234. #if TARGET_32 && !defined(_M_IX86)
  235. // Helper for 32bits systems without int64 const operand support
  236. int32 GetImmediateValueAsInt32(Func * func);
  237. #endif
  238. BailoutConstantValue GetConstValue();
  239. bool GetIsJITOptimizedReg() const { return m_isJITOptimizedReg; }
  240. void SetIsJITOptimizedReg(bool value) { Assert(!value || !this->IsIndirOpnd()); m_isJITOptimizedReg = value; }
  241. ValueType GetValueType() const { return m_valueType; }
  242. void SetValueType(const ValueType valueType);
  243. ValueType FindProfiledValueType();
  244. bool IsScopeObjOpnd(Func * func);
  245. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  246. virtual void DummyFunction() {} // Note needed for the VS debugger to disambiguate the different classes.
  247. void DumpValueType();
  248. static void DumpValueType(const ValueType valueType);
  249. #endif
  250. bool IsValueTypeFixed() const { return m_isValueTypeFixed; }
  251. void SetValueTypeFixed() { m_isValueTypeFixed = true; }
  252. IR::RegOpnd * FindRegUse(IR::RegOpnd *regOpnd);
  253. bool IsArgumentsObject();
  254. static IntConstOpnd *CreateUint32Opnd(const uint i, Func *const func);
  255. static IntConstOpnd *CreateProfileIdOpnd(const Js::ProfileId profileId, Func *const func);
  256. static IntConstOpnd *CreateInlineCacheIndexOpnd(const Js::InlineCacheIndex inlineCacheIndex, Func *const func);
  257. static RegOpnd *CreateFramePointerOpnd(Func *const func);
  258. public:
  259. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  260. static void DumpAddress(void *address, bool printToConsole, bool skipMaskedAddress);
  261. static void DumpFunctionInfo(_Outptr_result_buffer_(*count) char16 ** buffer, size_t * count, Js::FunctionInfo * info, bool printToConsole, _In_opt_z_ char16 const * type = nullptr);
  262. void Dump(IRDumpFlags flags, Func *func);
  263. void DumpOpndKindAddr(bool AsmDumpMode, Func *func);
  264. void DumpOpndKindMemRef(bool AsmDumpMode, Func *func);
  265. static void WriteToBuffer(_Outptr_result_buffer_(*count) char16 **buffer, size_t *count, const char16 *fmt, ...);
  266. void GetAddrDescription(__out_ecount(count) char16 *const description, const size_t count, bool AsmDumpMode,
  267. bool printToConsole, Func *func);
  268. static void GetAddrDescription(__out_ecount(count) char16 *const description, const size_t count,
  269. void * address, IR::AddrOpndKind addressKind, bool AsmDumpMode, bool printToConsole, Func *func, bool skipMaskedAddress = false);
  270. void Dump();
  271. #endif
  272. bool CanStoreTemp() const { return canStoreTemp; }
  273. void SetCanStoreTemp() { Assert(this->IsSymOpnd() || this->IsIndirOpnd()); canStoreTemp = true; }
  274. protected:
  275. ValueType m_valueType;
  276. IRType m_type;
  277. // If true, it was deemed that the value type is definite (not likely) and shouldn't be changed. This is used for NewScArray
  278. // and the store-element instructions that follow it.
  279. bool m_isValueTypeFixed:1;
  280. bool m_inUse:1;
  281. bool m_isDead:1;
  282. // This def/use of a byte code sym is not in the original byte code, don't count them in the bailout
  283. bool m_isJITOptimizedReg:1;
  284. // For SymOpnd, this bit applies to the object pointer stack sym
  285. // For IndirOpnd, this bit applies to the base operand
  286. // If this opnd is a dst, that means that the object pointer is a stack object,
  287. // and we can store temp object/number on it
  288. // If the opnd is a src, that means that the object pointer may be a stack object
  289. // so the load may be a temp object/number and we need to track its use
  290. bool canStoreTemp : 1;
  291. bool isDiagHelperCallOpnd : 1;
  292. bool isPropertySymOpnd : 1;
  293. public:
  294. #if DBG
  295. bool isFakeDst : 1;
  296. #endif
  297. OpndKind m_kind;
  298. #ifdef DBG
  299. public:
  300. bool isDeleted;
  301. #endif
  302. };
  303. template<typename ConstType>
  304. class EncodableOpnd
  305. {
  306. protected:
  307. ConstType m_value;
  308. public:
  309. ConstType GetValue() const { return m_value; }
  310. void SetEncodedValue(ConstType encodedValue)
  311. {
  312. #if DBG_DUMP
  313. decodedValue = m_value;
  314. #endif
  315. m_value = encodedValue;
  316. }
  317. #if DBG_DUMP
  318. void SetName(const char16* name) { this->name = name; }
  319. void DumpEncodable() const;
  320. private:
  321. ConstType decodedValue = 0;
  322. const char16* name = nullptr;
  323. static const char16* fmt;
  324. #endif
  325. };
  326. ///---------------------------------------------------------------------------
  327. ///
  328. /// class IntConstOpnd
  329. ///
  330. ///---------------------------------------------------------------------------
  331. class IntConstOpnd sealed : public Opnd, public EncodableOpnd<IntConstType>
  332. {
  333. public:
  334. static IntConstOpnd * New(IntConstType value, IRType type, Func *func, bool dontEncode = false);
  335. static IR::Opnd* NewFromType(int64 value, IRType type, Func* func);
  336. public:
  337. //Note: type OpndKindIntConst
  338. IntConstOpnd * CopyInternal(Func *func);
  339. bool IsEqualInternal(Opnd *opnd);
  340. void FreeInternal(Func * func) ;
  341. public:
  342. bool m_dontEncode; // Setting this to true turns off XOR encoding for this constant. Only set this on
  343. // constants not controllable by the user.
  344. void IncrValue(IntConstType by)
  345. {
  346. SetValue(m_value + by);
  347. }
  348. void DecrValue(IntConstType by)
  349. {
  350. SetValue(m_value - by);
  351. }
  352. void SetValue(IntConstType value);
  353. int32 AsInt32();
  354. uint32 AsUint32();
  355. };
  356. ///---------------------------------------------------------------------------
  357. ///
  358. /// class Int64ConstOpnd
  359. ///
  360. ///---------------------------------------------------------------------------
  361. class Int64ConstOpnd sealed : public Opnd, public EncodableOpnd<int64>
  362. {
  363. public:
  364. static Int64ConstOpnd* New(int64 value, IRType type, Func *func);
  365. public:
  366. Int64ConstOpnd* CopyInternal(Func *func);
  367. bool IsEqualInternal(Opnd *opnd);
  368. void FreeInternal(Func * func) ;
  369. };
  370. ///---------------------------------------------------------------------------
  371. ///
  372. /// class FloatConstOpnd
  373. ///
  374. ///---------------------------------------------------------------------------
  375. class FloatConstOpnd: public Opnd
  376. {
  377. public:
  378. static FloatConstOpnd * New(FloatConstType value, IRType type, Func *func);
  379. static FloatConstOpnd * New(Js::Var floatVar, IRType type, Func *func, Js::Var varLocal = nullptr);
  380. public:
  381. //Note: type OpndKindFloatConst
  382. FloatConstOpnd *CopyInternal(Func *func);
  383. bool IsEqualInternal(Opnd *opnd);
  384. void FreeInternal(Func * func);
  385. AddrOpnd *GetAddrOpnd(Func *func, bool dontEncode = false);
  386. public:
  387. FloatConstType m_value;
  388. protected:
  389. #if !FLOATVAR
  390. Js::Var m_number;
  391. Js::JavascriptNumber *m_numberCopy;
  392. #endif
  393. };
  394. class Simd128ConstOpnd sealed : public Opnd
  395. {
  396. public:
  397. static Simd128ConstOpnd * New(AsmJsSIMDValue value, IRType type, Func *func);
  398. public:
  399. Simd128ConstOpnd * CopyInternal(Func *func);
  400. bool IsEqualInternal(Opnd *opnd);
  401. void FreeInternal(Func * func);
  402. public:
  403. AsmJsSIMDValue m_value;
  404. };
  405. ///---------------------------------------------------------------------------
  406. ///
  407. /// class HelperCallOpnd
  408. ///
  409. ///---------------------------------------------------------------------------
  410. class HelperCallOpnd: public Opnd
  411. {
  412. public:
  413. static HelperCallOpnd * New(JnHelperMethod fnHelper, Func *func);
  414. protected:
  415. void Init(JnHelperMethod fnHelper);
  416. public:
  417. //Note type : OpndKindHelperCall
  418. HelperCallOpnd *CopyInternal(Func *func);
  419. bool IsEqualInternal(Opnd *opnd);
  420. void FreeInternal(Func * func);
  421. bool IsDiagHelperCallOpnd() const
  422. {
  423. Assert(this->DbgIsDiagHelperCallOpnd() == isDiagHelperCallOpnd);
  424. return isDiagHelperCallOpnd;
  425. }
  426. public:
  427. JnHelperMethod m_fnHelper;
  428. #if DBG
  429. private:
  430. virtual bool DbgIsDiagHelperCallOpnd() const { return false; }
  431. #endif
  432. };
  433. ///---------------------------------------------------------------------------
  434. ///
  435. /// class DiagHelperCallOpnd
  436. /// Used in debug mode (Fast F12) for wrapping original helper method with try-catch wrapper.
  437. ///
  438. ///---------------------------------------------------------------------------
  439. class DiagHelperCallOpnd: public HelperCallOpnd
  440. {
  441. public:
  442. static DiagHelperCallOpnd * New(JnHelperMethod fnHelper, Func *func, int argCount);
  443. public:
  444. DiagHelperCallOpnd *CopyInternalSub(Func *func);
  445. bool IsEqualInternalSub(Opnd *opnd);
  446. public:
  447. int m_argCount;
  448. #if DBG
  449. private:
  450. virtual bool DbgIsDiagHelperCallOpnd() const override { return true; }
  451. #endif
  452. };
  453. ///---------------------------------------------------------------------------
  454. ///
  455. /// class SymOpnd
  456. ///
  457. ///---------------------------------------------------------------------------
  458. class SymOpnd: public Opnd
  459. {
  460. public:
  461. static SymOpnd * New(Sym *sym, IRType type, Func *func);
  462. static SymOpnd * New(Sym *sym, uint32 offset, IRType type, Func *func);
  463. public:
  464. // Note type: OpndKindSym
  465. SymOpnd * CopyInternal(Func *func);
  466. SymOpnd * CloneDefInternal(Func *func);
  467. SymOpnd * CloneUseInternal(Func *func);
  468. StackSym * GetStackSymInternal() const;
  469. bool IsEqualInternal(Opnd *opnd);
  470. void FreeInternal(Func * func);
  471. bool IsPropertySymOpnd() const
  472. {
  473. Assert(this->DbgIsPropertySymOpnd() == this->isPropertySymOpnd);
  474. return isPropertySymOpnd;
  475. }
  476. public:
  477. Sym * m_sym;
  478. uint32 m_offset;
  479. private:
  480. #if DBG
  481. virtual bool DbgIsPropertySymOpnd() const { return false; }
  482. #endif
  483. private:
  484. ValueType propertyOwnerValueType;
  485. public:
  486. ValueType GetPropertyOwnerValueType() const
  487. {
  488. return propertyOwnerValueType;
  489. }
  490. void SetPropertyOwnerValueType(const ValueType valueType)
  491. {
  492. propertyOwnerValueType = valueType;
  493. }
  494. RegOpnd *CreatePropertyOwnerOpnd(Func *const func) const;
  495. };
  496. class PropertySymOpnd sealed : public SymOpnd
  497. {
  498. protected:
  499. PropertySymOpnd() : SymOpnd() {}
  500. PropertySymOpnd(SymOpnd* symOpnd) : SymOpnd(*symOpnd) {}
  501. public:
  502. static PropertySymOpnd * New(PropertySym *propertySym, uint inlineCacheIndex, IRType type, Func *func);
  503. public:
  504. PropertySymOpnd * CopyCommon(Func *func);
  505. PropertySymOpnd * CopyWithoutFlowSensitiveInfo(Func *func);
  506. PropertySymOpnd * CopyInternalSub(Func *func);
  507. PropertySymOpnd * CloneDefInternalSub(Func *func);
  508. PropertySymOpnd * CloneUseInternalSub(Func *func);
  509. void Init(uint inlineCacheIndex, Func *func);
  510. private:
  511. static PropertySymOpnd * New(PropertySym *propertySym, IRType type, Func *func);
  512. void Init(uint inlineCacheIndex, intptr_t runtimeInlineCache, JITTimePolymorphicInlineCache * runtimePolymorphicInlineCache, ObjTypeSpecFldInfo* objTypeSpecFldInfo, byte polyCacheUtil);
  513. #if DBG
  514. virtual bool DbgIsPropertySymOpnd() const override { return true; }
  515. #endif
  516. public:
  517. Js::InlineCacheIndex m_inlineCacheIndex;
  518. intptr_t m_runtimeInlineCache;
  519. JITTimePolymorphicInlineCache* m_runtimePolymorphicInlineCache;
  520. private:
  521. ObjTypeSpecFldInfo* objTypeSpecFldInfo;
  522. public:
  523. JITTypeHolder finalType;
  524. JITTypeHolder monoGuardType;
  525. BVSparse<JitArenaAllocator>* guardedPropOps;
  526. BVSparse<JitArenaAllocator>* writeGuards;
  527. byte m_polyCacheUtil;
  528. private:
  529. bool usesAuxSlot : 1;
  530. Js::PropertyIndex slotIndex;
  531. uint16 checkedTypeSetIndex;
  532. public:
  533. union
  534. {
  535. struct
  536. {
  537. bool isTypeCheckOnly: 1;
  538. // Note that even usesFixedValue cannot live on ObjTypeSpecFldInfo, because we may share a cache between
  539. // e.g. Object.prototype and new Object(), and only the latter actually uses the fixed value, even though both have it.
  540. bool usesFixedValue: 1;
  541. union
  542. {
  543. struct
  544. {
  545. bool isTypeCheckSeqCandidate: 1;
  546. bool typeAvailable: 1;
  547. bool typeDead: 1;
  548. bool typeChecked: 1;
  549. bool initialTypeChecked: 1;
  550. bool typeMismatch: 1;
  551. bool writeGuardChecked: 1;
  552. };
  553. uint8 typeCheckSeqFlags;
  554. };
  555. };
  556. uint16 objTypeSpecFlags;
  557. };
  558. public:
  559. StackSym * GetObjectSym() const { return this->m_sym->AsPropertySym()->m_stackSym; };
  560. bool HasObjectTypeSym() const { return this->m_sym->AsPropertySym()->HasObjectTypeSym(); };
  561. StackSym * GetObjectTypeSym() const { return this->m_sym->AsPropertySym()->GetObjectTypeSym(); };
  562. PropertySym* GetPropertySym() const { return this->m_sym->AsPropertySym(); }
  563. void TryDisableRuntimePolymorphicCache()
  564. {
  565. if (this->m_runtimePolymorphicInlineCache && (this->m_polyCacheUtil < PolymorphicInlineCacheUtilizationThreshold))
  566. {
  567. this->m_runtimePolymorphicInlineCache = nullptr;
  568. }
  569. }
  570. bool HasObjTypeSpecFldInfo() const
  571. {
  572. return this->objTypeSpecFldInfo != nullptr;
  573. }
  574. void SetObjTypeSpecFldInfo(ObjTypeSpecFldInfo *const objTypeSpecFldInfo)
  575. {
  576. this->objTypeSpecFldInfo = objTypeSpecFldInfo;
  577. // The following information may change in a flow-based manner, and an ObjTypeSpecFldInfo is shared among several
  578. // PropertySymOpnds, so copy the information to the opnd
  579. if(!objTypeSpecFldInfo)
  580. {
  581. usesAuxSlot = false;
  582. slotIndex = 0;
  583. return;
  584. }
  585. usesAuxSlot = objTypeSpecFldInfo->UsesAuxSlot();
  586. slotIndex = objTypeSpecFldInfo->GetSlotIndex();
  587. }
  588. void TryResetObjTypeSpecFldInfo()
  589. {
  590. if (this->ShouldResetObjTypeSpecFldInfo())
  591. {
  592. SetObjTypeSpecFldInfo(nullptr);
  593. }
  594. }
  595. bool ShouldResetObjTypeSpecFldInfo()
  596. {
  597. // If an objTypeSpecFldInfo was created just for the purpose of polymorphic inlining but didn't get used for the same (for some reason or the other), and the polymorphic cache it was created from, wasn't equivalent,
  598. // we should null out this info on the propertySymOpnd so that assumptions downstream around equivalent object type spec still hold.
  599. if (HasObjTypeSpecFldInfo() && IsPoly() && (DoesntHaveEquivalence() || !IsLoadedFromProto()))
  600. {
  601. return true;
  602. }
  603. return false;
  604. }
  605. ObjTypeSpecFldInfo* GetObjTypeSpecInfo() const
  606. {
  607. return this->objTypeSpecFldInfo;
  608. }
  609. uint GetObjTypeSpecFldId() const
  610. {
  611. Assert(HasObjTypeSpecFldInfo());
  612. return this->objTypeSpecFldInfo->GetObjTypeSpecFldId();
  613. }
  614. bool IsMono() const
  615. {
  616. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsMono();
  617. }
  618. bool IsPoly() const
  619. {
  620. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsPoly();
  621. }
  622. bool HasEquivalentTypeSet() const
  623. {
  624. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->HasEquivalentTypeSet();
  625. }
  626. bool DoesntHaveEquivalence() const
  627. {
  628. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->DoesntHaveEquivalence();
  629. }
  630. bool UsesAuxSlot() const
  631. {
  632. return usesAuxSlot && HasObjTypeSpecFldInfo();
  633. }
  634. void SetUsesAuxSlot(bool value)
  635. {
  636. Assert(HasObjTypeSpecFldInfo());
  637. usesAuxSlot = value;
  638. }
  639. bool IsLoadedFromProto() const
  640. {
  641. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsLoadedFromProto();
  642. }
  643. bool UsesAccessor() const
  644. {
  645. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->UsesAccessor();
  646. }
  647. bool HasFixedValue() const
  648. {
  649. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->HasFixedValue();
  650. }
  651. bool UsesFixedValue() const
  652. {
  653. return this->usesFixedValue;
  654. }
  655. void SetUsesFixedValue(bool value)
  656. {
  657. this->usesFixedValue = value;
  658. }
  659. bool MustDoMonoCheck() const
  660. {
  661. return this->monoGuardType != nullptr;
  662. }
  663. JITTypeHolder GetMonoGuardType() const
  664. {
  665. return this->monoGuardType;
  666. }
  667. void SetMonoGuardType(JITTypeHolder type)
  668. {
  669. this->monoGuardType = type;
  670. }
  671. bool NeedsMonoCheck() const
  672. {
  673. Assert(HasObjTypeSpecFldInfo());
  674. return this->IsBeingAdded() || (this->HasFixedValue() && !this->IsLoadedFromProto());
  675. }
  676. bool IsBeingStored() const
  677. {
  678. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsBeingStored();
  679. }
  680. void SetIsBeingStored(bool value)
  681. {
  682. Assert(HasObjTypeSpecFldInfo());
  683. this->objTypeSpecFldInfo->SetIsBeingStored(value);
  684. }
  685. bool IsBeingAdded() const
  686. {
  687. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsBeingAdded();
  688. }
  689. bool IsRootObjectNonConfigurableField() const
  690. {
  691. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsRootObjectNonConfigurableField();
  692. }
  693. bool IsRootObjectNonConfigurableFieldLoad() const
  694. {
  695. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsRootObjectNonConfigurableFieldLoad();
  696. }
  697. uint16 GetSlotIndex() const
  698. {
  699. Assert(HasObjTypeSpecFldInfo());
  700. return slotIndex;
  701. }
  702. void SetSlotIndex(uint16 index)
  703. {
  704. Assert(HasObjTypeSpecFldInfo());
  705. slotIndex = index;
  706. }
  707. uint16 GetCheckedTypeSetIndex() const
  708. {
  709. Assert(HasEquivalentTypeSet());
  710. return checkedTypeSetIndex;
  711. }
  712. void SetCheckedTypeSetIndex(uint16 index)
  713. {
  714. Assert(HasEquivalentTypeSet());
  715. checkedTypeSetIndex = index;
  716. }
  717. Js::PropertyId GetPropertyId() const
  718. {
  719. Assert(HasObjTypeSpecFldInfo());
  720. return this->objTypeSpecFldInfo->GetPropertyId();
  721. }
  722. intptr_t GetProtoObject() const
  723. {
  724. Assert(HasObjTypeSpecFldInfo());
  725. return this->objTypeSpecFldInfo->GetProtoObject();
  726. }
  727. FixedFieldInfo * GetFixedFunction() const
  728. {
  729. Assert(HasObjTypeSpecFldInfo());
  730. return this->objTypeSpecFldInfo->GetFixedFieldIfAvailableAsFixedFunction();
  731. }
  732. FixedFieldInfo * GetFixedFunction(uint i) const
  733. {
  734. Assert(HasObjTypeSpecFldInfo());
  735. return this->objTypeSpecFldInfo->GetFixedFieldIfAvailableAsFixedFunction(i);
  736. }
  737. intptr_t GetFieldValueAsFixedData() const
  738. {
  739. Assert(HasObjTypeSpecFldInfo());
  740. return this->objTypeSpecFldInfo->GetFieldValueAsFixedDataIfAvailable();
  741. }
  742. intptr_t GetFieldValue(uint i) const
  743. {
  744. Assert(HasObjTypeSpecFldInfo());
  745. return this->objTypeSpecFldInfo->GetFieldValue(i);
  746. }
  747. FixedFieldInfo * GetFixedFieldInfoArray()
  748. {
  749. Assert(HasObjTypeSpecFldInfo());
  750. return this->objTypeSpecFldInfo->GetFixedFieldInfoArray();
  751. }
  752. uint16 GetFixedFieldCount()
  753. {
  754. Assert(HasObjTypeSpecFldInfo());
  755. return this->objTypeSpecFldInfo->GetFixedFieldCount();
  756. }
  757. JITTimeConstructorCache * GetCtorCache() const
  758. {
  759. Assert(HasObjTypeSpecFldInfo());
  760. return this->objTypeSpecFldInfo->GetCtorCache();
  761. }
  762. intptr_t GetPropertyGuardValueAddr() const
  763. {
  764. Assert(HasObjTypeSpecFldInfo());
  765. return this->objTypeSpecFldInfo->GetPropertyGuardValueAddr();
  766. }
  767. bool IsTypeCheckSeqCandidate() const
  768. {
  769. Assert(IsObjTypeSpecCandidate() || !this->isTypeCheckSeqCandidate);
  770. return this->isTypeCheckSeqCandidate;
  771. }
  772. void SetTypeCheckSeqCandidate(bool value)
  773. {
  774. Assert(IsObjTypeSpecCandidate() || !value);
  775. this->isTypeCheckSeqCandidate = value;
  776. }
  777. bool IsTypeCheckOnly() const
  778. {
  779. return this->isTypeCheckOnly;
  780. }
  781. void SetTypeCheckOnly(bool value)
  782. {
  783. this->isTypeCheckOnly = value;
  784. }
  785. bool IsTypeAvailable() const
  786. {
  787. return this->typeAvailable;
  788. }
  789. void SetTypeAvailable(bool value)
  790. {
  791. Assert(IsTypeCheckSeqCandidate());
  792. this->typeAvailable = value;
  793. }
  794. bool IsTypeDead() const
  795. {
  796. return this->typeDead;
  797. }
  798. void SetTypeDead(bool value)
  799. {
  800. Assert(IsTypeCheckSeqCandidate());
  801. this->typeDead = value;
  802. }
  803. void SetTypeDeadIfTypeCheckSeqCandidate(bool value)
  804. {
  805. if (IsTypeCheckSeqCandidate())
  806. {
  807. this->typeDead = value;
  808. }
  809. }
  810. bool IsTypeChecked() const
  811. {
  812. return this->typeChecked;
  813. }
  814. void SetTypeChecked(bool value)
  815. {
  816. Assert(IsTypeCheckSeqCandidate());
  817. this->typeChecked = value;
  818. }
  819. bool IsInitialTypeChecked() const
  820. {
  821. return this->initialTypeChecked;
  822. }
  823. void SetInitialTypeChecked(bool value)
  824. {
  825. Assert(IsTypeCheckSeqCandidate());
  826. this->initialTypeChecked = value;
  827. }
  828. bool HasTypeMismatch() const
  829. {
  830. return this->typeMismatch;
  831. }
  832. void SetTypeMismatch(bool value)
  833. {
  834. Assert(IsTypeCheckSeqCandidate());
  835. this->typeMismatch = value;
  836. }
  837. bool IsWriteGuardChecked() const
  838. {
  839. return this->writeGuardChecked;
  840. }
  841. void SetWriteGuardChecked(bool value)
  842. {
  843. Assert(IsTypeCheckSeqCandidate());
  844. this->writeGuardChecked = value;
  845. }
  846. uint16 GetObjTypeSpecFlags() const
  847. {
  848. return this->objTypeSpecFlags;
  849. }
  850. void ClearObjTypeSpecFlags()
  851. {
  852. this->objTypeSpecFlags = 0;
  853. }
  854. uint16 GetTypeCheckSeqFlags() const
  855. {
  856. return this->typeCheckSeqFlags;
  857. }
  858. void ClearTypeCheckSeqFlags()
  859. {
  860. this->typeCheckSeqFlags = 0;
  861. }
  862. bool MayNeedTypeCheckProtection() const
  863. {
  864. return IsObjTypeSpecCandidate() && (IsTypeCheckSeqCandidate() || UsesFixedValue());
  865. }
  866. bool MayNeedWriteGuardProtection() const
  867. {
  868. return IsLoadedFromProto() || UsesFixedValue();
  869. }
  870. bool IsTypeCheckProtected() const
  871. {
  872. return IsTypeCheckSeqCandidate() && IsTypeChecked();
  873. }
  874. bool NeedsPrimaryTypeCheck() const
  875. {
  876. // Only indicate that we need a primary type check, i.e. the type isn't yet available but will be needed downstream.
  877. // Type checks and bailouts may still be needed in other places (e.g. loads from proto, fixed field checks, or
  878. // property adds), if a primary type check cannot protect them.
  879. Assert(MayNeedTypeCheckProtection());
  880. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  881. return IsTypeCheckSeqCandidate() && !IsTypeDead() && !IsTypeChecked() && !HasTypeMismatch();
  882. }
  883. bool NeedsLocalTypeCheck() const
  884. {
  885. Assert(MayNeedTypeCheckProtection());
  886. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  887. // Indicate whether this operation needs a type check for its own sake, since the type is dead and no downstream
  888. // operations require the type to be checked.
  889. return !PHASE_OFF1(Js::ObjTypeSpecIsolatedFldOpsPhase) &&
  890. IsTypeCheckSeqCandidate() && IsTypeDead() && !IsTypeCheckOnly() && !IsTypeChecked() && !HasTypeMismatch();
  891. }
  892. bool NeedsWriteGuardTypeCheck() const
  893. {
  894. Assert(MayNeedTypeCheckProtection());
  895. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  896. // Type has been checked but property might have been written to since then.
  897. return !IsTypeCheckOnly() && !NeedsPrimaryTypeCheck() && IsTypeChecked() && !IsWriteGuardChecked();
  898. }
  899. bool NeedsLoadFromProtoTypeCheck() const
  900. {
  901. Assert(MayNeedTypeCheckProtection());
  902. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  903. // Proto cache, where type has been checked but property might have been written to since then.
  904. return !IsTypeCheckOnly() && !NeedsPrimaryTypeCheck() && IsLoadedFromProto() && NeedsWriteGuardTypeCheck();
  905. }
  906. bool NeedsAddPropertyTypeCheck() const
  907. {
  908. Assert(MayNeedTypeCheckProtection());
  909. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  910. // A property cannot become read-only without an explicit or implicit call (at least Object.defineProperty is needed), so if this
  911. // operation is protected by a primary type check upstream, there is no need for an additional local type check.
  912. return false;
  913. }
  914. bool NeedsCheckFixedFieldTypeCheck() const
  915. {
  916. Assert(MayNeedTypeCheckProtection());
  917. Assert(TypeCheckSeqBitsSetOnlyIfCandidate());
  918. return !IsTypeCheckOnly() && !NeedsPrimaryTypeCheck() && UsesFixedValue() && (!IsTypeChecked() || NeedsWriteGuardTypeCheck());
  919. }
  920. bool NeedsTypeCheck() const
  921. {
  922. return NeedsPrimaryTypeCheck() || NeedsLocalTypeCheck() ||
  923. NeedsLoadFromProtoTypeCheck() || NeedsAddPropertyTypeCheck() || NeedsCheckFixedFieldTypeCheck();
  924. }
  925. bool NeedsTypeCheckAndBailOut() const
  926. {
  927. return NeedsPrimaryTypeCheck() || (PHASE_ON1(Js::ObjTypeSpecIsolatedFldOpsWithBailOutPhase) && NeedsLocalTypeCheck()) || NeedsCheckFixedFieldTypeCheck();
  928. }
  929. // Is the instruction involving this operand optimized with a direct slot load or store? In other words, is it guarded
  930. // by a type check, either as part of the type check sequence, or explicitly on this instruction.
  931. bool IsObjTypeSpecOptimized() const
  932. {
  933. return MayNeedTypeCheckProtection() && (NeedsTypeCheckAndBailOut() || IsTypeCheckProtected());
  934. }
  935. // May the instruction involving this operand result in an implicit call? Note, that because in dead store pass we
  936. // may choose to remove a type check and fall back on a check against a live cache, instructions that have a primary
  937. // type check may still end up with implicit call bailout. However, if we are type check protected we will never
  938. // fall back on live cache. Similarly, for fixed method checks.
  939. bool MayHaveImplicitCall() const
  940. {
  941. return !IsRootObjectNonConfigurableFieldLoad() && !UsesFixedValue() && (!IsTypeCheckSeqCandidate() || !IsTypeCheckProtected());
  942. }
  943. // Is the instruction involving this operand part of a type check sequence? This is different from IsObjTypeSpecOptimized
  944. // in that an instruction such as CheckFixedFld may require a type check even if it is not part of a type check
  945. // sequence. In this case IsObjTypeSpecOptimized() == true, but IsTypeCheckSeqParticipant() == false.
  946. bool IsTypeCheckSeqParticipant() const
  947. {
  948. Assert(IsTypeCheckSeqCandidate());
  949. return NeedsPrimaryTypeCheck() || IsTypeCheckProtected();
  950. }
  951. bool HasFinalType() const;
  952. JITTypeHolder GetFinalType() const
  953. {
  954. return this->finalType;
  955. }
  956. void SetFinalType(JITTypeHolder type)
  957. {
  958. Assert(type != nullptr);
  959. this->finalType = type;
  960. }
  961. void ClearFinalType()
  962. {
  963. this->finalType = JITTypeHolder(nullptr);
  964. }
  965. BVSparse<JitArenaAllocator>* GetGuardedPropOps()
  966. {
  967. return this->guardedPropOps;
  968. }
  969. void EnsureGuardedPropOps(JitArenaAllocator* allocator)
  970. {
  971. if (this->guardedPropOps == nullptr)
  972. {
  973. this->guardedPropOps = JitAnew(allocator, BVSparse<JitArenaAllocator>, allocator);
  974. }
  975. }
  976. void SetGuardedPropOp(uint propOpId)
  977. {
  978. Assert(this->guardedPropOps != nullptr);
  979. this->guardedPropOps->Set(propOpId);
  980. }
  981. void AddGuardedPropOps(const BVSparse<JitArenaAllocator>* propOps)
  982. {
  983. Assert(this->guardedPropOps != nullptr);
  984. this->guardedPropOps->Or(propOps);
  985. }
  986. BVSparse<JitArenaAllocator>* GetWriteGuards()
  987. {
  988. return this->writeGuards;
  989. }
  990. void SetWriteGuards(BVSparse<JitArenaAllocator>* value)
  991. {
  992. Assert(this->writeGuards == nullptr);
  993. this->writeGuards = value;
  994. }
  995. void ClearWriteGuards()
  996. {
  997. this->writeGuards = nullptr;
  998. }
  999. #if DBG
  1000. bool TypeCheckSeqBitsSetOnlyIfCandidate() const
  1001. {
  1002. return IsTypeCheckSeqCandidate() || (!IsTypeAvailable() && !IsTypeChecked() && !IsWriteGuardChecked() && !IsTypeDead());
  1003. }
  1004. #endif
  1005. bool IsObjTypeSpecCandidate() const
  1006. {
  1007. return HasObjTypeSpecFldInfo();
  1008. }
  1009. bool IsMonoObjTypeSpecCandidate() const
  1010. {
  1011. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsMonoObjTypeSpecCandidate();
  1012. }
  1013. bool IsPolyObjTypeSpecCandidate() const
  1014. {
  1015. return HasObjTypeSpecFldInfo() && this->objTypeSpecFldInfo->IsPolyObjTypeSpecCandidate();
  1016. }
  1017. Js::TypeId GetTypeId() const
  1018. {
  1019. Assert(HasObjTypeSpecFldInfo());
  1020. return this->objTypeSpecFldInfo->GetTypeId();
  1021. }
  1022. Js::TypeId GetTypeId(uint i) const
  1023. {
  1024. Assert(HasObjTypeSpecFldInfo());
  1025. return this->objTypeSpecFldInfo->GetTypeId(i);
  1026. }
  1027. JITTypeHolder GetType() const
  1028. {
  1029. Assert(HasObjTypeSpecFldInfo());
  1030. return this->objTypeSpecFldInfo->GetType();
  1031. }
  1032. JITTypeHolder GetType(uint i) const
  1033. {
  1034. Assert(HasObjTypeSpecFldInfo());
  1035. return this->objTypeSpecFldInfo->GetType(i);
  1036. }
  1037. bool HasInitialType() const
  1038. {
  1039. Assert(HasObjTypeSpecFldInfo());
  1040. return this->objTypeSpecFldInfo->HasInitialType();
  1041. }
  1042. JITTypeHolder GetInitialType() const
  1043. {
  1044. Assert(HasObjTypeSpecFldInfo());
  1045. return this->objTypeSpecFldInfo->GetInitialType();
  1046. }
  1047. Js::EquivalentTypeSet * GetEquivalentTypeSet() const
  1048. {
  1049. Assert(HasObjTypeSpecFldInfo());
  1050. return this->objTypeSpecFldInfo->GetEquivalentTypeSet();
  1051. }
  1052. JITTypeHolder GetFirstEquivalentType() const
  1053. {
  1054. Assert(HasObjTypeSpecFldInfo());
  1055. return this->objTypeSpecFldInfo->GetFirstEquivalentType();
  1056. }
  1057. bool IsObjectHeaderInlined() const;
  1058. void UpdateSlotForFinalType();
  1059. bool ChangesObjectLayout() const;
  1060. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1061. const char16* GetCacheLayoutString() const
  1062. {
  1063. return HasObjTypeSpecFldInfo() ? this->objTypeSpecFldInfo->GetCacheLayoutString() : _u("empty");
  1064. }
  1065. #endif
  1066. };
  1067. ///---------------------------------------------------------------------------
  1068. ///
  1069. /// class RegOpnd
  1070. ///
  1071. ///---------------------------------------------------------------------------
  1072. class RegOpnd : public Opnd
  1073. {
  1074. protected:
  1075. RegOpnd(StackSym *sym, RegNum reg, IRType type);
  1076. RegOpnd(const RegOpnd &other, StackSym * sym);
  1077. private:
  1078. void Initialize(StackSym *sym, RegNum reg, IRType type);
  1079. public:
  1080. static RegOpnd * New(IRType type, Func *func);
  1081. static RegOpnd * New(StackSym *sym, IRType type, Func *func);
  1082. static RegOpnd * New(StackSym *sym, RegNum reg, IRType type, Func *func);
  1083. public:
  1084. bool IsArrayRegOpnd() const
  1085. {
  1086. Assert(m_isArrayRegOpnd == DbgIsArrayRegOpnd());
  1087. Assert(!m_isArrayRegOpnd || m_valueType.IsAnyOptimizedArray());
  1088. return m_isArrayRegOpnd;
  1089. }
  1090. ArrayRegOpnd * AsArrayRegOpnd();
  1091. RegNum GetReg() const;
  1092. void SetReg(RegNum reg);
  1093. //Note type: OpndKindReg
  1094. RegOpnd * CopyInternal(Func *func);
  1095. RegOpnd * CloneDefInternal(Func *func);
  1096. RegOpnd * CloneUseInternal(Func *func);
  1097. StackSym * GetStackSymInternal() const;
  1098. static StackSym * TryGetStackSym(Opnd *const opnd);
  1099. bool IsEqualInternal(Opnd *opnd);
  1100. void FreeInternal(Func * func);
  1101. bool IsSameReg(Opnd *opnd);
  1102. bool IsSameRegUntyped(Opnd *opnd);
  1103. #if DBG
  1104. void FreezeSymValue() { m_symValueFrozen = true; }
  1105. bool IsSymValueFrozen() const { return m_symValueFrozen; }
  1106. virtual bool DbgIsArrayRegOpnd() const { return false; }
  1107. #endif
  1108. private:
  1109. RegOpnd * CopyInternal(StackSym * sym, Func * func);
  1110. public:
  1111. StackSym * m_sym;
  1112. bool m_isTempLastUse:1;
  1113. bool m_isCallArg:1;
  1114. bool m_dontDeadStore: 1;
  1115. bool m_fgPeepTmp: 1;
  1116. bool m_wasNegativeZeroPreventedByBailout : 1;
  1117. bool m_isArrayRegOpnd : 1;
  1118. #if DBG
  1119. private:
  1120. bool m_symValueFrozen : 1; // if true, prevents this operand from being used as the destination operand in an instruction
  1121. #endif
  1122. private:
  1123. RegNum m_reg;
  1124. PREVENT_COPY(RegOpnd);
  1125. };
  1126. ///---------------------------------------------------------------------------
  1127. ///
  1128. /// class ArrayRegOpnd
  1129. ///
  1130. ///---------------------------------------------------------------------------
  1131. class ArrayRegOpnd sealed : public RegOpnd
  1132. {
  1133. private:
  1134. StackSym *headSegmentSym;
  1135. StackSym *headSegmentLengthSym;
  1136. StackSym *lengthSym;
  1137. const bool eliminatedLowerBoundCheck, eliminatedUpperBoundCheck;
  1138. protected:
  1139. ArrayRegOpnd(StackSym *const arraySym, const ValueType valueType, StackSym *const headSegmentSym, StackSym *const headSegmentLengthSym, StackSym *const lengthSym, const bool eliminatedLowerBoundCheck, const bool eliminatedUpperBoundCheck);
  1140. ArrayRegOpnd(const RegOpnd &other, StackSym *const arraySym, const ValueType valueType, StackSym *const headSegmentSym, StackSym *const headSegmentLengthSym, StackSym *const lengthSym, const bool eliminatedLowerBoundCheck, const bool eliminatedUpperBoundCheck);
  1141. public:
  1142. static ArrayRegOpnd *New(StackSym *const arraySym, const ValueType valueType, StackSym *const headSegmentSym, StackSym *const headSegmentLengthSym, StackSym *const lengthSym, const bool eliminatedLowerBoundCheck, const bool eliminatedUpperBoundCheck, Func *const func);
  1143. static ArrayRegOpnd *New(const RegOpnd *const other, const ValueType valueType, StackSym *const headSegmentSym, StackSym *const headSegmentLengthSym, StackSym *const lengthSym, const bool eliminatedLowerBoundCheck, const bool eliminatedUpperBoundCheck, Func *const func);
  1144. public:
  1145. #if DBG
  1146. virtual bool DbgIsArrayRegOpnd() const { return true; }
  1147. #endif
  1148. StackSym *HeadSegmentSym() const
  1149. {
  1150. return headSegmentSym;
  1151. }
  1152. void RemoveHeadSegmentSym()
  1153. {
  1154. headSegmentSym = nullptr;
  1155. }
  1156. StackSym *HeadSegmentLengthSym() const
  1157. {
  1158. return headSegmentLengthSym;
  1159. }
  1160. void RemoveHeadSegmentLengthSym()
  1161. {
  1162. headSegmentLengthSym = nullptr;
  1163. }
  1164. StackSym *LengthSym() const
  1165. {
  1166. // For typed arrays, the head segment length is the same as the array length
  1167. Assert(!(m_valueType.IsLikelyTypedArray() && !m_valueType.IsOptimizedTypedArray()));
  1168. return m_valueType.IsLikelyTypedArray() ? HeadSegmentLengthSym() : lengthSym;
  1169. }
  1170. void RemoveLengthSym()
  1171. {
  1172. Assert(m_valueType.IsArray());
  1173. lengthSym = nullptr;
  1174. }
  1175. bool EliminatedLowerBoundCheck() const
  1176. {
  1177. return eliminatedLowerBoundCheck;
  1178. }
  1179. bool EliminatedUpperBoundCheck() const
  1180. {
  1181. return eliminatedUpperBoundCheck;
  1182. }
  1183. public:
  1184. RegOpnd *CopyAsRegOpnd(Func *func);
  1185. ArrayRegOpnd * CopyInternalSub(Func *func);
  1186. ArrayRegOpnd *CloneDefInternalSub(Func *func);
  1187. ArrayRegOpnd *CloneUseInternalSub(Func *func);
  1188. private:
  1189. ArrayRegOpnd *Clone(StackSym *const arraySym, StackSym *const headSegmentSym, StackSym *const headSegmentLengthSym, StackSym *const lengthSym, Func *const func) const;
  1190. public:
  1191. void FreeInternalSub(Func *func);
  1192. // IsEqual is not overridden because this opnd still primarily represents the array sym. Equality comparisons using IsEqual
  1193. // are used to determine whether opnds should be swapped, etc. and the extra information in this class should not affect
  1194. // that behavior.
  1195. // virtual bool IsEqual(Opnd *opnd) override;
  1196. PREVENT_COPY(ArrayRegOpnd);
  1197. };
  1198. ///---------------------------------------------------------------------------
  1199. ///
  1200. /// class AddrOpnd
  1201. ///
  1202. ///---------------------------------------------------------------------------
  1203. class AddrOpnd sealed : public Opnd
  1204. {
  1205. public:
  1206. static AddrOpnd * New(intptr_t address, AddrOpndKind addrOpndKind, Func *func, bool dontEncode = false, Js::Var varLocal = nullptr);
  1207. static AddrOpnd * New(Js::Var address, AddrOpndKind addrOpndKind, Func *func, bool dontEncode = false, Js::Var varLocal = nullptr);
  1208. static AddrOpnd * NewFromNumber(double value, Func *func, bool dontEncode = false);
  1209. static AddrOpnd * NewFromNumber(int32 value, Func *func, bool dontEncode = false);
  1210. static AddrOpnd * NewFromNumber(int64 value, Func *func, bool dontEncode = false);
  1211. static AddrOpnd * NewFromNumberVar(double value, Func *func, bool dontEncode = false);
  1212. static AddrOpnd * NewNull(Func * func);
  1213. public:
  1214. //Note type: OpndKindAddr
  1215. AddrOpnd * CopyInternal(Func *func);
  1216. bool IsEqualInternal(Opnd *opnd);
  1217. void FreeInternal(Func * func);
  1218. bool IsDynamic() const { return addrOpndKind > AddrOpndKindConstantVar; }
  1219. bool IsVar() const { return addrOpndKind == AddrOpndKindDynamicVar || addrOpndKind == AddrOpndKindConstantVar; }
  1220. void SetEncodedValue(Js::Var address, AddrOpndKind addrOpndKind);
  1221. AddrOpndKind GetAddrOpndKind() const { return addrOpndKind; }
  1222. void SetAddress(Js::Var address, AddrOpndKind addrOpndKind);
  1223. public:
  1224. // TODO: OOP JIT, make this union more transparent
  1225. //union {
  1226. void * m_metadata;
  1227. Js::Var m_localAddress;
  1228. //};
  1229. Js::Var m_address;
  1230. bool m_dontEncode: 1;
  1231. bool m_isFunction: 1;
  1232. private:
  1233. AddrOpndKind addrOpndKind;
  1234. public:
  1235. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1236. Js::Var decodedValue; // FIXME (t-doilij) set ENABLE_IR_VIEWER blocks where this is set
  1237. #endif
  1238. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1239. bool wasVar;
  1240. #endif
  1241. };
  1242. ///---------------------------------------------------------------------------
  1243. ///
  1244. /// class IndirOpnd
  1245. ///
  1246. ///---------------------------------------------------------------------------
  1247. class IndirOpnd: public Opnd
  1248. {
  1249. public:
  1250. static IndirOpnd * New(RegOpnd * baseOpnd, RegOpnd * indexOpnd, IRType type, Func *func);
  1251. static IndirOpnd * New(RegOpnd * baseOpnd, RegOpnd * indexOpnd, byte scale, IRType type, Func *func);
  1252. static IndirOpnd * New(RegOpnd * indexOpnd, int32 offset, byte scale, IRType type, Func *func);
  1253. static IndirOpnd * New(RegOpnd * baseOpnd, int32 offset, IRType type, Func *func, bool dontEncode = false);
  1254. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1255. static IndirOpnd * New(RegOpnd * baseOpnd, int32 offset, IRType type, const char16 *desc, Func *func, bool dontEncode = false);
  1256. #endif
  1257. public:
  1258. IndirOpnd() : Opnd(), m_baseOpnd(nullptr), m_indexOpnd(nullptr), m_offset(0), m_scale(0), m_func(nullptr), m_dontEncode(false)
  1259. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1260. , m_desc(nullptr)
  1261. #endif
  1262. #if DBG_DUMP
  1263. , m_addrKind((IR::AddrOpndKind)-1)
  1264. #endif
  1265. {
  1266. }
  1267. ~IndirOpnd();
  1268. // Note type: OpndKindIndir
  1269. IndirOpnd * CopyInternal(Func *func);
  1270. IndirOpnd * CloneDefInternal(Func *func);
  1271. IndirOpnd * CloneUseInternal(Func *func);
  1272. bool IsEqualInternal(Opnd *opnd);
  1273. void FreeInternal(Func * func);
  1274. RegOpnd * GetBaseOpnd();
  1275. const RegOpnd * GetBaseOpnd() const;
  1276. void SetBaseOpnd(RegOpnd *baseOpnd);
  1277. RegOpnd * UnlinkBaseOpnd();
  1278. void ReplaceBaseOpnd(RegOpnd *newBase);
  1279. RegOpnd * GetIndexOpnd();
  1280. const RegOpnd * GetIndexOpnd() const;
  1281. void SetIndexOpnd(RegOpnd *indexOpnd);
  1282. RegOpnd * UnlinkIndexOpnd();
  1283. void ReplaceIndexOpnd(RegOpnd *newIndex);
  1284. int32 GetOffset() const;
  1285. void SetOffset(int32 offset, bool dontEncode = false);
  1286. byte GetScale() const;
  1287. void SetScale(byte scale);
  1288. bool TryGetIntConstIndexValue(bool trySym, IntConstType *pValue, bool *pIsNotInt);
  1289. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1290. const char16 * GetDescription();
  1291. IR::AddrOpndKind GetAddrKind() const;
  1292. bool HasAddrKind() const;
  1293. void * GetOriginalAddress() const;
  1294. #endif
  1295. bool m_dontEncode;
  1296. #if DBG_DUMP
  1297. void SetAddrKind(IR::AddrOpndKind kind, void * originalAddress);
  1298. #endif
  1299. private:
  1300. RegOpnd * m_baseOpnd;
  1301. RegOpnd * m_indexOpnd;
  1302. int32 m_offset;
  1303. byte m_scale;
  1304. Func * m_func; // We need the allocator to copy the base and index...
  1305. #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
  1306. const char16 * m_desc;
  1307. #endif
  1308. #if DBG_DUMP
  1309. IR::AddrOpndKind m_addrKind; // if m_addrKind != -1, than this used to be MemRefOpnd which has the address hoisted;
  1310. void * m_originalAddress;
  1311. #endif
  1312. };
  1313. ///---------------------------------------------------------------------------
  1314. ///
  1315. /// class MemRefOpnd - represents a reference to a fixed memory location
  1316. ///
  1317. ///---------------------------------------------------------------------------
  1318. class MemRefOpnd : public Opnd
  1319. {
  1320. public:
  1321. static MemRefOpnd * New(void * pMemLoc, IRType, Func * func, AddrOpndKind addrOpndKind = AddrOpndKindDynamicMisc);
  1322. static MemRefOpnd * New(intptr_t pMemLoc, IRType, Func * func, AddrOpndKind addrOpndKind = AddrOpndKindDynamicMisc);
  1323. public:
  1324. // Note type: OpndKindMemRef
  1325. MemRefOpnd * CopyInternal(Func * func);
  1326. bool IsEqualInternal(Opnd *opnd);
  1327. void FreeInternal(Func * func);
  1328. intptr_t GetMemLoc() const;
  1329. void SetMemLoc(intptr_t pMemLoc);
  1330. IR::AddrOpndKind GetAddrKind() const;
  1331. private:
  1332. intptr_t m_memLoc;
  1333. #if DBG_DUMP
  1334. AddrOpndKind m_addrKind;
  1335. #endif
  1336. };
  1337. //
  1338. // class LabelOpnd - represents a reference to a local code address
  1339. //
  1340. class LabelOpnd : public Opnd
  1341. {
  1342. public:
  1343. static LabelOpnd * New(LabelInstr * labelInstr, Func * func);
  1344. public:
  1345. //Note type: OpndKindLabel
  1346. LabelOpnd * CopyInternal(Func * func);
  1347. bool IsEqualInternal(Opnd * opnd);
  1348. void FreeInternal(Func * func);
  1349. LabelInstr * GetLabel() const;
  1350. void SetLabel(LabelInstr * labelInstr);
  1351. private:
  1352. LabelInstr * m_label;
  1353. };
  1354. ///---------------------------------------------------------------------------
  1355. ///
  1356. /// class Bit Field vector
  1357. ///
  1358. ///---------------------------------------------------------------------------
  1359. class RegBVOpnd: public Opnd
  1360. {
  1361. public:
  1362. static RegBVOpnd * New(BVUnit32 value, IRType type, Func *func);
  1363. public:
  1364. //Note: type: OpndKindRegBV
  1365. RegBVOpnd * CopyInternal(Func *func);
  1366. bool IsEqualInternal(Opnd *opnd);
  1367. void FreeInternal(Func * func);
  1368. BVUnit32 GetValue() const;
  1369. public:
  1370. BVUnit32 m_value;
  1371. };
  1372. class AutoReuseOpnd
  1373. {
  1374. private:
  1375. Opnd *opnd;
  1376. Func *func;
  1377. bool autoDelete;
  1378. bool wasInUse;
  1379. public:
  1380. AutoReuseOpnd() : opnd(nullptr), wasInUse(true)
  1381. {
  1382. }
  1383. AutoReuseOpnd(Opnd *const opnd, Func *const func, const bool autoDelete = true) : opnd(nullptr)
  1384. {
  1385. Initialize(opnd, func, autoDelete);
  1386. }
  1387. void Initialize(Opnd *const opnd, Func *const func, const bool autoDelete = true)
  1388. {
  1389. Assert(!this->opnd);
  1390. Assert(func);
  1391. if(!opnd)
  1392. {
  1393. // Simulate the default constructor
  1394. wasInUse = true;
  1395. return;
  1396. }
  1397. this->opnd = opnd;
  1398. wasInUse = opnd->IsInUse();
  1399. if(wasInUse)
  1400. {
  1401. return;
  1402. }
  1403. this->func = func;
  1404. this->autoDelete = autoDelete;
  1405. // Create a fake use of the opnd to enable opnd reuse during lowering. One issue is that when an unused opnd is first
  1406. // used in an instruction and the instruction is legalized, the opnd may be replaced by legalization and the original
  1407. // opnd would be freed. By creating a fake use, it forces the opnd to be copied when used by the instruction, so the
  1408. // original opnd can continue to be reused for other instructions. Typically, any opnds used during lowering in more
  1409. // than one instruction can use this class to enable opnd reuse.
  1410. opnd->Use(func);
  1411. }
  1412. ~AutoReuseOpnd()
  1413. {
  1414. if(wasInUse)
  1415. {
  1416. return;
  1417. }
  1418. if(autoDelete)
  1419. {
  1420. opnd->Free(func);
  1421. }
  1422. else
  1423. {
  1424. opnd->UnUse();
  1425. }
  1426. }
  1427. PREVENT_COPY(AutoReuseOpnd)
  1428. };
  1429. } // namespace IR