blob: b07c535b374048109e69c90ad8c9a9ff29487c23 [file] [log] [blame]
fpizlo@apple.com43219522014-02-25 02:02:50 +00001/*
mark.lam@apple.com17ae4902021-02-19 15:51:15 +00002 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
fpizlo@apple.com43219522014-02-25 02:02:50 +00003 *
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#include "config.h"
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000027#include "PutByVariant.h"
fpizlo@apple.com43219522014-02-25 02:02:50 +000028
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000029#include "CacheableIdentifierInlines.h"
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000030#include "CallLinkStatus.h"
ross.kirsling@sony.come257a3b2020-05-19 23:56:00 +000031#include "HeapInlines.h"
fpizlo@apple.comb41e6822014-07-25 20:55:17 +000032
fpizlo@apple.com43219522014-02-25 02:02:50 +000033namespace JSC {
34
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000035PutByVariant::PutByVariant(const PutByVariant& other)
36 : PutByVariant(other.m_identifier)
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000037{
38 *this = other;
39}
40
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000041PutByVariant& PutByVariant::operator=(const PutByVariant& other)
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000042{
43 m_kind = other.m_kind;
44 m_oldStructure = other.m_oldStructure;
45 m_newStructure = other.m_newStructure;
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +000046 m_conditionSet = other.m_conditionSet;
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000047 m_offset = other.m_offset;
48 if (other.m_callLinkStatus)
ysuzuki@apple.com1d8e24d2019-08-19 06:59:40 +000049 m_callLinkStatus = makeUnique<CallLinkStatus>(*other.m_callLinkStatus);
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000050 else
51 m_callLinkStatus = nullptr;
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000052 m_identifier = other.m_identifier;
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000053 return *this;
54}
55
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000056PutByVariant PutByVariant::replace(CacheableIdentifier identifier, const StructureSet& structure, PropertyOffset offset)
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000057{
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000058 PutByVariant result(WTFMove(identifier));
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000059 result.m_kind = Replace;
60 result.m_oldStructure = structure;
61 result.m_offset = offset;
62 return result;
63}
64
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000065PutByVariant PutByVariant::transition(CacheableIdentifier identifier, const StructureSet& oldStructure, Structure* newStructure, const ObjectPropertyConditionSet& conditionSet, PropertyOffset offset)
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000066{
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000067 PutByVariant result(WTFMove(identifier));
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000068 result.m_kind = Transition;
69 result.m_oldStructure = oldStructure;
70 result.m_newStructure = newStructure;
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +000071 result.m_conditionSet = conditionSet;
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000072 result.m_offset = offset;
73 return result;
74}
75
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000076PutByVariant PutByVariant::setter(CacheableIdentifier identifier, const StructureSet& structure, PropertyOffset offset, const ObjectPropertyConditionSet& conditionSet, std::unique_ptr<CallLinkStatus> callLinkStatus)
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000077{
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000078 PutByVariant result(WTFMove(identifier));
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000079 result.m_kind = Setter;
80 result.m_oldStructure = structure;
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +000081 result.m_conditionSet = conditionSet;
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000082 result.m_offset = offset;
aestes@apple.com13aae082016-01-02 08:03:08 +000083 result.m_callLinkStatus = WTFMove(callLinkStatus);
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +000084 return result;
85}
86
ysuzuki@apple.com23c96142021-08-26 07:39:01 +000087Structure* PutByVariant::oldStructureForTransition() const
fpizlo@apple.com3378c482014-07-27 23:14:40 +000088{
fpizlo@apple.comed2da802018-07-22 02:48:16 +000089 RELEASE_ASSERT(kind() == Transition);
90 RELEASE_ASSERT(m_oldStructure.size() <= 2);
fpizlo@apple.com3378c482014-07-27 23:14:40 +000091 for (unsigned i = m_oldStructure.size(); i--;) {
92 Structure* structure = m_oldStructure[i];
93 if (structure != m_newStructure)
94 return structure;
95 }
96 RELEASE_ASSERT_NOT_REACHED();
ryuan.choi@samsung.com951e85f2014-07-28 02:02:43 +000097
98 return nullptr;
fpizlo@apple.com3378c482014-07-27 23:14:40 +000099}
100
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000101void PutByVariant::fixTransitionToReplaceIfNecessary()
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000102{
103 if (kind() != Transition)
104 return;
105
106 RELEASE_ASSERT(m_oldStructure.size() <= 2);
107 for (unsigned i = m_oldStructure.size(); i--;) {
108 Structure* structure = m_oldStructure[i];
109 if (structure != m_newStructure)
110 return;
111 }
112
113 m_newStructure = nullptr;
114 m_kind = Replace;
115 m_conditionSet = ObjectPropertyConditionSet();
116 RELEASE_ASSERT(!m_callLinkStatus);
117}
118
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000119bool PutByVariant::writesStructures() const
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000120{
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000121 switch (kind()) {
122 case Transition:
123 case Setter:
124 return true;
125 default:
126 return false;
127 }
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000128}
129
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000130bool PutByVariant::reallocatesStorage() const
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000131{
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000132 switch (kind()) {
133 case Transition:
134 return oldStructureForTransition()->outOfLineCapacity() != newStructure()->outOfLineCapacity();
135 case Setter:
136 return true;
137 default:
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000138 return false;
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000139 }
140}
141
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000142bool PutByVariant::makesCalls() const
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000143{
144 return kind() == Setter;
145}
146
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000147bool PutByVariant::attemptToMerge(const PutByVariant& other)
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000148{
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000149 if (!!m_identifier != !!other.m_identifier)
150 return false;
151
152 if (m_identifier && (m_identifier != other.m_identifier))
153 return false;
154
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000155 if (m_offset != other.m_offset)
156 return false;
fpizlo@apple.com12835772015-09-21 20:49:04 +0000157
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000158 switch (m_kind) {
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000159 case NotSet:
160 RELEASE_ASSERT_NOT_REACHED();
161 return false;
162
fpizlo@apple.com12835772015-09-21 20:49:04 +0000163 case Replace: {
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000164 switch (other.m_kind) {
165 case Replace: {
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +0000166 ASSERT(m_conditionSet.isEmpty());
167 ASSERT(other.m_conditionSet.isEmpty());
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000168
169 m_oldStructure.merge(other.m_oldStructure);
170 return true;
171 }
172
173 case Transition: {
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000174 PutByVariant newVariant = other;
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000175 if (newVariant.attemptToMergeTransitionWithReplace(*this)) {
176 *this = newVariant;
177 return true;
178 }
179 return false;
180 }
181
182 default:
183 return false;
184 }
fpizlo@apple.com12835772015-09-21 20:49:04 +0000185 }
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000186
187 case Transition:
188 switch (other.m_kind) {
189 case Replace:
190 return attemptToMergeTransitionWithReplace(other);
191
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000192 case Transition: {
193 if (m_oldStructure != other.m_oldStructure)
194 return false;
195
196 if (m_newStructure != other.m_newStructure)
197 return false;
198
199 ObjectPropertyConditionSet mergedConditionSet;
200 if (!m_conditionSet.isEmpty()) {
201 mergedConditionSet = m_conditionSet.mergedWith(other.m_conditionSet);
202 if (!mergedConditionSet.isValid())
203 return false;
204 }
205 m_conditionSet = mergedConditionSet;
206 return true;
207 }
208
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000209 default:
210 return false;
211 }
212
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000213 case Setter: {
214 if (other.m_kind != Setter)
215 return false;
216
217 if (m_callLinkStatus || other.m_callLinkStatus) {
218 if (!(m_callLinkStatus && other.m_callLinkStatus))
219 return false;
220 }
221
222 if (m_conditionSet.isEmpty() != other.m_conditionSet.isEmpty())
223 return false;
224
225 ObjectPropertyConditionSet mergedConditionSet;
226 if (!m_conditionSet.isEmpty()) {
227 mergedConditionSet = m_conditionSet.mergedWith(other.m_conditionSet);
228 if (!mergedConditionSet.isValid() || !mergedConditionSet.hasOneSlotBaseCondition())
229 return false;
230 }
231 m_conditionSet = mergedConditionSet;
232
233 if (m_callLinkStatus)
234 m_callLinkStatus->merge(*other.m_callLinkStatus);
235
236 m_oldStructure.merge(other.m_oldStructure);
237 return true;
238 } }
239
240 RELEASE_ASSERT_NOT_REACHED();
241 return false;
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000242}
243
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000244bool PutByVariant::attemptToMergeTransitionWithReplace(const PutByVariant& replace)
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000245{
246 ASSERT(m_kind == Transition);
247 ASSERT(replace.m_kind == Replace);
248 ASSERT(m_offset == replace.m_offset);
249 ASSERT(!replace.writesStructures());
250 ASSERT(!replace.reallocatesStorage());
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +0000251 ASSERT(replace.conditionSet().isEmpty());
fpizlo@apple.com3378c482014-07-27 23:14:40 +0000252
253 // This sort of merging only works when we have one path along which we add a new field which
254 // transitions to structure S while the other path was already on structure S. This doesn't
255 // work if we need to reallocate anything or if the replace path is polymorphic.
256
257 if (reallocatesStorage())
258 return false;
259
260 if (replace.m_oldStructure.onlyStructure() != m_newStructure)
261 return false;
262
263 m_oldStructure.merge(m_newStructure);
264 return true;
265}
266
mark.lam@apple.com17ae4902021-02-19 15:51:15 +0000267template<typename Visitor>
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000268void PutByVariant::visitAggregateImpl(Visitor& visitor)
269{
270 m_identifier.visitAggregate(visitor);
271}
272
273DEFINE_VISIT_AGGREGATE(PutByVariant);
274
275template<typename Visitor>
276void PutByVariant::markIfCheap(Visitor& visitor)
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000277{
278 m_oldStructure.markIfCheap(visitor);
279 if (m_newStructure)
280 m_newStructure->markIfCheap(visitor);
281}
282
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000283template void PutByVariant::markIfCheap(AbstractSlotVisitor&);
284template void PutByVariant::markIfCheap(SlotVisitor&);
mark.lam@apple.com17ae4902021-02-19 15:51:15 +0000285
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000286bool PutByVariant::finalize(VM& vm)
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000287{
ysuzuki@apple.comabaf3fd2019-03-25 22:40:58 +0000288 if (!m_oldStructure.isStillAlive(vm))
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000289 return false;
ysuzuki@apple.comabaf3fd2019-03-25 22:40:58 +0000290 if (m_newStructure && !vm.heap.isMarked(m_newStructure))
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000291 return false;
ysuzuki@apple.comabaf3fd2019-03-25 22:40:58 +0000292 if (!m_conditionSet.areStillLive(vm))
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000293 return false;
ysuzuki@apple.comabaf3fd2019-03-25 22:40:58 +0000294 if (m_callLinkStatus && !m_callLinkStatus->finalize(vm))
fpizlo@apple.comed2da802018-07-22 02:48:16 +0000295 return false;
296 return true;
297}
298
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000299void PutByVariant::dump(PrintStream& out) const
fpizlo@apple.com43219522014-02-25 02:02:50 +0000300{
ross.kirsling@sony.com2abe6c62020-05-11 02:36:05 +0000301 dumpInContext(out, nullptr);
fpizlo@apple.com43219522014-02-25 02:02:50 +0000302}
303
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000304void PutByVariant::dumpInContext(PrintStream& out, DumpContext* context) const
fpizlo@apple.com43219522014-02-25 02:02:50 +0000305{
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000306 out.print("<");
307 out.print("id='", m_identifier, "', ");
fpizlo@apple.com43219522014-02-25 02:02:50 +0000308 switch (kind()) {
309 case NotSet:
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000310 out.print("empty>");
fpizlo@apple.com43219522014-02-25 02:02:50 +0000311 return;
312
313 case Replace:
314 out.print(
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000315 "Replace: ", inContext(structure(), context), ", offset = ", offset(), ", ", ">");
fpizlo@apple.com43219522014-02-25 02:02:50 +0000316 return;
317
318 case Transition:
319 out.print(
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000320 "Transition: ", inContext(oldStructure(), context), " to ",
fpizlo@apple.comb41e6822014-07-25 20:55:17 +0000321 pointerDumpInContext(newStructure(), context), ", [",
sbarati@apple.comdedeea82019-01-16 01:41:42 +0000322 inContext(m_conditionSet, context), "], offset = ", offset(), ", ", ">");
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000323 return;
324
325 case Setter:
326 out.print(
ysuzuki@apple.com23c96142021-08-26 07:39:01 +0000327 "Setter: ", inContext(structure(), context), ", [",
fpizlo@apple.com6b62eaf2015-08-03 23:13:56 +0000328 inContext(m_conditionSet, context), "]");
fpizlo@apple.com2c4a7e92014-08-06 05:27:46 +0000329 out.print(", offset = ", m_offset);
330 out.print(", call = ", *m_callLinkStatus);
331 out.print(">");
fpizlo@apple.com43219522014-02-25 02:02:50 +0000332 return;
333 }
334
335 RELEASE_ASSERT_NOT_REACHED();
336}
337
338} // namespace JSC
339