IndexedProperties.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/QuickSort.h>
  7. #include <LibJS/Runtime/Accessor.h>
  8. #include <LibJS/Runtime/IndexedProperties.h>
  9. namespace JS {
  10. constexpr const size_t SPARSE_ARRAY_HOLE_THRESHOLD = 200;
  11. constexpr const size_t LENGTH_SETTER_GENERIC_STORAGE_THRESHOLD = 4 * MiB;
  12. SimpleIndexedPropertyStorage::SimpleIndexedPropertyStorage(Vector<Value>&& initial_values)
  13. : m_array_size(initial_values.size())
  14. , m_packed_elements(move(initial_values))
  15. {
  16. }
  17. bool SimpleIndexedPropertyStorage::has_index(u32 index) const
  18. {
  19. return index < m_array_size && !m_packed_elements[index].is_empty();
  20. }
  21. Optional<ValueAndAttributes> SimpleIndexedPropertyStorage::get(u32 index) const
  22. {
  23. if (index >= m_array_size)
  24. return {};
  25. return ValueAndAttributes { m_packed_elements[index], default_attributes };
  26. }
  27. void SimpleIndexedPropertyStorage::grow_storage_if_needed()
  28. {
  29. if (m_array_size <= m_packed_elements.size())
  30. return;
  31. // Grow storage by 25% at a time.
  32. m_packed_elements.resize(m_array_size + (m_array_size / 4));
  33. }
  34. void SimpleIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
  35. {
  36. VERIFY(attributes == default_attributes);
  37. if (index >= m_array_size) {
  38. m_array_size = index + 1;
  39. grow_storage_if_needed();
  40. }
  41. m_packed_elements[index] = value;
  42. }
  43. void SimpleIndexedPropertyStorage::remove(u32 index)
  44. {
  45. if (index < m_array_size)
  46. m_packed_elements[index] = {};
  47. }
  48. void SimpleIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
  49. {
  50. VERIFY(attributes == default_attributes);
  51. m_array_size++;
  52. m_packed_elements.insert(index, value);
  53. }
  54. ValueAndAttributes SimpleIndexedPropertyStorage::take_first()
  55. {
  56. m_array_size--;
  57. return { m_packed_elements.take_first(), default_attributes };
  58. }
  59. ValueAndAttributes SimpleIndexedPropertyStorage::take_last()
  60. {
  61. m_array_size--;
  62. auto last_element = m_packed_elements[m_array_size];
  63. m_packed_elements[m_array_size] = {};
  64. return { last_element, default_attributes };
  65. }
  66. void SimpleIndexedPropertyStorage::set_array_like_size(size_t new_size)
  67. {
  68. m_array_size = new_size;
  69. m_packed_elements.resize(new_size);
  70. }
  71. GenericIndexedPropertyStorage::GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&& storage)
  72. {
  73. m_array_size = storage.array_like_size();
  74. for (size_t i = 0; i < storage.m_packed_elements.size(); ++i) {
  75. m_sparse_elements.set(i, { storage.m_packed_elements[i], default_attributes });
  76. }
  77. }
  78. bool GenericIndexedPropertyStorage::has_index(u32 index) const
  79. {
  80. return m_sparse_elements.contains(index);
  81. }
  82. Optional<ValueAndAttributes> GenericIndexedPropertyStorage::get(u32 index) const
  83. {
  84. if (index >= m_array_size)
  85. return {};
  86. return m_sparse_elements.get(index);
  87. }
  88. void GenericIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
  89. {
  90. if (index >= m_array_size)
  91. m_array_size = index + 1;
  92. m_sparse_elements.set(index, { value, attributes });
  93. }
  94. void GenericIndexedPropertyStorage::remove(u32 index)
  95. {
  96. if (index >= m_array_size)
  97. return;
  98. if (index + 1 == m_array_size) {
  99. take_last();
  100. return;
  101. }
  102. m_sparse_elements.remove(index);
  103. }
  104. void GenericIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
  105. {
  106. if (index >= m_array_size) {
  107. put(index, value, attributes);
  108. return;
  109. }
  110. m_array_size++;
  111. if (!m_sparse_elements.is_empty()) {
  112. HashMap<u32, ValueAndAttributes> new_sparse_elements;
  113. for (auto& entry : m_sparse_elements)
  114. new_sparse_elements.set(entry.key >= index ? entry.key + 1 : entry.key, entry.value);
  115. m_sparse_elements = move(new_sparse_elements);
  116. }
  117. m_sparse_elements.set(index, { value, attributes });
  118. }
  119. ValueAndAttributes GenericIndexedPropertyStorage::take_first()
  120. {
  121. VERIFY(m_array_size > 0);
  122. m_array_size--;
  123. auto indices = m_sparse_elements.keys();
  124. quick_sort(indices);
  125. auto it = m_sparse_elements.find(indices.first());
  126. auto first_element = it->value;
  127. m_sparse_elements.remove(it);
  128. return first_element;
  129. }
  130. ValueAndAttributes GenericIndexedPropertyStorage::take_last()
  131. {
  132. VERIFY(m_array_size > 0);
  133. m_array_size--;
  134. auto result = m_sparse_elements.get(m_array_size);
  135. if (!result.has_value())
  136. return {};
  137. m_sparse_elements.remove(m_array_size);
  138. return result.value();
  139. }
  140. void GenericIndexedPropertyStorage::set_array_like_size(size_t new_size)
  141. {
  142. m_array_size = new_size;
  143. HashMap<u32, ValueAndAttributes> new_sparse_elements;
  144. for (auto& entry : m_sparse_elements) {
  145. if (entry.key < new_size)
  146. new_sparse_elements.set(entry.key, entry.value);
  147. }
  148. m_sparse_elements = move(new_sparse_elements);
  149. }
  150. IndexedPropertyIterator::IndexedPropertyIterator(const IndexedProperties& indexed_properties, u32 staring_index, bool skip_empty)
  151. : m_indexed_properties(indexed_properties)
  152. , m_index(staring_index)
  153. , m_skip_empty(skip_empty)
  154. {
  155. if (m_skip_empty)
  156. skip_empty_indices();
  157. }
  158. IndexedPropertyIterator& IndexedPropertyIterator::operator++()
  159. {
  160. m_index++;
  161. if (m_skip_empty)
  162. skip_empty_indices();
  163. return *this;
  164. }
  165. IndexedPropertyIterator& IndexedPropertyIterator::operator*()
  166. {
  167. return *this;
  168. }
  169. bool IndexedPropertyIterator::operator!=(const IndexedPropertyIterator& other) const
  170. {
  171. return m_index != other.m_index;
  172. }
  173. ValueAndAttributes IndexedPropertyIterator::value_and_attributes(Object* this_object, AllowSideEffects allow_side_effects)
  174. {
  175. if (m_index < m_indexed_properties.array_like_size())
  176. return m_indexed_properties.get(this_object, m_index, allow_side_effects).value_or({});
  177. return {};
  178. }
  179. void IndexedPropertyIterator::skip_empty_indices()
  180. {
  181. auto indices = m_indexed_properties.indices();
  182. for (auto i : indices) {
  183. if (i < m_index)
  184. continue;
  185. m_index = i;
  186. return;
  187. }
  188. m_index = m_indexed_properties.array_like_size();
  189. }
  190. Optional<ValueAndAttributes> IndexedProperties::get(Object* this_object, u32 index, AllowSideEffects allow_side_effects) const
  191. {
  192. auto result = m_storage->get(index);
  193. if (allow_side_effects == AllowSideEffects::No)
  194. return result;
  195. if (!result.has_value())
  196. return {};
  197. auto& value = result.value();
  198. if (value.value.is_accessor()) {
  199. VERIFY(this_object);
  200. auto& accessor = value.value.as_accessor();
  201. return ValueAndAttributes { accessor.call_getter(this_object), value.attributes };
  202. }
  203. return result;
  204. }
  205. void IndexedProperties::put(Object* this_object, u32 index, Value value, PropertyAttributes attributes, AllowSideEffects allow_side_effects)
  206. {
  207. if (m_storage->is_simple_storage() && (attributes != default_attributes || index > (array_like_size() + SPARSE_ARRAY_HOLE_THRESHOLD))) {
  208. switch_to_generic_storage();
  209. }
  210. if (m_storage->is_simple_storage() || allow_side_effects == AllowSideEffects::No) {
  211. m_storage->put(index, value, attributes);
  212. return;
  213. }
  214. auto value_here = m_storage->get(index);
  215. if (value_here.has_value() && value_here.value().value.is_accessor()) {
  216. VERIFY(this_object);
  217. value_here.value().value.as_accessor().call_setter(this_object, value);
  218. } else {
  219. m_storage->put(index, value, attributes);
  220. }
  221. }
  222. bool IndexedProperties::remove(u32 index)
  223. {
  224. auto result = m_storage->get(index);
  225. if (!result.has_value())
  226. return true;
  227. if (!result.value().attributes.is_configurable())
  228. return false;
  229. m_storage->remove(index);
  230. return true;
  231. }
  232. void IndexedProperties::insert(u32 index, Value value, PropertyAttributes attributes)
  233. {
  234. if (m_storage->is_simple_storage()) {
  235. if (attributes != default_attributes
  236. || index > (array_like_size() + SPARSE_ARRAY_HOLE_THRESHOLD)) {
  237. switch_to_generic_storage();
  238. }
  239. }
  240. m_storage->insert(index, value, attributes);
  241. }
  242. ValueAndAttributes IndexedProperties::take_first(Object* this_object)
  243. {
  244. auto first = m_storage->take_first();
  245. if (first.value.is_accessor())
  246. return { first.value.as_accessor().call_getter(this_object), first.attributes };
  247. return first;
  248. }
  249. ValueAndAttributes IndexedProperties::take_last(Object* this_object)
  250. {
  251. auto last = m_storage->take_last();
  252. if (last.value.is_accessor())
  253. return { last.value.as_accessor().call_getter(this_object), last.attributes };
  254. return last;
  255. }
  256. void IndexedProperties::set_array_like_size(size_t new_size)
  257. {
  258. auto current_array_like_size = array_like_size();
  259. // We can't use simple storage for lengths that don't fit in an i32.
  260. // Also, to avoid gigantic unused storage allocations, let's put an (arbitrary) 4M cap on simple storage here.
  261. // This prevents something like "a = []; a.length = 0x80000000;" from allocating 2G entries.
  262. if (m_storage->is_simple_storage()
  263. && (new_size > NumericLimits<i32>::max()
  264. || (current_array_like_size < LENGTH_SETTER_GENERIC_STORAGE_THRESHOLD && new_size > LENGTH_SETTER_GENERIC_STORAGE_THRESHOLD))) {
  265. switch_to_generic_storage();
  266. }
  267. m_storage->set_array_like_size(new_size);
  268. }
  269. Vector<u32> IndexedProperties::indices() const
  270. {
  271. if (m_storage->is_simple_storage()) {
  272. const auto& storage = static_cast<const SimpleIndexedPropertyStorage&>(*m_storage);
  273. const auto& elements = storage.elements();
  274. Vector<u32> indices;
  275. indices.ensure_capacity(storage.array_like_size());
  276. for (size_t i = 0; i < elements.size(); ++i) {
  277. if (!elements.at(i).is_empty())
  278. indices.unchecked_append(i);
  279. }
  280. return indices;
  281. }
  282. const auto& storage = static_cast<const GenericIndexedPropertyStorage&>(*m_storage);
  283. auto indices = storage.sparse_elements().keys();
  284. quick_sort(indices);
  285. return indices;
  286. }
  287. void IndexedProperties::switch_to_generic_storage()
  288. {
  289. auto& storage = static_cast<SimpleIndexedPropertyStorage&>(*m_storage);
  290. m_storage = make<GenericIndexedPropertyStorage>(move(storage));
  291. }
  292. }