1/*
2 * Copyright (C) 2014-2018 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#include "config.h"
27#include "GetByIdVariant.h"
28
29#include "CallLinkStatus.h"
30#include "JSCInlines.h"
31#include <wtf/ListDump.h>
32
33namespace JSC {
34
35GetByIdVariant::GetByIdVariant(
36 const StructureSet& structureSet, PropertyOffset offset,
37 const ObjectPropertyConditionSet& conditionSet,
38 std::unique_ptr<CallLinkStatus> callLinkStatus,
39 JSFunction* intrinsicFunction,
40 FunctionPtr<OperationPtrTag> customAccessorGetter,
41 Optional<DOMAttributeAnnotation> domAttribute)
42 : m_structureSet(structureSet)
43 , m_conditionSet(conditionSet)
44 , m_offset(offset)
45 , m_callLinkStatus(WTFMove(callLinkStatus))
46 , m_intrinsicFunction(intrinsicFunction)
47 , m_customAccessorGetter(customAccessorGetter)
48 , m_domAttribute(domAttribute)
49{
50 if (!structureSet.size()) {
51 ASSERT(offset == invalidOffset);
52 ASSERT(conditionSet.isEmpty());
53 }
54 if (intrinsicFunction)
55 ASSERT(intrinsic() != NoIntrinsic);
56}
57
58GetByIdVariant::~GetByIdVariant() { }
59
60GetByIdVariant::GetByIdVariant(const GetByIdVariant& other)
61 : GetByIdVariant()
62{
63 *this = other;
64}
65
66GetByIdVariant& GetByIdVariant::operator=(const GetByIdVariant& other)
67{
68 m_structureSet = other.m_structureSet;
69 m_conditionSet = other.m_conditionSet;
70 m_offset = other.m_offset;
71 m_intrinsicFunction = other.m_intrinsicFunction;
72 m_customAccessorGetter = other.m_customAccessorGetter;
73 m_domAttribute = other.m_domAttribute;
74 if (other.m_callLinkStatus)
75 m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus);
76 else
77 m_callLinkStatus = nullptr;
78 return *this;
79}
80
81inline bool GetByIdVariant::canMergeIntrinsicStructures(const GetByIdVariant& other) const
82{
83 if (m_intrinsicFunction != other.m_intrinsicFunction)
84 return false;
85 switch (intrinsic()) {
86 case TypedArrayByteLengthIntrinsic: {
87 // We can merge these sets as long as the element size of the two sets is the same.
88 TypedArrayType thisType = (*m_structureSet.begin())->classInfo()->typedArrayStorageType;
89 TypedArrayType otherType = (*other.m_structureSet.begin())->classInfo()->typedArrayStorageType;
90
91 ASSERT(isTypedView(thisType) && isTypedView(otherType));
92
93 return logElementSize(thisType) == logElementSize(otherType);
94 }
95
96 default:
97 return true;
98 }
99 RELEASE_ASSERT_NOT_REACHED();
100}
101
102bool GetByIdVariant::attemptToMerge(const GetByIdVariant& other)
103{
104 if (m_offset != other.m_offset)
105 return false;
106
107 if (m_callLinkStatus || other.m_callLinkStatus) {
108 if (!(m_callLinkStatus && other.m_callLinkStatus))
109 return false;
110 }
111
112 if (!canMergeIntrinsicStructures(other))
113 return false;
114
115 if (m_customAccessorGetter != other.m_customAccessorGetter)
116 return false;
117
118 if (m_domAttribute || other.m_domAttribute) {
119 if (!(m_domAttribute && other.m_domAttribute))
120 return false;
121 if (*m_domAttribute != *other.m_domAttribute)
122 return false;
123 }
124
125 if (m_conditionSet.isEmpty() != other.m_conditionSet.isEmpty())
126 return false;
127
128 ObjectPropertyConditionSet mergedConditionSet;
129 if (!m_conditionSet.isEmpty()) {
130 mergedConditionSet = m_conditionSet.mergedWith(other.m_conditionSet);
131 if (!mergedConditionSet.isValid())
132 return false;
133 // If this is a hit variant, one slot base should exist. If this is not a hit variant, the slot base is not necessary.
134 if (!isPropertyUnset() && !mergedConditionSet.hasOneSlotBaseCondition())
135 return false;
136 }
137 m_conditionSet = mergedConditionSet;
138
139 m_structureSet.merge(other.m_structureSet);
140
141 if (m_callLinkStatus)
142 m_callLinkStatus->merge(*other.m_callLinkStatus);
143
144 return true;
145}
146
147void GetByIdVariant::markIfCheap(SlotVisitor& visitor)
148{
149 m_structureSet.markIfCheap(visitor);
150}
151
152bool GetByIdVariant::finalize(VM& vm)
153{
154 if (!m_structureSet.isStillAlive(vm))
155 return false;
156 if (!m_conditionSet.areStillLive(vm))
157 return false;
158 if (m_callLinkStatus && !m_callLinkStatus->finalize(vm))
159 return false;
160 if (m_intrinsicFunction && !vm.heap.isMarked(m_intrinsicFunction))
161 return false;
162 return true;
163}
164
165void GetByIdVariant::dump(PrintStream& out) const
166{
167 dumpInContext(out, 0);
168}
169
170void GetByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const
171{
172 if (!isSet()) {
173 out.print("<empty>");
174 return;
175 }
176
177 out.print(
178 "<", inContext(structureSet(), context), ", ", inContext(m_conditionSet, context));
179 out.print(", offset = ", offset());
180 if (m_callLinkStatus)
181 out.print(", call = ", *m_callLinkStatus);
182 if (m_intrinsicFunction)
183 out.print(", intrinsic = ", *m_intrinsicFunction);
184 if (m_customAccessorGetter)
185 out.print(", customaccessorgetter = ", RawPointer(m_customAccessorGetter.executableAddress()));
186 if (m_domAttribute) {
187 out.print(", domclass = ", RawPointer(m_domAttribute->classInfo));
188 if (m_domAttribute->domJIT)
189 out.print(", domjit = ", RawPointer(m_domAttribute->domJIT));
190 }
191 out.print(">");
192}
193
194} // namespace JSC
195
196