[JSC] Compress Watchpoint size by using enum type and Packed<> data structure
[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 "JSImmutableButterfly.h"
31 #include "JSPropertyNameEnumerator.h"
32 #include "JSString.h"
33 #include "JSCInlines.h"
34 #include "ObjectPropertyConditionSet.h"
35 #include "ObjectToStringAdaptiveStructureWatchpoint.h"
36
37 namespace JSC {
38
39 const ClassInfo StructureRareData::s_info = { "StructureRareData", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(StructureRareData) };
40
41 Structure* StructureRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
42 {
43     return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
44 }
45
46 StructureRareData* StructureRareData::create(VM& vm, Structure* previous)
47 {
48     StructureRareData* rareData = new (NotNull, allocateCell<StructureRareData>(vm.heap)) StructureRareData(vm, previous);
49     rareData->finishCreation(vm);
50     return rareData;
51 }
52
53 void StructureRareData::destroy(JSCell* cell)
54 {
55     static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData();
56 }
57
58 StructureRareData::StructureRareData(VM& vm, Structure* previous)
59     : JSCell(vm, vm.structureRareDataStructure.get())
60     , m_giveUpOnObjectToStringValueCache(false)
61 {
62     if (previous)
63         m_previous.set(vm, this, previous);
64 }
65
66 void StructureRareData::visitChildren(JSCell* cell, SlotVisitor& visitor)
67 {
68     StructureRareData* thisObject = jsCast<StructureRareData*>(cell);
69     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
70
71     Base::visitChildren(thisObject, visitor);
72     visitor.append(thisObject->m_previous);
73     visitor.append(thisObject->m_objectToStringValue);
74     visitor.append(thisObject->m_cachedPropertyNameEnumerator);
75     auto* cachedOwnKeys = thisObject->m_cachedOwnKeys.unvalidatedGet();
76     if (cachedOwnKeys != cachedOwnKeysSentinel())
77         visitor.appendUnbarriered(cachedOwnKeys);
78 }
79
80 // ----------- Object.prototype.toString() helper watchpoint classes -----------
81
82 class ObjectToStringAdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
83 public:
84     typedef AdaptiveInferredPropertyValueWatchpointBase Base;
85     ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
86
87 private:
88     bool isValid() const override;
89     void handleFire(VM&, const FireDetail&) override;
90
91     StructureRareData* m_structureRareData;
92 };
93
94 void StructureRareData::setObjectToStringValue(ExecState* exec, VM& vm, Structure* ownStructure, JSString* value, PropertySlot toStringTagSymbolSlot)
95 {
96     if (m_giveUpOnObjectToStringValueCache)
97         return;
98
99     ObjectPropertyConditionSet conditionSet;
100     if (toStringTagSymbolSlot.isValue()) {
101         // We don't handle the own property case of Symbol.toStringTag because we would never know if a new
102         // object transitioning to the same structure had the same value stored in Symbol.toStringTag.
103         // Additionally, this is a super unlikely case anyway.
104         if (!toStringTagSymbolSlot.isCacheable() || toStringTagSymbolSlot.slotBase()->structure(vm) == ownStructure)
105             return;
106
107
108         // This will not create a condition for the current structure but that is good because we know the Symbol.toStringTag
109         // is not on the ownStructure so we will transisition if one is added and this cache will no longer be used.
110         conditionSet = generateConditionsForPrototypePropertyHit(vm, this, exec, ownStructure, toStringTagSymbolSlot.slotBase(), vm.propertyNames->toStringTagSymbol.impl());
111         ASSERT(!conditionSet.isValid() || conditionSet.hasOneSlotBaseCondition());
112     } else if (toStringTagSymbolSlot.isUnset())
113         conditionSet = generateConditionsForPropertyMiss(vm, this, exec, ownStructure, vm.propertyNames->toStringTagSymbol.impl());
114     else
115         return;
116
117     if (!conditionSet.isValid()) {
118         m_giveUpOnObjectToStringValueCache = true;
119         return;
120     }
121
122     ObjectPropertyCondition equivCondition;
123     for (const ObjectPropertyCondition& condition : conditionSet) {
124         if (condition.condition().kind() == PropertyCondition::Presence) {
125             ASSERT(isValidOffset(condition.offset()));
126             condition.object()->structure(vm)->startWatchingPropertyForReplacements(vm, condition.offset());
127             equivCondition = condition.attemptToMakeEquivalenceWithoutBarrier(vm);
128
129             // The equivalence condition won't be watchable if we have already seen a replacement.
130             if (!equivCondition.isWatchable()) {
131                 m_giveUpOnObjectToStringValueCache = true;
132                 return;
133             }
134         } else if (!condition.isWatchable()) {
135             m_giveUpOnObjectToStringValueCache = true;
136             return;
137         }
138     }
139
140     ASSERT(conditionSet.structuresEnsureValidity());
141     for (ObjectPropertyCondition condition : conditionSet) {
142         if (condition.condition().kind() == PropertyCondition::Presence) {
143             m_objectToStringAdaptiveInferredValueWatchpoint = std::make_unique<ObjectToStringAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
144             m_objectToStringAdaptiveInferredValueWatchpoint->install(vm);
145         } else
146             m_objectToStringAdaptiveWatchpointSet.add(condition, this)->install(vm);
147     }
148
149     m_objectToStringValue.set(vm, this, value);
150 }
151
152 void StructureRareData::clearObjectToStringValue()
153 {
154     m_objectToStringAdaptiveWatchpointSet.clear();
155     m_objectToStringAdaptiveInferredValueWatchpoint.reset();
156     m_objectToStringValue.clear();
157 }
158
159 void StructureRareData::finalizeUnconditionally(VM& vm)
160 {
161     if (m_objectToStringAdaptiveInferredValueWatchpoint) {
162         if (!m_objectToStringAdaptiveInferredValueWatchpoint->key().isStillLive(vm)) {
163             clearObjectToStringValue();
164             return;
165         }
166     }
167     for (auto* watchpoint : m_objectToStringAdaptiveWatchpointSet) {
168         if (!watchpoint->key().isStillLive(vm)) {
169             clearObjectToStringValue();
170             return;
171         }
172     }
173 }
174
175 // ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
176
177 ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
178     : Base(key)
179     , m_structureRareData(structureRareData)
180 {
181 }
182
183 bool ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid() const
184 {
185     return m_structureRareData->isLive();
186 }
187
188 void ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire(VM&, const FireDetail&)
189 {
190     m_structureRareData->clearObjectToStringValue();
191 }
192
193 } // namespace JSC