PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/base/repo-auth-type.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 386 lines | 300 code | 47 blank | 39 comment | 101 complexity | 62966c2a93e5352da0d76e3e8406f2cd MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/runtime/base/repo-auth-type.h"
  17. #include <vector>
  18. #include <folly/Hash.h>
  19. #include "hphp/runtime/base/repo-auth-type-array.h"
  20. #include "hphp/runtime/base/object-data.h"
  21. #include "hphp/runtime/base/tv-helpers.h"
  22. #include "hphp/runtime/base/typed-value.h"
  23. #include "hphp/runtime/vm/unit.h"
  24. namespace HPHP {
  25. //////////////////////////////////////////////////////////////////////
  26. static_assert(sizeof(RepoAuthType) == sizeof(CompactTaggedPtr<void>), "");
  27. //////////////////////////////////////////////////////////////////////
  28. namespace {
  29. bool tvMatchesArrayType(TypedValue tv, const RepoAuthType::Array* arrTy) {
  30. assert(tv.m_type == KindOfArray);
  31. auto const ad = tv.m_data.parr;
  32. using A = RepoAuthType::Array;
  33. auto sizeMatches = [&] {
  34. switch (arrTy->emptiness()) {
  35. case A::Empty::Maybe:
  36. return ad->size() == 0 || ad->size() == arrTy->size();
  37. case A::Empty::No:
  38. return ad->size() == arrTy->size();
  39. }
  40. not_reached();
  41. };
  42. // O(N) checks are available if you want them for debugging, but
  43. // they are too slow for general use in debug builds. These type
  44. // matching functions are currently only used for assertions, so
  45. // it's ok to leave them out.
  46. auto const use_slow_checks = false;
  47. switch (arrTy->tag()) {
  48. case A::Tag::Packed:
  49. if (!sizeMatches()) return false;
  50. if (use_slow_checks) {
  51. for (auto i = uint32_t{0}; i < ad->size(); ++i) {
  52. auto const elem = ad->nvGet(i);
  53. if (!tvMatchesRepoAuthType(*elem, arrTy->packedElem(i))) {
  54. return false;
  55. }
  56. }
  57. }
  58. break;
  59. case A::Tag::PackedN:
  60. if (use_slow_checks) {
  61. for (auto i = uint32_t{0}; i < ad->size(); ++i) {
  62. auto const elem = ad->nvGet(i);
  63. if (!tvMatchesRepoAuthType(*elem, arrTy->elemType())) {
  64. return false;
  65. }
  66. }
  67. }
  68. break;
  69. }
  70. return true;
  71. }
  72. }
  73. //////////////////////////////////////////////////////////////////////
  74. bool RepoAuthType::operator==(RepoAuthType o) const {
  75. using T = Tag;
  76. if (tag() != o.tag()) return false;
  77. switch (tag()) {
  78. case T::OptBool:
  79. case T::OptInt:
  80. case T::OptSStr:
  81. case T::OptStr:
  82. case T::OptDbl:
  83. case T::OptRes:
  84. case T::OptObj:
  85. case T::Null:
  86. case T::Cell:
  87. case T::Ref:
  88. case T::InitUnc:
  89. case T::Unc:
  90. case T::InitCell:
  91. case T::InitGen:
  92. case T::Gen:
  93. case T::Uninit:
  94. case T::InitNull:
  95. case T::Bool:
  96. case T::Int:
  97. case T::Dbl:
  98. case T::Res:
  99. case T::SStr:
  100. case T::Str:
  101. case T::Obj:
  102. return true;
  103. case T::OptSArr:
  104. case T::OptArr:
  105. // Can't currently have array() info.
  106. return true;
  107. case T::SArr:
  108. case T::Arr:
  109. if (array() == nullptr && o.array() == nullptr) {
  110. return true;
  111. }
  112. if ((array() == nullptr) != (o.array() == nullptr)) {
  113. return false;
  114. }
  115. return array()->id() == o.array()->id();
  116. case T::SubObj:
  117. case T::ExactObj:
  118. case T::OptSubObj:
  119. case T::OptExactObj:
  120. return clsName() == o.clsName();
  121. }
  122. not_reached();
  123. }
  124. size_t RepoAuthType::hash() const {
  125. auto const iTag = static_cast<size_t>(tag());
  126. if (hasClassName()) {
  127. return folly::hash::hash_128_to_64(iTag, clsName()->hash());
  128. }
  129. if (mayHaveArrData() && array()) {
  130. return folly::hash::hash_128_to_64(iTag, array()->id());
  131. }
  132. return iTag;
  133. }
  134. //////////////////////////////////////////////////////////////////////
  135. folly::Optional<DataType> convertToDataType(RepoAuthType ty) {
  136. using T = RepoAuthType::Tag;
  137. switch (ty.tag()) {
  138. case T::OptBool:
  139. case T::OptInt:
  140. case T::OptSArr:
  141. case T::OptArr:
  142. case T::OptSStr:
  143. case T::OptStr:
  144. case T::OptDbl:
  145. case T::OptRes:
  146. case T::OptSubObj:
  147. case T::OptExactObj:
  148. case T::OptObj:
  149. case T::Null:
  150. return folly::none;
  151. case T::Cell:
  152. case T::Ref:
  153. case T::InitUnc:
  154. case T::Unc:
  155. case T::InitCell:
  156. case T::InitGen:
  157. case T::Gen:
  158. return folly::none;
  159. case T::Uninit: return KindOfUninit;
  160. case T::InitNull: return KindOfNull;
  161. case T::Bool: return KindOfBoolean;
  162. case T::Int: return KindOfInt64;
  163. case T::Dbl: return KindOfDouble;
  164. case T::Res: return KindOfResource;
  165. case T::SStr:
  166. case T::Str: return KindOfString;
  167. case T::SArr:
  168. case T::Arr: return KindOfArray;
  169. case T::Obj:
  170. case T::SubObj:
  171. case T::ExactObj: return KindOfObject;
  172. }
  173. not_reached();
  174. }
  175. bool tvMatchesRepoAuthType(TypedValue tv, RepoAuthType ty) {
  176. assert(tvIsPlausible(tv));
  177. bool const initNull = tv.m_type == KindOfNull;
  178. using T = RepoAuthType::Tag;
  179. switch (ty.tag()) {
  180. case T::Uninit: return tv.m_type == KindOfUninit;
  181. case T::InitNull: return initNull;
  182. case T::OptBool: if (initNull) return true;
  183. // fallthrough
  184. case T::Bool: return tv.m_type == KindOfBoolean;
  185. case T::OptInt: if (initNull) return true;
  186. // fallthrough
  187. case T::Int: return tv.m_type == KindOfInt64;
  188. case T::OptDbl: if (initNull) return true;
  189. // fallthrough
  190. case T::Dbl: return tv.m_type == KindOfDouble;
  191. case T::OptRes: if (initNull) return true;
  192. // fallthrough
  193. case T::Res: return tv.m_type == KindOfResource;
  194. case T::OptObj: if (initNull) return true;
  195. // fallthrough
  196. case T::Obj: return tv.m_type == KindOfObject;
  197. case T::OptSStr:
  198. if (initNull) return true;
  199. // fallthrough
  200. case T::SStr:
  201. return tv.m_type == KindOfStaticString ||
  202. (tv.m_type == KindOfString && tv.m_data.pstr->isStatic());
  203. case T::OptStr:
  204. if (initNull) return true;
  205. // fallthrough
  206. case T::Str:
  207. return IS_STRING_TYPE(tv.m_type);
  208. case T::OptSArr:
  209. if (initNull) return true;
  210. // fallthrough
  211. case T::SArr:
  212. if (tv.m_type != KindOfArray || !tv.m_data.parr->isStatic()) {
  213. return false;
  214. }
  215. if (auto const arr = ty.array()) {
  216. if (!tvMatchesArrayType(tv, arr)) return false;
  217. }
  218. return true;
  219. case T::OptArr:
  220. if (initNull) return true;
  221. // fallthrough
  222. case T::Arr:
  223. if (tv.m_type != KindOfArray) return false;
  224. if (auto const arr = ty.array()) {
  225. if (!tvMatchesArrayType(tv, arr)) return false;
  226. }
  227. return true;
  228. case T::Null:
  229. return initNull || tv.m_type == KindOfUninit;
  230. case T::OptSubObj:
  231. if (initNull) return true;
  232. // fallthrough
  233. case T::SubObj:
  234. {
  235. auto const cls = Unit::lookupClass(ty.clsName());
  236. if (!cls) return false;
  237. return tv.m_type == KindOfObject &&
  238. tv.m_data.pobj->getVMClass()->classof(cls);
  239. }
  240. case T::OptExactObj:
  241. if (initNull) return true;
  242. // fallthrough
  243. case T::ExactObj:
  244. {
  245. auto const cls = Unit::lookupClass(ty.clsName());
  246. if (!cls) return false;
  247. return tv.m_type == KindOfObject && tv.m_data.pobj->getVMClass() == cls;
  248. }
  249. case T::InitUnc:
  250. if (tv.m_type == KindOfUninit) return false;
  251. // fallthrough
  252. case T::Unc:
  253. return !IS_REFCOUNTED_TYPE(tv.m_type) ||
  254. (tv.m_type == KindOfString && tv.m_data.pstr->isStatic()) ||
  255. (tv.m_type == KindOfArray && tv.m_data.parr->isStatic());
  256. case T::InitCell:
  257. if (tv.m_type == KindOfUninit) return false;
  258. // fallthrough
  259. case T::Cell:
  260. return tv.m_type != KindOfRef;
  261. case T::Ref:
  262. return tv.m_type == KindOfRef;
  263. case T::InitGen:
  264. if (tv.m_type == KindOfUninit) return false;
  265. // fallthrough
  266. case T::Gen:
  267. return true;
  268. }
  269. not_reached();
  270. }
  271. std::string show(RepoAuthType rat) {
  272. auto const tag = rat.tag();
  273. using T = RepoAuthType::Tag;
  274. switch (tag) {
  275. case T::OptBool: return "?Bool";
  276. case T::OptInt: return "?Int";
  277. case T::OptSStr: return "?SStr";
  278. case T::OptStr: return "?Str";
  279. case T::OptDbl: return "?Dbl";
  280. case T::OptRes: return "?Res";
  281. case T::OptObj: return "?Obj";
  282. case T::Null: return "Null";
  283. case T::Cell: return "Cell";
  284. case T::Ref: return "Ref";
  285. case T::InitUnc: return "InitUnc";
  286. case T::Unc: return "Unc";
  287. case T::InitCell: return "InitCell";
  288. case T::InitGen: return "InitGen";
  289. case T::Gen: return "Gen";
  290. case T::Uninit: return "Uninit";
  291. case T::InitNull: return "InitNull";
  292. case T::Bool: return "Bool";
  293. case T::Int: return "Int";
  294. case T::Dbl: return "Dbl";
  295. case T::Res: return "Res";
  296. case T::SStr: return "SStr";
  297. case T::Str: return "Str";
  298. case T::Obj: return "Obj";
  299. case T::OptSArr:
  300. case T::OptArr:
  301. case T::SArr:
  302. case T::Arr:
  303. {
  304. auto ret = std::string{};
  305. if (tag == T::OptArr || tag == T::OptSArr) {
  306. ret += '?';
  307. }
  308. if (tag == T::SArr || tag == T::OptSArr) {
  309. ret += 'S';
  310. }
  311. ret += "Arr";
  312. if (auto const ar = rat.array()) {
  313. folly::format(&ret, "{}", show(*ar));
  314. }
  315. return ret;
  316. }
  317. break;
  318. case T::OptSubObj:
  319. case T::OptExactObj:
  320. case T::SubObj:
  321. case T::ExactObj:
  322. {
  323. auto ret = std::string{};
  324. if (tag == T::OptSubObj || tag == T::OptExactObj) {
  325. ret += '?';
  326. }
  327. ret += "Obj";
  328. if (tag == T::OptSubObj || tag == T::SubObj) {
  329. ret += "<";
  330. }
  331. ret += '=';
  332. ret += rat.clsName()->data();
  333. return ret;
  334. }
  335. }
  336. not_reached();
  337. }
  338. //////////////////////////////////////////////////////////////////////
  339. }