IndexedProperties.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/QuickSort.h>
  27. #include <LibJS/Runtime/Accessor.h>
  28. #include <LibJS/Runtime/IndexedProperties.h>
  29. namespace JS {
  30. const u32 SPARSE_ARRAY_HOLE_THRESHOLD = 200;
  31. SimpleIndexedPropertyStorage::SimpleIndexedPropertyStorage(Vector<Value>&& initial_values)
  32. : m_array_size(initial_values.size())
  33. , m_packed_elements(move(initial_values))
  34. {
  35. }
  36. bool SimpleIndexedPropertyStorage::has_index(u32 index) const
  37. {
  38. return index < m_array_size && !m_packed_elements[index].is_empty();
  39. }
  40. Optional<ValueAndAttributes> SimpleIndexedPropertyStorage::get(u32 index) const
  41. {
  42. if (index >= m_array_size)
  43. return {};
  44. return ValueAndAttributes { m_packed_elements[index], default_attributes };
  45. }
  46. void SimpleIndexedPropertyStorage::grow_storage_if_needed()
  47. {
  48. if (m_array_size <= m_packed_elements.size())
  49. return;
  50. // Grow storage by 25% at a time.
  51. m_packed_elements.resize(m_array_size + (m_array_size / 4));
  52. }
  53. void SimpleIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
  54. {
  55. VERIFY(attributes == default_attributes);
  56. if (index >= m_array_size) {
  57. m_array_size = index + 1;
  58. grow_storage_if_needed();
  59. }
  60. m_packed_elements[index] = value;
  61. }
  62. void SimpleIndexedPropertyStorage::remove(u32 index)
  63. {
  64. if (index < m_array_size)
  65. m_packed_elements[index] = {};
  66. }
  67. void SimpleIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
  68. {
  69. VERIFY(attributes == default_attributes);
  70. m_array_size++;
  71. m_packed_elements.insert(index, value);
  72. }
  73. ValueAndAttributes SimpleIndexedPropertyStorage::take_first()
  74. {
  75. m_array_size--;
  76. return { m_packed_elements.take_first(), default_attributes };
  77. }
  78. ValueAndAttributes SimpleIndexedPropertyStorage::take_last()
  79. {
  80. m_array_size--;
  81. auto last_element = m_packed_elements[m_array_size];
  82. m_packed_elements[m_array_size] = {};
  83. return { last_element, default_attributes };
  84. }
  85. void SimpleIndexedPropertyStorage::set_array_like_size(size_t new_size)
  86. {
  87. m_array_size = new_size;
  88. m_packed_elements.resize(new_size);
  89. }
  90. GenericIndexedPropertyStorage::GenericIndexedPropertyStorage(SimpleIndexedPropertyStorage&& storage)
  91. {
  92. m_array_size = storage.array_like_size();
  93. for (size_t i = 0; i < storage.m_packed_elements.size(); ++i) {
  94. m_sparse_elements.set(i, { storage.m_packed_elements[i], default_attributes });
  95. }
  96. }
  97. bool GenericIndexedPropertyStorage::has_index(u32 index) const
  98. {
  99. return m_sparse_elements.contains(index);
  100. }
  101. Optional<ValueAndAttributes> GenericIndexedPropertyStorage::get(u32 index) const
  102. {
  103. if (index >= m_array_size)
  104. return {};
  105. return m_sparse_elements.get(index);
  106. }
  107. void GenericIndexedPropertyStorage::put(u32 index, Value value, PropertyAttributes attributes)
  108. {
  109. if (index >= m_array_size)
  110. m_array_size = index + 1;
  111. m_sparse_elements.set(index, { value, attributes });
  112. }
  113. void GenericIndexedPropertyStorage::remove(u32 index)
  114. {
  115. if (index >= m_array_size)
  116. return;
  117. if (index + 1 == m_array_size) {
  118. take_last();
  119. return;
  120. }
  121. m_sparse_elements.remove(index);
  122. }
  123. void GenericIndexedPropertyStorage::insert(u32 index, Value value, PropertyAttributes attributes)
  124. {
  125. if (index >= m_array_size) {
  126. put(index, value, attributes);
  127. return;
  128. }
  129. m_array_size++;
  130. if (!m_sparse_elements.is_empty()) {
  131. HashMap<u32, ValueAndAttributes> new_sparse_elements;
  132. for (auto& entry : m_sparse_elements)
  133. new_sparse_elements.set(entry.key >= index ? entry.key + 1 : entry.key, entry.value);
  134. m_sparse_elements = move(new_sparse_elements);
  135. }
  136. m_sparse_elements.set(index, { value, attributes });
  137. }
  138. ValueAndAttributes GenericIndexedPropertyStorage::take_first()
  139. {
  140. VERIFY(m_array_size > 0);
  141. m_array_size--;
  142. auto indices = m_sparse_elements.keys();
  143. quick_sort(indices);
  144. auto it = m_sparse_elements.find(indices.first());
  145. auto first_element = it->value;
  146. m_sparse_elements.remove(it);
  147. return first_element;
  148. }
  149. ValueAndAttributes GenericIndexedPropertyStorage::take_last()
  150. {
  151. VERIFY(m_array_size > 0);
  152. m_array_size--;
  153. auto result = m_sparse_elements.get(m_array_size);
  154. m_sparse_elements.remove(m_array_size);
  155. VERIFY(result.has_value());
  156. return result.value();
  157. }
  158. void GenericIndexedPropertyStorage::set_array_like_size(size_t new_size)
  159. {
  160. m_array_size = new_size;
  161. HashMap<u32, ValueAndAttributes> new_sparse_elements;
  162. for (auto& entry : m_sparse_elements) {
  163. if (entry.key < new_size)
  164. new_sparse_elements.set(entry.key, entry.value);
  165. }
  166. m_sparse_elements = move(new_sparse_elements);
  167. }
  168. IndexedPropertyIterator::IndexedPropertyIterator(const IndexedProperties& indexed_properties, u32 staring_index, bool skip_empty)
  169. : m_indexed_properties(indexed_properties)
  170. , m_index(staring_index)
  171. , m_skip_empty(skip_empty)
  172. {
  173. if (m_skip_empty)
  174. skip_empty_indices();
  175. }
  176. IndexedPropertyIterator& IndexedPropertyIterator::operator++()
  177. {
  178. m_index++;
  179. if (m_skip_empty)
  180. skip_empty_indices();
  181. return *this;
  182. }
  183. IndexedPropertyIterator& IndexedPropertyIterator::operator*()
  184. {
  185. return *this;
  186. }
  187. bool IndexedPropertyIterator::operator!=(const IndexedPropertyIterator& other) const
  188. {
  189. return m_index != other.m_index;
  190. }
  191. ValueAndAttributes IndexedPropertyIterator::value_and_attributes(Object* this_object, bool evaluate_accessors)
  192. {
  193. if (m_index < m_indexed_properties.array_like_size())
  194. return m_indexed_properties.get(this_object, m_index, evaluate_accessors).value_or({});
  195. return {};
  196. }
  197. void IndexedPropertyIterator::skip_empty_indices()
  198. {
  199. auto indices = m_indexed_properties.indices();
  200. for (auto i : indices) {
  201. if (i < m_index)
  202. continue;
  203. m_index = i;
  204. return;
  205. }
  206. m_index = m_indexed_properties.array_like_size();
  207. }
  208. Optional<ValueAndAttributes> IndexedProperties::get(Object* this_object, u32 index, bool evaluate_accessors) const
  209. {
  210. auto result = m_storage->get(index);
  211. if (!evaluate_accessors)
  212. return result;
  213. if (!result.has_value())
  214. return {};
  215. auto& value = result.value();
  216. if (value.value.is_accessor()) {
  217. VERIFY(this_object);
  218. auto& accessor = value.value.as_accessor();
  219. return ValueAndAttributes { accessor.call_getter(this_object), value.attributes };
  220. }
  221. return result;
  222. }
  223. void IndexedProperties::put(Object* this_object, u32 index, Value value, PropertyAttributes attributes, bool evaluate_accessors)
  224. {
  225. if (m_storage->is_simple_storage() && (attributes != default_attributes || index > (array_like_size() + SPARSE_ARRAY_HOLE_THRESHOLD))) {
  226. switch_to_generic_storage();
  227. }
  228. if (m_storage->is_simple_storage() || !evaluate_accessors) {
  229. m_storage->put(index, value, attributes);
  230. return;
  231. }
  232. auto value_here = m_storage->get(index);
  233. if (value_here.has_value() && value_here.value().value.is_accessor()) {
  234. VERIFY(this_object);
  235. value_here.value().value.as_accessor().call_setter(this_object, value);
  236. } else {
  237. m_storage->put(index, value, attributes);
  238. }
  239. }
  240. bool IndexedProperties::remove(u32 index)
  241. {
  242. auto result = m_storage->get(index);
  243. if (!result.has_value())
  244. return true;
  245. if (!result.value().attributes.is_configurable())
  246. return false;
  247. m_storage->remove(index);
  248. return true;
  249. }
  250. void IndexedProperties::insert(u32 index, Value value, PropertyAttributes attributes)
  251. {
  252. if (m_storage->is_simple_storage()) {
  253. if (attributes != default_attributes
  254. || index > (array_like_size() + SPARSE_ARRAY_HOLE_THRESHOLD)) {
  255. switch_to_generic_storage();
  256. }
  257. }
  258. m_storage->insert(index, value, attributes);
  259. }
  260. ValueAndAttributes IndexedProperties::take_first(Object* this_object)
  261. {
  262. auto first = m_storage->take_first();
  263. if (first.value.is_accessor())
  264. return { first.value.as_accessor().call_getter(this_object), first.attributes };
  265. return first;
  266. }
  267. ValueAndAttributes IndexedProperties::take_last(Object* this_object)
  268. {
  269. auto last = m_storage->take_last();
  270. if (last.value.is_accessor())
  271. return { last.value.as_accessor().call_getter(this_object), last.attributes };
  272. return last;
  273. }
  274. void IndexedProperties::append_all(Object* this_object, const IndexedProperties& properties, bool evaluate_accessors)
  275. {
  276. if (m_storage->is_simple_storage() && !properties.m_storage->is_simple_storage())
  277. switch_to_generic_storage();
  278. for (auto it = properties.begin(false); it != properties.end(); ++it) {
  279. const auto& element = it.value_and_attributes(this_object, evaluate_accessors);
  280. if (this_object && this_object->vm().exception())
  281. return;
  282. m_storage->put(m_storage->array_like_size(), element.value, element.attributes);
  283. }
  284. }
  285. void IndexedProperties::set_array_like_size(size_t new_size)
  286. {
  287. constexpr size_t length_setter_generic_storage_threshold = 4 * MiB;
  288. auto current_array_like_size = array_like_size();
  289. // We can't use simple storage for lengths that don't fit in an i32.
  290. // Also, to avoid gigantic unused storage allocations, let's put an (arbitrary) 4M cap on simple storage here.
  291. // This prevents something like "a = []; a.length = 0x80000000;" from allocating 2G entries.
  292. if (m_storage->is_simple_storage()
  293. && (new_size > NumericLimits<i32>::max()
  294. || (current_array_like_size < length_setter_generic_storage_threshold && new_size > length_setter_generic_storage_threshold))) {
  295. switch_to_generic_storage();
  296. }
  297. m_storage->set_array_like_size(new_size);
  298. }
  299. Vector<u32> IndexedProperties::indices() const
  300. {
  301. if (m_storage->is_simple_storage()) {
  302. const auto& storage = static_cast<const SimpleIndexedPropertyStorage&>(*m_storage);
  303. const auto& elements = storage.elements();
  304. Vector<u32> indices;
  305. indices.ensure_capacity(storage.array_like_size());
  306. for (size_t i = 0; i < elements.size(); ++i) {
  307. if (!elements.at(i).is_empty())
  308. indices.unchecked_append(i);
  309. }
  310. return indices;
  311. }
  312. const auto& storage = static_cast<const GenericIndexedPropertyStorage&>(*m_storage);
  313. auto indices = storage.sparse_elements().keys();
  314. quick_sort(indices);
  315. return indices;
  316. }
  317. void IndexedProperties::switch_to_generic_storage()
  318. {
  319. auto& storage = static_cast<SimpleIndexedPropertyStorage&>(*m_storage);
  320. m_storage = make<GenericIndexedPropertyStorage>(move(storage));
  321. }
  322. }