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
37namespace JSC {
38
39const ClassInfo StructureRareData::s_info = { "StructureRareData", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(StructureRareData) };
40
41Structure* StructureRareData::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
42{
43 return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info());
44}
45
46StructureRareData* 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
53void StructureRareData::destroy(JSCell* cell)
54{
55 static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData();
56}
57
58StructureRareData::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
66void 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
82class ObjectToStringAdaptiveInferredPropertyValueWatchpoint final : public AdaptiveInferredPropertyValueWatchpointBase {
83public:
84 typedef AdaptiveInferredPropertyValueWatchpointBase Base;
85 ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition&, StructureRareData*);
86
87private:
88 bool isValid() const override;
89 void handleFire(VM&, const FireDetail&) override;
90
91 StructureRareData* m_structureRareData;
92};
93
94void StructureRareData::setObjectToStringValue(JSGlobalObject* globalObject, 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 preparePrototypeChainForCaching(globalObject, ownStructure, toStringTagSymbolSlot.slotBase());
111 conditionSet = generateConditionsForPrototypePropertyHit(vm, this, globalObject, ownStructure, toStringTagSymbolSlot.slotBase(), vm.propertyNames->toStringTagSymbol.impl());
112 ASSERT(!conditionSet.isValid() || conditionSet.hasOneSlotBaseCondition());
113 } else if (toStringTagSymbolSlot.isUnset()) {
114 preparePrototypeChainForCaching(globalObject, ownStructure, nullptr);
115 conditionSet = generateConditionsForPropertyMiss(vm, this, globalObject, ownStructure, vm.propertyNames->toStringTagSymbol.impl());
116 } else
117 return;
118
119 if (!conditionSet.isValid()) {
120 m_giveUpOnObjectToStringValueCache = true;
121 return;
122 }
123
124 ObjectPropertyCondition equivCondition;
125 for (const ObjectPropertyCondition& condition : conditionSet) {
126 if (condition.condition().kind() == PropertyCondition::Presence) {
127 ASSERT(isValidOffset(condition.offset()));
128 condition.object()->structure(vm)->startWatchingPropertyForReplacements(vm, condition.offset());
129 equivCondition = condition.attemptToMakeEquivalenceWithoutBarrier(vm);
130
131 // The equivalence condition won't be watchable if we have already seen a replacement.
132 if (!equivCondition.isWatchable()) {
133 m_giveUpOnObjectToStringValueCache = true;
134 return;
135 }
136 } else if (!condition.isWatchable()) {
137 m_giveUpOnObjectToStringValueCache = true;
138 return;
139 }
140 }
141
142 ASSERT(conditionSet.structuresEnsureValidity());
143 for (ObjectPropertyCondition condition : conditionSet) {
144 if (condition.condition().kind() == PropertyCondition::Presence) {
145 m_objectToStringAdaptiveInferredValueWatchpoint = makeUnique<ObjectToStringAdaptiveInferredPropertyValueWatchpoint>(equivCondition, this);
146 m_objectToStringAdaptiveInferredValueWatchpoint->install(vm);
147 } else
148 m_objectToStringAdaptiveWatchpointSet.add(condition, this)->install(vm);
149 }
150
151 m_objectToStringValue.set(vm, this, value);
152}
153
154void StructureRareData::clearObjectToStringValue()
155{
156 m_objectToStringAdaptiveWatchpointSet.clear();
157 m_objectToStringAdaptiveInferredValueWatchpoint.reset();
158 m_objectToStringValue.clear();
159}
160
161void StructureRareData::finalizeUnconditionally(VM& vm)
162{
163 if (m_objectToStringAdaptiveInferredValueWatchpoint) {
164 if (!m_objectToStringAdaptiveInferredValueWatchpoint->key().isStillLive(vm)) {
165 clearObjectToStringValue();
166 return;
167 }
168 }
169 for (auto* watchpoint : m_objectToStringAdaptiveWatchpointSet) {
170 if (!watchpoint->key().isStillLive(vm)) {
171 clearObjectToStringValue();
172 return;
173 }
174 }
175}
176
177// ------------- Methods for Object.prototype.toString() helper watchpoint classes --------------
178
179ObjectToStringAdaptiveInferredPropertyValueWatchpoint::ObjectToStringAdaptiveInferredPropertyValueWatchpoint(const ObjectPropertyCondition& key, StructureRareData* structureRareData)
180 : Base(key)
181 , m_structureRareData(structureRareData)
182{
183}
184
185bool ObjectToStringAdaptiveInferredPropertyValueWatchpoint::isValid() const
186{
187 return m_structureRareData->isLive();
188}
189
190void ObjectToStringAdaptiveInferredPropertyValueWatchpoint::handleFire(VM&, const FireDetail&)
191{
192 m_structureRareData->clearObjectToStringValue();
193}
194
195} // namespace JSC
196