1/* 2 * Copyright (C) 2012, 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#include "config.h" 27#include "ProfilerCompilation.h" 28 29#include "JSGlobalObject.h" 30#include "ObjectConstructor.h" 31#include "Operations.h" 32#include "ProfilerDatabase.h" 33#include <wtf/StringPrintStream.h> 34 35namespace JSC { namespace Profiler { 36 37Compilation::Compilation(Bytecodes* bytecodes, CompilationKind kind) 38 : m_bytecodes(bytecodes) 39 , m_kind(kind) 40 , m_numInlinedGetByIds(0) 41 , m_numInlinedPutByIds(0) 42 , m_numInlinedCalls(0) 43{ 44} 45 46Compilation::~Compilation() { } 47 48void Compilation::addProfiledBytecodes(Database& database, CodeBlock* profiledBlock) 49{ 50 Bytecodes* bytecodes = database.ensureBytecodesFor(profiledBlock); 51 52 // First make sure that we haven't already added profiled bytecodes for this code 53 // block. We do this using an O(N) search because I suspect that this list will 54 // tend to be fairly small, and the additional space costs of having a HashMap/Set 55 // would be greater than the time cost of occasionally doing this search. 56 57 for (unsigned i = m_profiledBytecodes.size(); i--;) { 58 if (m_profiledBytecodes[i].bytecodes() == bytecodes) 59 return; 60 } 61 62 m_profiledBytecodes.append(ProfiledBytecodes(bytecodes, profiledBlock)); 63} 64 65void Compilation::addDescription(const CompiledBytecode& compiledBytecode) 66{ 67 m_descriptions.append(compiledBytecode); 68} 69 70ExecutionCounter* Compilation::executionCounterFor(const OriginStack& origin) 71{ 72 HashMap<OriginStack, OwnPtr<ExecutionCounter> >::iterator iter = m_counters.find(origin); 73 if (iter != m_counters.end()) 74 return iter->value.get(); 75 76 OwnPtr<ExecutionCounter> counter = adoptPtr(new ExecutionCounter()); 77 ExecutionCounter* result = counter.get(); 78 m_counters.add(origin, counter.release()); 79 return result; 80} 81 82void Compilation::addOSRExitSite(const Vector<const void*>& codeAddresses) 83{ 84 m_osrExitSites.append(OSRExitSite(codeAddresses)); 85} 86 87OSRExit* Compilation::addOSRExit(unsigned id, const OriginStack& originStack, ExitKind exitKind, bool isWatchpoint) 88{ 89 m_osrExits.append(OSRExit(id, originStack, exitKind, isWatchpoint)); 90 return &m_osrExits.last(); 91} 92 93JSValue Compilation::toJS(ExecState* exec) const 94{ 95 JSObject* result = constructEmptyObject(exec); 96 97 result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); 98 result->putDirect(exec->vm(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); 99 100 JSArray* profiledBytecodes = constructEmptyArray(exec, 0); 101 for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) 102 profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); 103 result->putDirect(exec->vm(), exec->propertyNames().profiledBytecodes, profiledBytecodes); 104 105 JSArray* descriptions = constructEmptyArray(exec, 0); 106 for (unsigned i = 0; i < m_descriptions.size(); ++i) 107 descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); 108 result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions); 109 110 JSArray* counters = constructEmptyArray(exec, 0); 111 HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end(); 112 for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) { 113 JSObject* counterEntry = constructEmptyObject(exec); 114 counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, iter->key.toJS(exec)); 115 counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(iter->value->count())); 116 counters->push(exec, counterEntry); 117 } 118 result->putDirect(exec->vm(), exec->propertyNames().counters, counters); 119 120 JSArray* exitSites = constructEmptyArray(exec, 0); 121 for (unsigned i = 0; i < m_osrExitSites.size(); ++i) 122 exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); 123 result->putDirect(exec->vm(), exec->propertyNames().osrExitSites, exitSites); 124 125 JSArray* exits = constructEmptyArray(exec, 0); 126 for (unsigned i = 0; i < m_osrExits.size(); ++i) 127 exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); 128 result->putDirect(exec->vm(), exec->propertyNames().osrExits, exits); 129 130 result->putDirect(exec->vm(), exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds)); 131 result->putDirect(exec->vm(), exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds)); 132 result->putDirect(exec->vm(), exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls)); 133 134 return result; 135} 136 137} } // namespace JSC::Profiler 138 139