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#pragma once
27
28#include "ObjectPropertyConditionSet.h"
29#include "PropertyOffset.h"
30#include "StructureSet.h"
31
32namespace JSC {
33
34class CallLinkStatus;
35
36class PutByIdVariant {
37 WTF_MAKE_FAST_ALLOCATED;
38public:
39 enum Kind {
40 NotSet,
41 Replace,
42 Transition,
43 Setter
44 };
45
46 PutByIdVariant()
47 : m_kind(NotSet)
48 , m_offset(invalidOffset)
49 , m_newStructure(nullptr)
50 {
51 }
52
53 PutByIdVariant(const PutByIdVariant&);
54 PutByIdVariant& operator=(const PutByIdVariant&);
55
56 static PutByIdVariant replace(const StructureSet&, PropertyOffset);
57
58 static PutByIdVariant transition(
59 const StructureSet& oldStructure, Structure* newStructure,
60 const ObjectPropertyConditionSet&, PropertyOffset);
61
62 static PutByIdVariant setter(
63 const StructureSet&, PropertyOffset, const ObjectPropertyConditionSet&,
64 std::unique_ptr<CallLinkStatus>);
65
66 Kind kind() const { return m_kind; }
67
68 bool isSet() const { return kind() != NotSet; }
69 bool operator!() const { return !isSet(); }
70
71 const StructureSet& structure() const
72 {
73 ASSERT(kind() == Replace || kind() == Setter);
74 return m_oldStructure;
75 }
76
77 const StructureSet& oldStructure() const
78 {
79 ASSERT(kind() == Transition || kind() == Replace || kind() == Setter);
80 return m_oldStructure;
81 }
82
83 const StructureSet& structureSet() const
84 {
85 return oldStructure();
86 }
87
88 StructureSet& oldStructure()
89 {
90 ASSERT(kind() == Transition || kind() == Replace || kind() == Setter);
91 return m_oldStructure;
92 }
93
94 StructureSet& structureSet()
95 {
96 return oldStructure();
97 }
98
99 Structure* oldStructureForTransition() const;
100
101 Structure* newStructure() const
102 {
103 ASSERT(kind() == Transition);
104 return m_newStructure;
105 }
106
107 void fixTransitionToReplaceIfNecessary();
108
109 bool writesStructures() const;
110 bool reallocatesStorage() const;
111 bool makesCalls() const;
112
113 const ObjectPropertyConditionSet& conditionSet() const { return m_conditionSet; }
114
115 // We don't support intrinsics for Setters (it would be sweet if we did) but we need this for templated helpers.
116 Intrinsic intrinsic() const { return NoIntrinsic; }
117
118 // This is needed for templated helpers.
119 bool isPropertyUnset() const { return false; }
120
121 PropertyOffset offset() const
122 {
123 ASSERT(isSet());
124 return m_offset;
125 }
126
127 CallLinkStatus* callLinkStatus() const
128 {
129 ASSERT(kind() == Setter);
130 return m_callLinkStatus.get();
131 }
132
133 bool attemptToMerge(const PutByIdVariant& other);
134
135 void markIfCheap(SlotVisitor&);
136 bool finalize(VM&);
137
138 void dump(PrintStream&) const;
139 void dumpInContext(PrintStream&, DumpContext*) const;
140
141 bool overlaps(const PutByIdVariant& other)
142 {
143 return structureSet().overlaps(other.structureSet());
144 }
145
146private:
147 bool attemptToMergeTransitionWithReplace(const PutByIdVariant& replace);
148
149 Kind m_kind;
150 PropertyOffset m_offset;
151 StructureSet m_oldStructure;
152 Structure* m_newStructure { nullptr };
153 ObjectPropertyConditionSet m_conditionSet;
154 std::unique_ptr<CallLinkStatus> m_callLinkStatus;
155};
156
157} // namespace JSC
158