We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / StructureRareData.cpp
1 /*
2  * Copyright (C) 2013-2017 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "StructureRareData.h"
28
29 #include "AdaptiveInferredPropertyValueWatchpointBase.h"
30 #include "JSPropertyNameEnumerator.h"
31 #include "JSString.h"
32 #include "JSCInlines.h"
33 #include "ObjectPropertyConditionSet.h"
34
35 namespace JSC {
36
37 const ClassInfo StructureRareData::s_info = { "StructureRareData", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(StructureRareData) };
38
39 Structure* StructureRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
40 {
41     return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
42 }
43
44 StructureRareData* StructureRareData::create(VM& vm, Structure* previous)
45 {
46     StructureRareData* rareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, previous);
47     rareData->finishCreation(vm);
48     return rareData;
49 }
50
51 void StructureRareData::destroy(JSCell* cell)
52 {
53     static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData();
54 }
55
56 StructureRareData::StructureRareData(VM& vm, Structure* previous)
57     : JSCell(vm, vm.structureRareDataStructure.get())
58     , m_giveUpOnObjectToStringValueCache(false)
59 {
60     if (previous)
61         m_previous.set(vm, this, previous);
62 }
63
64 void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
65 {
66     StructureRareData* thisObject = jsCast<StructureRareData*>(cell);
67     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
68
69     Base::visitChildren(thisObject, visitor);
70     visitor.append(thisObject->m_previous);
71     visitor.append(thisObject->m_objectToStringValue);
72     visitor.append(thisObject->m_cachedPropertyNameEnumerator);
73 }
74
75 JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const
76 {
77     return m_cachedPropertyNameEnumerator.get();
78 }
79
80 void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator)
81 {
82     m_cachedPropertyNameEnumerator.set(vm, this, enumerator);
83 }
84
85 // ----------- Object.prototype.toString() helper watchpoint classes -----------
86
87 class ObjectToStringAdaptiveInferredPropertyValueWatchpoint : public AdaptiveInferredPropertyValueWatchpointBase {
88 public:
89     typedef AdaptiveInferredPropertyValueWatchpointBase Base;
90     ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
91
92 private:
93     bool isValid() const override;
94     void handleFire(VM&, const FireDetail&) override;
95
96     StructureRareData* m_structureRareData;
97 };
98
99 class ObjectToStringAdaptiveStructureWatchpoint : public Watchpoint {
100 public:
101     ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
102
103     void install(VM&);
104
105 protected:
106     void fireInternal(VM&, const FireDetail&) override;
107     
108 private:
109     ObjectPropertyCondition m_key;
110     StructureRareData* m_structureRareData;
111 };
112
113 void StructureRareData::setObjectToStringValue(ExecState* exec, VM& vm, Structure* ownStructure, JSString* value, PropertySlot toStringTagSymbolSlot)
114 {
115     if (m_giveUpOnObjectToStringValueCache)
116         return;
117
118     ObjectPropertyConditionSet conditionSet;
119     if (toStringTagSymbolSlot.isValue()) {
120         // We don't handle the own property case of Symbol.toStringTag because we would never know if a new
121         // object transitioning to the same structure had the same value stored in Symbol.toStringTag.
122         // Additionally, this is a super unlikely case anyway.
123         if (!toStringTagSymbolSlot.isCacheable() || toStringTagSymbolSlot.slotBase()->structure(vm) == ownStructure)
124             return;
125
126
127         // This will not create a condition for the current structure but that is good because we know the Symbol.toStringTag
128         // is not on the ownStructure so we will transisition if one is added and this cache will no longer be used.
129         conditionSet = generateConditionsForPrototypePropertyHit(vm, this, exec, ownStructure, toStringTagSymbolSlot.slotBase(), vm.propertyNames->toStringTagSymbol.impl());
130         ASSERT(!conditionSet.isValid() || conditionSet.hasOneSlotBaseCondition());
131     } else if (toStringTagSymbolSlot.isUnset())
132         conditionSet = generateConditionsForPropertyMiss(vm, this, exec, ownStructure, vm.propertyNames->toStringTagSymbol.impl());
133     else
134         return;
135
136     if (!conditionSet.isValid()) {
137         m_giveUpOnObjectToStringValueCache = true;
138         return;
139     }
140
141     ObjectPropertyCondition equivCondition;
142     for (const ObjectPropertyCondition& condition : conditionSet) {
143         if (condition.condition().kind() == PropertyCondition::Presence) {
144             ASSERT(isValidOffset(condition.offset()));
145             condition.object()->structure(vm)->startWatchingPropertyForReplacements(vm, condition.offset());
146             equivCondition = condition.attemptToMakeEquivalenceWithoutBarrier(vm);
147
148             // The equivalence condition won't be watchable if we have already seen a replacement.
149             if (!equivCondition.isWatchable()) {
150                 m_giveUpOnObjectToStringValueCache = true;
151                 return;
152             }
153         } else if (!condition.isWatchable()) {
154             m_giveUpOnObjectToStringValueCache = true;
155             return;
156         }
157     }
158
159     ASSERT(conditionSet.structuresEnsureValidity());
160     for (ObjectPropertyCondition condition : conditionSet) {
161         if (condition.condition().kind() == PropertyCondition::Presence) {
162             m_objectToStringAdaptiveInferredValueWatchpoint = std::make_unique<ObjectToStringAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
163             m_objectToStringAdaptiveInferredValueWatchpoint->install(vm);
164         } else
165             m_objectToStringAdaptiveWatchpointSet.add(condition, this)->install(vm);
166     }
167
168     m_objectToStringValue.set(vm, this, value);
169 }
170
171 inline void StructureRareData::clearObjectToStringValue()
172 {
173     m_objectToStringAdaptiveWatchpointSet.clear();
174     m_objectToStringAdaptiveInferredValueWatchpoint.reset();
175     m_objectToStringValue.clear();
176 }
177
178 // ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
179
180 ObjectToStringAdaptiveStructureWatchpoint::ObjectToStringAdaptiveStructureWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
181     : m_key(key)
182     , m_structureRareData(structureRareData)
183 {
184     RELEASE_ASSERT(key.watchingRequiresStructureTransitionWatchpoint());
185     RELEASE_ASSERT(!key.watchingRequiresReplacementWatchpoint());
186 }
187
188 void ObjectToStringAdaptiveStructureWatchpoint::install(VM& vm)
189 {
190     RELEASE_ASSERT(m_key.isWatchable());
191
192     m_key.object()->structure(vm)->addTransitionWatchpoint(this);
193 }
194
195 void ObjectToStringAdaptiveStructureWatchpoint::fireInternal(VM& vm, const FireDetail&)
196 {
197     if (!m_structureRareData->isLive())
198         return;
199
200     if (m_key.isWatchable(PropertyCondition::EnsureWatchability)) {
201         install(vm);
202         return;
203     }
204
205     m_structureRareData->clearObjectToStringValue();
206 }
207
208 ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
209     : Base(key)
210     , m_structureRareData(structureRareData)
211 {
212 }
213
214 bool ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid() const
215 {
216     return m_structureRareData->isLive();
217 }
218
219 void ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire(VM&, const FireDetail&)
220 {
221     m_structureRareData->clearObjectToStringValue();
222 }
223
224 } // namespace JSC