2 * Copyright (C) 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "PutByIdVariant.h"
29 #include "CallLinkStatus.h"
30 #include "JSCInlines.h"
31 #include <wtf/ListDump.h>
35 PutByIdVariant::PutByIdVariant(const PutByIdVariant
& other
)
41 PutByIdVariant
& PutByIdVariant::operator=(const PutByIdVariant
& other
)
43 m_kind
= other
.m_kind
;
44 m_oldStructure
= other
.m_oldStructure
;
45 m_newStructure
= other
.m_newStructure
;
46 m_constantChecks
= other
.m_constantChecks
;
47 m_alternateBase
= other
.m_alternateBase
;
48 m_offset
= other
.m_offset
;
49 if (other
.m_callLinkStatus
)
50 m_callLinkStatus
= std::make_unique
<CallLinkStatus
>(*other
.m_callLinkStatus
);
52 m_callLinkStatus
= nullptr;
56 PutByIdVariant
PutByIdVariant::replace(const StructureSet
& structure
, PropertyOffset offset
)
58 PutByIdVariant result
;
59 result
.m_kind
= Replace
;
60 result
.m_oldStructure
= structure
;
61 result
.m_offset
= offset
;
65 PutByIdVariant
PutByIdVariant::transition(
66 const StructureSet
& oldStructure
, Structure
* newStructure
,
67 const IntendedStructureChain
* structureChain
, PropertyOffset offset
)
69 PutByIdVariant result
;
70 result
.m_kind
= Transition
;
71 result
.m_oldStructure
= oldStructure
;
72 result
.m_newStructure
= newStructure
;
74 structureChain
->gatherChecks(result
.m_constantChecks
);
75 result
.m_offset
= offset
;
79 PutByIdVariant
PutByIdVariant::setter(
80 const StructureSet
& structure
, PropertyOffset offset
,
81 IntendedStructureChain
* chain
, std::unique_ptr
<CallLinkStatus
> callLinkStatus
)
83 PutByIdVariant result
;
84 result
.m_kind
= Setter
;
85 result
.m_oldStructure
= structure
;
87 chain
->gatherChecks(result
.m_constantChecks
);
88 result
.m_alternateBase
= chain
->terminalPrototype();
90 result
.m_offset
= offset
;
91 result
.m_callLinkStatus
= WTF::move(callLinkStatus
);
95 Structure
* PutByIdVariant::oldStructureForTransition() const
97 ASSERT(kind() == Transition
);
98 ASSERT(m_oldStructure
.size() <= 2);
99 for (unsigned i
= m_oldStructure
.size(); i
--;) {
100 Structure
* structure
= m_oldStructure
[i
];
101 if (structure
!= m_newStructure
)
104 RELEASE_ASSERT_NOT_REACHED();
109 bool PutByIdVariant::writesStructures() const
120 bool PutByIdVariant::reallocatesStorage() const
124 return oldStructureForTransition()->outOfLineCapacity() != newStructure()->outOfLineCapacity();
132 bool PutByIdVariant::makesCalls() const
134 return kind() == Setter
;
137 StructureSet
PutByIdVariant::baseStructure() const
139 ASSERT(kind() == Setter
);
141 if (!m_alternateBase
)
144 Structure
* structure
= structureFor(m_constantChecks
, m_alternateBase
);
145 RELEASE_ASSERT(structure
);
149 bool PutByIdVariant::attemptToMerge(const PutByIdVariant
& other
)
151 if (m_offset
!= other
.m_offset
)
156 switch (other
.m_kind
) {
158 ASSERT(m_constantChecks
.isEmpty());
159 ASSERT(other
.m_constantChecks
.isEmpty());
161 m_oldStructure
.merge(other
.m_oldStructure
);
166 PutByIdVariant newVariant
= other
;
167 if (newVariant
.attemptToMergeTransitionWithReplace(*this)) {
179 switch (other
.m_kind
) {
181 return attemptToMergeTransitionWithReplace(other
);
192 bool PutByIdVariant::attemptToMergeTransitionWithReplace(const PutByIdVariant
& replace
)
194 ASSERT(m_kind
== Transition
);
195 ASSERT(replace
.m_kind
== Replace
);
196 ASSERT(m_offset
== replace
.m_offset
);
197 ASSERT(!replace
.writesStructures());
198 ASSERT(!replace
.reallocatesStorage());
200 // This sort of merging only works when we have one path along which we add a new field which
201 // transitions to structure S while the other path was already on structure S. This doesn't
202 // work if we need to reallocate anything or if the replace path is polymorphic.
204 if (reallocatesStorage())
207 if (replace
.m_oldStructure
.onlyStructure() != m_newStructure
)
210 m_oldStructure
.merge(m_newStructure
);
214 void PutByIdVariant::dump(PrintStream
& out
) const
216 dumpInContext(out
, 0);
219 void PutByIdVariant::dumpInContext(PrintStream
& out
, DumpContext
* context
) const
223 out
.print("<empty>");
228 "<Replace: ", inContext(structure(), context
), ", offset = ", offset(), ">");
233 "<Transition: ", inContext(oldStructure(), context
), " -> ",
234 pointerDumpInContext(newStructure(), context
), ", [",
235 listDumpInContext(constantChecks(), context
), "], offset = ", offset(), ">");
240 "<Setter: ", inContext(structure(), context
), ", [",
241 listDumpInContext(constantChecks(), context
), "]");
243 out
.print(", alternateBase = ", inContext(JSValue(m_alternateBase
), context
));
244 out
.print(", offset = ", m_offset
);
245 out
.print(", call = ", *m_callLinkStatus
);
250 RELEASE_ASSERT_NOT_REACHED();