CacheOperators.inl 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. 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. namespace Js
  7. {
  8. template<
  9. bool CheckLocal,
  10. bool CheckProto,
  11. bool CheckAccessor,
  12. bool CheckMissing,
  13. bool CheckPolymorphicInlineCache,
  14. bool CheckTypePropertyCache,
  15. bool IsInlineCacheAvailable,
  16. bool IsPolymorphicInlineCacheAvailable,
  17. bool ReturnOperationInfo>
  18. inline bool CacheOperators::TryGetProperty(
  19. Var const instance,
  20. const bool isRoot,
  21. RecyclableObject *const object,
  22. const PropertyId propertyId,
  23. Var *const propertyValue,
  24. ScriptContext *const requestContext,
  25. PropertyCacheOperationInfo * operationInfo,
  26. PropertyValueInfo *const propertyValueInfo)
  27. {
  28. CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
  29. Assert(!CheckTypePropertyCache || !isRoot);
  30. Assert(propertyValueInfo);
  31. Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
  32. Assert(IsPolymorphicInlineCacheAvailable == !!propertyValueInfo->GetPolymorphicInlineCache());
  33. Assert(!ReturnOperationInfo || operationInfo);
  34. if(CheckLocal || CheckProto || CheckAccessor)
  35. {
  36. InlineCache *const inlineCache = IsInlineCacheAvailable ? propertyValueInfo->GetInlineCache() : nullptr;
  37. if(IsInlineCacheAvailable)
  38. {
  39. if (inlineCache->TryGetProperty<CheckLocal, CheckProto, CheckAccessor, CheckMissing, ReturnOperationInfo>(
  40. instance,
  41. object,
  42. propertyId,
  43. propertyValue,
  44. requestContext,
  45. operationInfo))
  46. {
  47. return true;
  48. }
  49. if(ReturnOperationInfo)
  50. {
  51. operationInfo->isPolymorphic = inlineCache->HasDifferentType(object->GetType());
  52. }
  53. }
  54. else if(ReturnOperationInfo)
  55. {
  56. operationInfo->isPolymorphic = true;
  57. }
  58. if(CheckPolymorphicInlineCache)
  59. {
  60. Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
  61. PolymorphicInlineCache *const polymorphicInlineCache =
  62. IsPolymorphicInlineCacheAvailable
  63. ? propertyValueInfo->GetPolymorphicInlineCache()
  64. : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(
  65. propertyValueInfo->GetInlineCacheIndex());
  66. if ((IsPolymorphicInlineCacheAvailable || polymorphicInlineCache) &&
  67. polymorphicInlineCache->TryGetProperty<
  68. CheckLocal,
  69. CheckProto,
  70. CheckAccessor,
  71. CheckMissing,
  72. IsInlineCacheAvailable,
  73. ReturnOperationInfo
  74. >(
  75. instance,
  76. object,
  77. propertyId,
  78. propertyValue,
  79. requestContext,
  80. operationInfo,
  81. inlineCache
  82. ))
  83. {
  84. return true;
  85. }
  86. }
  87. }
  88. if(!CheckTypePropertyCache)
  89. {
  90. return false;
  91. }
  92. TypePropertyCache *const typePropertyCache = object->GetType()->GetPropertyCache();
  93. if(!typePropertyCache ||
  94. !typePropertyCache->TryGetProperty(
  95. CheckMissing,
  96. object,
  97. propertyId,
  98. propertyValue,
  99. requestContext,
  100. ReturnOperationInfo ? operationInfo : nullptr,
  101. propertyValueInfo))
  102. {
  103. return false;
  104. }
  105. if(!ReturnOperationInfo || operationInfo->cacheType == CacheType_TypeProperty)
  106. {
  107. return true;
  108. }
  109. // The property access was cached in an inline cache. Get the proper property operation info.
  110. PretendTryGetProperty<IsInlineCacheAvailable, IsPolymorphicInlineCacheAvailable>(
  111. object->GetType(),
  112. operationInfo,
  113. propertyValueInfo);
  114. return true;
  115. }
  116. template<
  117. bool CheckLocal,
  118. bool CheckLocalTypeWithoutProperty,
  119. bool CheckAccessor,
  120. bool CheckPolymorphicInlineCache,
  121. bool CheckTypePropertyCache,
  122. bool IsInlineCacheAvailable,
  123. bool IsPolymorphicInlineCacheAvailable,
  124. bool ReturnOperationInfo>
  125. inline bool CacheOperators::TrySetProperty(
  126. RecyclableObject *const object,
  127. const bool isRoot,
  128. const PropertyId propertyId,
  129. Var propertyValue,
  130. ScriptContext *const requestContext,
  131. const PropertyOperationFlags propertyOperationFlags,
  132. PropertyCacheOperationInfo * operationInfo,
  133. PropertyValueInfo *const propertyValueInfo)
  134. {
  135. CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
  136. Assert(!CheckTypePropertyCache || !isRoot);
  137. Assert(propertyValueInfo);
  138. Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
  139. Assert(IsPolymorphicInlineCacheAvailable == !!propertyValueInfo->GetPolymorphicInlineCache());
  140. Assert(!ReturnOperationInfo || operationInfo);
  141. if(CheckLocal || CheckLocalTypeWithoutProperty || CheckAccessor)
  142. {
  143. InlineCache *const inlineCache = IsInlineCacheAvailable ? propertyValueInfo->GetInlineCache() : nullptr;
  144. if(IsInlineCacheAvailable)
  145. {
  146. if (inlineCache->TrySetProperty<CheckLocal, CheckLocalTypeWithoutProperty, CheckAccessor, ReturnOperationInfo>(
  147. object,
  148. propertyId,
  149. propertyValue,
  150. requestContext,
  151. operationInfo,
  152. propertyOperationFlags))
  153. {
  154. return true;
  155. }
  156. if(ReturnOperationInfo)
  157. {
  158. operationInfo->isPolymorphic = inlineCache->HasDifferentType(object->GetType());
  159. }
  160. }
  161. else if(ReturnOperationInfo)
  162. {
  163. operationInfo->isPolymorphic = true;
  164. }
  165. if(CheckPolymorphicInlineCache)
  166. {
  167. Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
  168. PolymorphicInlineCache *const polymorphicInlineCache =
  169. IsPolymorphicInlineCacheAvailable
  170. ? propertyValueInfo->GetPolymorphicInlineCache()
  171. : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(
  172. propertyValueInfo->GetInlineCacheIndex());
  173. if ((IsPolymorphicInlineCacheAvailable || polymorphicInlineCache) &&
  174. polymorphicInlineCache->TrySetProperty<
  175. CheckLocal,
  176. CheckLocalTypeWithoutProperty,
  177. CheckAccessor,
  178. IsInlineCacheAvailable,
  179. ReturnOperationInfo
  180. >(
  181. object,
  182. propertyId,
  183. propertyValue,
  184. requestContext,
  185. operationInfo,
  186. inlineCache,
  187. propertyOperationFlags
  188. ))
  189. {
  190. return true;
  191. }
  192. }
  193. }
  194. if(!CheckTypePropertyCache)
  195. {
  196. return false;
  197. }
  198. TypePropertyCache *const typePropertyCache = object->GetType()->GetPropertyCache();
  199. if(!typePropertyCache ||
  200. !typePropertyCache->TrySetProperty(
  201. object,
  202. propertyId,
  203. propertyValue,
  204. requestContext,
  205. ReturnOperationInfo ? operationInfo : nullptr,
  206. propertyValueInfo))
  207. {
  208. return false;
  209. }
  210. if(!ReturnOperationInfo || operationInfo->cacheType == CacheType_TypeProperty)
  211. {
  212. return true;
  213. }
  214. // The property access was cached in an inline cache. Get the proper property operation info.
  215. PretendTrySetProperty<IsInlineCacheAvailable, IsPolymorphicInlineCacheAvailable>(
  216. object->GetType(),
  217. object->GetType(),
  218. operationInfo,
  219. propertyValueInfo);
  220. return true;
  221. }
  222. template<
  223. bool IsInlineCacheAvailable,
  224. bool IsPolymorphicInlineCacheAvailable>
  225. inline void CacheOperators::PretendTryGetProperty(
  226. Type *const type,
  227. PropertyCacheOperationInfo *operationInfo,
  228. PropertyValueInfo *const propertyValueInfo)
  229. {
  230. CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
  231. Assert(propertyValueInfo);
  232. Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
  233. Assert(!IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetPolymorphicInlineCache());
  234. Assert(operationInfo);
  235. if (IsInlineCacheAvailable && propertyValueInfo->GetInlineCache()->PretendTryGetProperty(type, operationInfo))
  236. {
  237. return;
  238. }
  239. Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
  240. PolymorphicInlineCache *const polymorphicInlineCache =
  241. IsPolymorphicInlineCacheAvailable
  242. ? propertyValueInfo->GetPolymorphicInlineCache()
  243. : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(propertyValueInfo->GetInlineCacheIndex());
  244. if (IsPolymorphicInlineCacheAvailable || polymorphicInlineCache)
  245. {
  246. polymorphicInlineCache->PretendTryGetProperty(type, operationInfo);
  247. }
  248. }
  249. template<
  250. bool IsInlineCacheAvailable,
  251. bool IsPolymorphicInlineCacheAvailable>
  252. inline void CacheOperators::PretendTrySetProperty(
  253. Type *const type,
  254. Type *const oldType,
  255. PropertyCacheOperationInfo * operationInfo,
  256. PropertyValueInfo *const propertyValueInfo)
  257. {
  258. CompileAssert(IsInlineCacheAvailable || IsPolymorphicInlineCacheAvailable);
  259. Assert(propertyValueInfo);
  260. Assert(IsInlineCacheAvailable == !!propertyValueInfo->GetInlineCache());
  261. Assert(!IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetPolymorphicInlineCache());
  262. Assert(operationInfo);
  263. if (IsInlineCacheAvailable && propertyValueInfo->GetInlineCache()->PretendTrySetProperty(type, oldType, operationInfo))
  264. {
  265. return;
  266. }
  267. Assert(IsPolymorphicInlineCacheAvailable || propertyValueInfo->GetFunctionBody());
  268. PolymorphicInlineCache *const polymorphicInlineCache =
  269. IsPolymorphicInlineCacheAvailable
  270. ? propertyValueInfo->GetPolymorphicInlineCache()
  271. : propertyValueInfo->GetFunctionBody()->GetPolymorphicInlineCache(propertyValueInfo->GetInlineCacheIndex());
  272. if (IsPolymorphicInlineCacheAvailable || polymorphicInlineCache)
  273. {
  274. polymorphicInlineCache->PretendTrySetProperty(type, oldType, operationInfo);
  275. }
  276. }
  277. template<
  278. bool IsAccessor,
  279. bool IsRead,
  280. bool IncludeTypePropertyCache>
  281. inline void CacheOperators::Cache(
  282. const bool isProto,
  283. DynamicObject *const objectWithProperty,
  284. const bool isRoot,
  285. Type *const type,
  286. Type *const typeWithoutProperty,
  287. const PropertyId propertyId,
  288. const PropertyIndex propertyIndex,
  289. const bool isInlineSlot,
  290. const bool isMissing,
  291. const int requiredAuxSlotCapacity,
  292. const PropertyValueInfo *const info,
  293. ScriptContext *const requestContext)
  294. {
  295. CompileAssert(!IsAccessor || !IncludeTypePropertyCache);
  296. Assert(info);
  297. Assert(objectWithProperty);
  298. if(!IsAccessor)
  299. {
  300. if(!isProto)
  301. {
  302. Assert(type == objectWithProperty->GetType());
  303. }
  304. else
  305. {
  306. Assert(IsRead);
  307. Assert(type != objectWithProperty->GetType());
  308. }
  309. }
  310. else
  311. {
  312. Assert(!isRoot); // could still be root object, but the parameter will be false and shouldn't be used for accessors
  313. Assert(!typeWithoutProperty);
  314. Assert(requiredAuxSlotCapacity == 0);
  315. }
  316. if(IsRead)
  317. {
  318. Assert(!typeWithoutProperty);
  319. Assert(requiredAuxSlotCapacity == 0);
  320. Assert(CanCachePropertyRead(objectWithProperty, requestContext));
  321. if(!IsAccessor && isProto && PropertyValueInfo::PrototypeCacheDisabled(info))
  322. {
  323. return;
  324. }
  325. }
  326. else
  327. {
  328. Assert(CanCachePropertyWrite(objectWithProperty, requestContext));
  329. // TODO(ianhall): the following assert would let global const properties slip through when they shadow
  330. // a global property. Reason being DictionaryTypeHandler::IsWritable cannot tell if it should check
  331. // the global property or the global let/const. Fix this by updating IsWritable to recognize isRoot.
  332. // Built-in Function.prototype properties 'length', 'arguments', and 'caller' are special cases.
  333. Assert(
  334. objectWithProperty->IsWritable(propertyId) ||
  335. (isRoot && RootObjectBase::FromVar(objectWithProperty)->IsLetConstGlobal(propertyId)) ||
  336. JavascriptFunction::IsBuiltinProperty(objectWithProperty, propertyId));
  337. }
  338. const bool includeTypePropertyCache = IncludeTypePropertyCache && !isRoot;
  339. bool createTypePropertyCache = false;
  340. PolymorphicInlineCache *polymorphicInlineCache = info->GetPolymorphicInlineCache();
  341. if(!polymorphicInlineCache && info->GetFunctionBody())
  342. {
  343. polymorphicInlineCache = info->GetFunctionBody()->GetPolymorphicInlineCache(info->GetInlineCacheIndex());
  344. }
  345. InlineCache *const inlineCache = info->GetInlineCache();
  346. if(inlineCache)
  347. {
  348. const bool tryCreatePolymorphicInlineCache = !polymorphicInlineCache && info->GetFunctionBody();
  349. if((includeTypePropertyCache || tryCreatePolymorphicInlineCache) &&
  350. inlineCache->HasDifferentType<IsAccessor>(isProto, type, typeWithoutProperty))
  351. {
  352. if(tryCreatePolymorphicInlineCache)
  353. {
  354. polymorphicInlineCache =
  355. info->GetFunctionBody()->CreateNewPolymorphicInlineCache(
  356. info->GetInlineCacheIndex(),
  357. propertyId,
  358. inlineCache);
  359. }
  360. if(includeTypePropertyCache)
  361. {
  362. createTypePropertyCache = true;
  363. }
  364. }
  365. if(!IsAccessor)
  366. {
  367. if(!isProto)
  368. {
  369. inlineCache->CacheLocal(
  370. type,
  371. propertyId,
  372. propertyIndex,
  373. isInlineSlot,
  374. typeWithoutProperty,
  375. requiredAuxSlotCapacity,
  376. requestContext);
  377. }
  378. else
  379. {
  380. inlineCache->CacheProto(
  381. objectWithProperty,
  382. propertyId,
  383. propertyIndex,
  384. isInlineSlot,
  385. isMissing,
  386. type,
  387. requestContext);
  388. }
  389. }
  390. else
  391. {
  392. inlineCache->CacheAccessor(
  393. IsRead,
  394. propertyId,
  395. propertyIndex,
  396. isInlineSlot,
  397. type,
  398. objectWithProperty,
  399. isProto,
  400. requestContext);
  401. }
  402. }
  403. if(polymorphicInlineCache)
  404. {
  405. // Don't resize a polymorphic inline cache from full JIT because it currently doesn't rejit to use the new
  406. // polymorphic inline cache. Once resized, bailouts would populate only the new set of caches and full JIT would
  407. // continue to use to old set of caches.
  408. Assert(!info->AllowResizingPolymorphicInlineCache() || info->GetFunctionBody());
  409. if(((includeTypePropertyCache && !createTypePropertyCache) || info->AllowResizingPolymorphicInlineCache()) &&
  410. polymorphicInlineCache->HasDifferentType<IsAccessor>(isProto, type, typeWithoutProperty))
  411. {
  412. if(info->AllowResizingPolymorphicInlineCache() && polymorphicInlineCache->CanAllocateBigger())
  413. {
  414. polymorphicInlineCache =
  415. info->GetFunctionBody()->CreateBiggerPolymorphicInlineCache(
  416. info->GetInlineCacheIndex(),
  417. propertyId);
  418. }
  419. if(includeTypePropertyCache)
  420. {
  421. createTypePropertyCache = true;
  422. }
  423. }
  424. if(!IsAccessor)
  425. {
  426. if(!isProto)
  427. {
  428. polymorphicInlineCache->CacheLocal(
  429. type,
  430. propertyId,
  431. propertyIndex,
  432. isInlineSlot,
  433. typeWithoutProperty,
  434. requiredAuxSlotCapacity,
  435. requestContext);
  436. }
  437. else
  438. {
  439. polymorphicInlineCache->CacheProto(
  440. objectWithProperty,
  441. propertyId,
  442. propertyIndex,
  443. isInlineSlot,
  444. isMissing,
  445. type,
  446. requestContext);
  447. }
  448. }
  449. else
  450. {
  451. polymorphicInlineCache->CacheAccessor(
  452. IsRead,
  453. propertyId,
  454. propertyIndex,
  455. isInlineSlot,
  456. type,
  457. objectWithProperty,
  458. isProto,
  459. requestContext);
  460. }
  461. }
  462. if(!includeTypePropertyCache)
  463. {
  464. return;
  465. }
  466. Assert(!IsAccessor);
  467. TypePropertyCache *typePropertyCache = type->GetPropertyCache();
  468. if(!typePropertyCache)
  469. {
  470. if(!createTypePropertyCache)
  471. {
  472. return;
  473. }
  474. typePropertyCache = type->CreatePropertyCache();
  475. }
  476. if(isProto)
  477. {
  478. typePropertyCache->Cache(
  479. propertyId,
  480. propertyIndex,
  481. isInlineSlot,
  482. info->IsWritable() && info->IsStoreFieldCacheEnabled(),
  483. isMissing,
  484. objectWithProperty,
  485. type);
  486. typePropertyCache = objectWithProperty->GetType()->GetPropertyCache();
  487. if(!typePropertyCache)
  488. {
  489. return;
  490. }
  491. }
  492. typePropertyCache->Cache(
  493. propertyId,
  494. propertyIndex,
  495. isInlineSlot,
  496. info->IsWritable() && info->IsStoreFieldCacheEnabled());
  497. }
  498. }