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