1/*
2 * Copyright (C) 2015-2019 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 "InternalFunctionAllocationProfile.h"
29#include "JSCast.h"
30#include "ObjectAllocationProfile.h"
31#include "PackedCellPtr.h"
32#include "Watchpoint.h"
33
34namespace JSC {
35
36class JSGlobalObject;
37class LLIntOffsetsExtractor;
38namespace DFG {
39class SpeculativeJIT;
40class JITCompiler;
41}
42
43class FunctionRareData final : public JSCell {
44 friend class JIT;
45 friend class DFG::SpeculativeJIT;
46 friend class DFG::JITCompiler;
47 friend class VM;
48
49public:
50 typedef JSCell Base;
51 static constexpr unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
52
53 static FunctionRareData* create(VM&);
54
55 static constexpr bool needsDestruction = true;
56
57 template<typename CellType, SubspaceAccess mode>
58 static IsoSubspace* subspaceFor(VM& vm)
59 {
60 return vm.functionRareDataSpace<mode>();
61 }
62
63 static void destroy(JSCell*);
64
65 static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
66
67 static void visitChildren(JSCell*, SlotVisitor&);
68
69 DECLARE_INFO;
70
71 static inline ptrdiff_t offsetOfObjectAllocationProfile() { return OBJECT_OFFSETOF(FunctionRareData, m_objectAllocationProfile); }
72 static inline ptrdiff_t offsetOfAllocationProfileWatchpointSet() { return OBJECT_OFFSETOF(FunctionRareData, m_allocationProfileWatchpointSet); }
73 static inline ptrdiff_t offsetOfInternalFunctionAllocationProfile() { return OBJECT_OFFSETOF(FunctionRareData, m_internalFunctionAllocationProfile); }
74 static inline ptrdiff_t offsetOfBoundFunctionStructure() { return OBJECT_OFFSETOF(FunctionRareData, m_boundFunctionStructure); }
75 static inline ptrdiff_t offsetOfAllocationProfileClearingWatchpoint() { return OBJECT_OFFSETOF(FunctionRareData, m_allocationProfileClearingWatchpoint); }
76 static inline ptrdiff_t offsetOfHasReifiedLength() { return OBJECT_OFFSETOF(FunctionRareData, m_hasReifiedLength); }
77 static inline ptrdiff_t offsetOfHasReifiedName() { return OBJECT_OFFSETOF(FunctionRareData, m_hasReifiedName); }
78
79 ObjectAllocationProfileWithPrototype* objectAllocationProfile()
80 {
81 return &m_objectAllocationProfile;
82 }
83
84 Structure* objectAllocationStructure() { return m_objectAllocationProfile.structure(); }
85 JSObject* objectAllocationPrototype() { return m_objectAllocationProfile.prototype(); }
86
87 InlineWatchpointSet& allocationProfileWatchpointSet()
88 {
89 return m_allocationProfileWatchpointSet;
90 }
91
92 void clear(const char* reason);
93
94 void initializeObjectAllocationProfile(VM&, JSGlobalObject*, JSObject* prototype, size_t inlineCapacity, JSFunction* constructor);
95
96 bool isObjectAllocationProfileInitialized() { return !m_objectAllocationProfile.isNull(); }
97
98 Structure* internalFunctionAllocationStructure() { return m_internalFunctionAllocationProfile.structure(); }
99 Structure* createInternalFunctionAllocationStructureFromBase(VM& vm, JSGlobalObject* baseGlobalObject, JSObject* prototype, Structure* baseStructure)
100 {
101 initializeAllocationProfileWatchpointSet();
102 return m_internalFunctionAllocationProfile.createAllocationStructureFromBase(vm, baseGlobalObject, this, prototype, baseStructure);
103 }
104 void clearInternalFunctionAllocationProfile(const char* reason)
105 {
106 m_internalFunctionAllocationProfile.clear();
107 m_allocationProfileWatchpointSet.fireAll(vm(), reason);
108 }
109
110 void initializeAllocationProfileWatchpointSet()
111 {
112 if (m_allocationProfileWatchpointSet.isStillValid())
113 m_allocationProfileWatchpointSet.startWatching();
114 }
115
116 Structure* getBoundFunctionStructure() { return m_boundFunctionStructure.get(); }
117 void setBoundFunctionStructure(VM& vm, Structure* structure) { m_boundFunctionStructure.set(vm, this, structure); }
118
119 bool hasReifiedLength() const { return m_hasReifiedLength; }
120 void setHasReifiedLength() { m_hasReifiedLength = true; }
121 bool hasReifiedName() const { return m_hasReifiedName; }
122 void setHasReifiedName() { m_hasReifiedName = true; }
123
124 bool hasAllocationProfileClearingWatchpoint() const { return !!m_allocationProfileClearingWatchpoint; }
125 Watchpoint* createAllocationProfileClearingWatchpoint();
126 class AllocationProfileClearingWatchpoint;
127
128protected:
129 explicit FunctionRareData(VM&);
130 ~FunctionRareData();
131
132private:
133 friend class LLIntOffsetsExtractor;
134
135 // Ideally, there would only be one allocation profile for subclassing but due to Reflect.construct we
136 // have two. There are some pros and cons in comparison to our current system to using the same profile
137 // for both JS constructors and subclasses of builtin constructors:
138 //
139 // 1) + Uses less memory.
140 // 2) + Conceptually simplier as there is only one profile.
141 // 3) - We would need a check in all JSFunction object creations (both with classes and without) that the
142 // new.target's profiled structure has a JSFinalObject ClassInfo. This is needed, for example, if we have
143 // `Reflect.construct(Array, args, myConstructor)` since myConstructor will be the new.target of Array
144 // the Array constructor will set the allocation profile of myConstructor to hold an Array structure
145 //
146 // We don't really care about 1) since this memory is rare and small in total. 2) is unfortunate but is
147 // probably outweighed by the cost of 3).
148 ObjectAllocationProfileWithPrototype m_objectAllocationProfile;
149 InlineWatchpointSet m_allocationProfileWatchpointSet;
150 InternalFunctionAllocationProfile m_internalFunctionAllocationProfile;
151 WriteBarrier<Structure> m_boundFunctionStructure;
152 std::unique_ptr<AllocationProfileClearingWatchpoint> m_allocationProfileClearingWatchpoint;
153 bool m_hasReifiedLength { false };
154 bool m_hasReifiedName { false };
155};
156
157class FunctionRareData::AllocationProfileClearingWatchpoint final : public Watchpoint {
158public:
159 AllocationProfileClearingWatchpoint(FunctionRareData* rareData)
160 : Watchpoint(Watchpoint::Type::FunctionRareDataAllocationProfileClearing)
161 , m_rareData(rareData)
162 { }
163
164 void fireInternal(VM&, const FireDetail&);
165
166private:
167 // Own destructor may not be called. Keep members trivially destructible.
168 JSC_WATCHPOINT_FIELD(PackedCellPtr<FunctionRareData>, m_rareData);
169};
170
171inline Watchpoint* FunctionRareData::createAllocationProfileClearingWatchpoint()
172{
173 RELEASE_ASSERT(!hasAllocationProfileClearingWatchpoint());
174 m_allocationProfileClearingWatchpoint = makeUnique<AllocationProfileClearingWatchpoint>(this);
175 return m_allocationProfileClearingWatchpoint.get();
176}
177
178} // namespace JSC
179