1/*
2 * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "JSCast.h"
29#include "JSTypeInfo.h"
30#include "PropertyDescriptor.h"
31#include "PutDirectIndexMode.h"
32#include "WriteBarrier.h"
33#include <wtf/HashMap.h>
34
35namespace JSC {
36
37class SparseArrayValueMap;
38
39class SparseArrayEntry : private WriteBarrier<Unknown> {
40 WTF_MAKE_FAST_ALLOCATED;
41public:
42 using Base = WriteBarrier<Unknown>;
43
44 SparseArrayEntry()
45 {
46 Base::setWithoutWriteBarrier(jsUndefined());
47 }
48
49 void get(JSObject*, PropertySlot&) const;
50 void get(PropertyDescriptor&) const;
51 bool put(ExecState*, JSValue thisValue, SparseArrayValueMap*, JSValue, bool shouldThrow);
52 JSValue getNonSparseMode() const;
53 JSValue getConcurrently() const;
54
55 unsigned attributes() const { return m_attributes; }
56
57 void forceSet(unsigned attributes)
58 {
59 // FIXME: We can expand this for non x86 environments. Currently, loading ReadOnly | DontDelete property
60 // from compiler thread is only supported in X86 architecture because of its TSO nature.
61 // https://bugs.webkit.org/show_bug.cgi?id=134641
62 if (isX86())
63 WTF::storeStoreFence();
64 m_attributes = attributes;
65 }
66
67 void forceSet(VM& vm, JSCell* map, JSValue value, unsigned attributes)
68 {
69 Base::set(vm, map, value);
70 forceSet(attributes);
71 }
72
73 WriteBarrier<Unknown>& asValue() { return *this; }
74
75private:
76 unsigned m_attributes { 0 };
77};
78
79class SparseArrayValueMap final : public JSCell {
80public:
81 typedef JSCell Base;
82 static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
83
84private:
85 typedef HashMap<uint64_t, SparseArrayEntry, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> Map;
86
87 enum Flags {
88 Normal = 0,
89 SparseMode = 1,
90 LengthIsReadOnly = 2,
91 };
92
93 SparseArrayValueMap(VM&);
94
95 void finishCreation(VM&);
96
97public:
98 DECLARE_EXPORT_INFO;
99
100 typedef Map::iterator iterator;
101 typedef Map::const_iterator const_iterator;
102 typedef Map::AddResult AddResult;
103
104 static SparseArrayValueMap* create(VM&);
105
106 static const bool needsDestruction = true;
107 static void destroy(JSCell*);
108
109 static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
110
111 static void visitChildren(JSCell*, SlotVisitor&);
112
113 bool sparseMode()
114 {
115 return m_flags & SparseMode;
116 }
117
118 void setSparseMode()
119 {
120 m_flags = static_cast<Flags>(m_flags | SparseMode);
121 }
122
123 bool lengthIsReadOnly()
124 {
125 return m_flags & LengthIsReadOnly;
126 }
127
128 void setLengthIsReadOnly()
129 {
130 m_flags = static_cast<Flags>(m_flags | LengthIsReadOnly);
131 }
132
133 // These methods may mutate the contents of the map
134 bool putEntry(ExecState*, JSObject*, unsigned, JSValue, bool shouldThrow);
135 bool putDirect(ExecState*, JSObject*, unsigned, JSValue, unsigned attributes, PutDirectIndexMode);
136 AddResult add(JSObject*, unsigned);
137 iterator find(unsigned i) { return m_map.find(i); }
138 // This should ASSERT the remove is valid (check the result of the find).
139 void remove(iterator it);
140 void remove(unsigned i);
141
142 JSValue getConcurrently(unsigned index);
143
144 // These methods do not mutate the contents of the map.
145 iterator notFound() { return m_map.end(); }
146 bool isEmpty() const { return m_map.isEmpty(); }
147 bool contains(unsigned i) const { return m_map.contains(i); }
148 size_t size() const { return m_map.size(); }
149 // Only allow const begin/end iteration.
150 const_iterator begin() const { return m_map.begin(); }
151 const_iterator end() const { return m_map.end(); }
152
153private:
154 Map m_map;
155 Flags m_flags { Normal };
156 size_t m_reportedCapacity { 0 };
157};
158
159} // namespace JSC
160