Get rid of HeapRootVisitor and make SlotVisitor less painful to use
[WebKit-https.git] / Source / JavaScriptCore / bytecode / ObjectAllocationProfile.h
1 /*
2  * Copyright (C) 2013-2016 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 "VM.h"
29 #include "JSGlobalObject.h"
30 #include "ObjectPrototype.h"
31 #include "SlotVisitor.h"
32 #include "WriteBarrier.h"
33
34 namespace JSC {
35
36 class ObjectAllocationProfile {
37     friend class LLIntOffsetsExtractor;
38 public:
39     static ptrdiff_t offsetOfAllocator() { return OBJECT_OFFSETOF(ObjectAllocationProfile, m_allocator); }
40     static ptrdiff_t offsetOfStructure() { return OBJECT_OFFSETOF(ObjectAllocationProfile, m_structure); }
41     static ptrdiff_t offsetOfInlineCapacity() { return OBJECT_OFFSETOF(ObjectAllocationProfile, m_inlineCapacity); }
42
43     ObjectAllocationProfile()
44         : m_allocator(0)
45         , m_inlineCapacity(0)
46     {
47     }
48
49     bool isNull() { return !m_structure; }
50
51     void initialize(VM& vm, JSCell* owner, JSObject* prototype, unsigned inferredInlineCapacity)
52     {
53         ASSERT(!m_allocator);
54         ASSERT(!m_structure);
55         ASSERT(!m_inlineCapacity);
56
57         unsigned inlineCapacity = 0;
58         if (inferredInlineCapacity < JSFinalObject::defaultInlineCapacity()) {
59             // Try to shrink the object based on static analysis.
60             inferredInlineCapacity += possibleDefaultPropertyCount(vm, prototype);
61
62             if (!inferredInlineCapacity) {
63                 // Empty objects are rare, so most likely the static analyzer just didn't
64                 // see the real initializer function. This can happen with helper functions.
65                 inferredInlineCapacity = JSFinalObject::defaultInlineCapacity();
66             } else if (inferredInlineCapacity > JSFinalObject::defaultInlineCapacity()) {
67                 // Default properties are weak guesses, so don't allow them to turn a small
68                 // object into a large object.
69                 inferredInlineCapacity = JSFinalObject::defaultInlineCapacity();
70             }
71
72             inlineCapacity = inferredInlineCapacity;
73             ASSERT(inlineCapacity < JSFinalObject::maxInlineCapacity());
74         } else {
75             // Normal or large object.
76             inlineCapacity = inferredInlineCapacity;
77             if (inlineCapacity > JSFinalObject::maxInlineCapacity())
78                 inlineCapacity = JSFinalObject::maxInlineCapacity();
79         }
80
81         ASSERT(inlineCapacity > 0);
82         ASSERT(inlineCapacity <= JSFinalObject::maxInlineCapacity());
83
84         size_t allocationSize = JSFinalObject::allocationSize(inlineCapacity);
85         MarkedAllocator* allocator = vm.heap.allocatorForObjectWithoutDestructor(allocationSize);
86         
87         // Take advantage of extra inline capacity available in the size class.
88         if (allocator) {
89             size_t slop = (allocator->cellSize() - allocationSize) / sizeof(WriteBarrier<Unknown>);
90             inlineCapacity += slop;
91             if (inlineCapacity > JSFinalObject::maxInlineCapacity())
92                 inlineCapacity = JSFinalObject::maxInlineCapacity();
93         }
94
95         Structure* structure = vm.prototypeMap.emptyObjectStructureForPrototype(prototype, inlineCapacity);
96
97         // Ensure that if another thread sees the structure, it will see it properly created
98         WTF::storeStoreFence();
99
100         m_allocator = allocator;
101         m_structure.set(vm, owner, structure);
102         m_inlineCapacity = inlineCapacity;
103     }
104
105     Structure* structure()
106     {
107         Structure* structure = m_structure.get();
108         // Ensure that if we see the structure, it has been properly created
109         WTF::loadLoadFence();
110         return structure;
111     }
112     unsigned inlineCapacity() { return m_inlineCapacity; }
113
114     void clear()
115     {
116         m_allocator = 0;
117         m_structure.clear();
118         m_inlineCapacity = 0;
119         ASSERT(isNull());
120     }
121
122     void visitAggregate(SlotVisitor& visitor)
123     {
124         visitor.append(m_structure);
125     }
126
127 private:
128
129     unsigned possibleDefaultPropertyCount(VM& vm, JSObject* prototype)
130     {
131         if (prototype == prototype->globalObject()->objectPrototype())
132             return 0;
133
134         size_t count = 0;
135         PropertyNameArray propertyNameArray(&vm, PropertyNameMode::StringsAndSymbols);
136         prototype->structure()->getPropertyNamesFromStructure(vm, propertyNameArray, EnumerationMode());
137         PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArray.data()->propertyNameVector();
138         for (size_t i = 0; i < propertyNameVector.size(); ++i) {
139             JSValue value = prototype->getDirect(vm, propertyNameVector[i]);
140
141             // Functions are common, and are usually class-level objects that are not overridden.
142             if (jsDynamicCast<JSFunction*>(value))
143                 continue;
144
145             ++count;
146
147         }
148         return count;
149     }
150
151     MarkedAllocator* m_allocator; // Precomputed to make things easier for generated code.
152     WriteBarrier<Structure> m_structure;
153     unsigned m_inlineCapacity;
154 };
155
156 } // namespace JSC