2012-11-29 06:01:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
2017-03-01 15:43:54 +00:00
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2012-11-29 06:01:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2018-10-15 14:24:49 +00:00
|
|
|
#include <wtf/StringPrintStream.h>
|
2012-11-29 06:01:40 +00:00
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <wtf/FastMalloc.h>
|
|
|
|
|
|
|
|
namespace WTF {
|
|
|
|
|
|
|
|
StringPrintStream::StringPrintStream()
|
|
|
|
: m_buffer(m_inlineBuffer)
|
|
|
|
, m_next(0)
|
|
|
|
, m_size(sizeof(m_inlineBuffer))
|
|
|
|
{
|
|
|
|
m_buffer[0] = 0; // Make sure that we always have a null terminator.
|
|
|
|
}
|
|
|
|
|
|
|
|
StringPrintStream::~StringPrintStream()
|
|
|
|
{
|
|
|
|
if (m_buffer == m_inlineBuffer)
|
|
|
|
return;
|
|
|
|
fastFree(m_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StringPrintStream::vprintf(const char* format, va_list argList)
|
|
|
|
{
|
2013-02-11 08:06:45 +00:00
|
|
|
ASSERT_WITH_SECURITY_IMPLICATION(m_next < m_size);
|
2012-11-29 06:01:40 +00:00
|
|
|
ASSERT(!m_buffer[m_next]);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
va_list firstPassArgList;
|
|
|
|
va_copy(firstPassArgList, argList);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
int numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten =
|
|
|
|
vsnprintf(m_buffer + m_next, m_size - m_next, format, firstPassArgList);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
|
|
|
va_end(firstPassArgList);
|
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
int numberOfBytesThatWouldHaveBeenWritten =
|
|
|
|
numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten + 1;
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
if (m_next + numberOfBytesThatWouldHaveBeenWritten <= m_size) {
|
|
|
|
m_next += numberOfBytesNotIncludingTerminatorThatWouldHaveBeenWritten;
|
|
|
|
return; // This means that vsnprintf() succeeded.
|
|
|
|
}
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
increaseSize(m_next + numberOfBytesThatWouldHaveBeenWritten);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
int numberOfBytesNotIncludingTerminatorThatWereWritten =
|
|
|
|
vsnprintf(m_buffer + m_next, m_size - m_next, format, argList);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
int numberOfBytesThatWereWritten = numberOfBytesNotIncludingTerminatorThatWereWritten + 1;
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
ASSERT_UNUSED(numberOfBytesThatWereWritten, m_next + numberOfBytesThatWereWritten <= m_size);
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
m_next += numberOfBytesNotIncludingTerminatorThatWereWritten;
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2013-02-11 08:06:45 +00:00
|
|
|
ASSERT_WITH_SECURITY_IMPLICATION(m_next < m_size);
|
2012-11-29 06:01:40 +00:00
|
|
|
ASSERT(!m_buffer[m_next]);
|
|
|
|
}
|
|
|
|
|
|
|
|
CString StringPrintStream::toCString()
|
|
|
|
{
|
|
|
|
ASSERT(m_next == strlen(m_buffer));
|
|
|
|
return CString(m_buffer, m_next);
|
|
|
|
}
|
|
|
|
|
JSC should be able to report profiling data associated with the IR dumps and disassembly
https://bugs.webkit.org/show_bug.cgi?id=102999
Reviewed by Gavin Barraclough.
Source/JavaScriptCore:
Added a new profiler to JSC. It's simply called "Profiler" in anticipation of it
ultimately replacing the previous profiling infrastructure. This profiler counts the
number of times that a bytecode executes in various engines, and will record both the
counts and all disassembly and bytecode dumps, into a database that can be at any
time turned into either a JS object using any global object or global data of your
choice, or can be turned into a JSON string, or saved to a file.
Currently the only use of this is the new '-p <file>' flag to the jsc command-line.
The profiler is always compiled in and normally incurs no execution time cost, but is
only activated when you create a Profiler::Database and install it in
JSGlobalData::m_perBytecodeProfiler. From that point on, all code blocks will be
compiled along with disassembly and bytecode dumps stored into the Profiler::Database,
and all code blocks will have execution counts, which are also stored in the database.
The database will continue to keep information about code blocks alive even after they
are otherwise GC'd.
This currently still has some glitches, like the fact that it only counts executions
in the JITs. Doing execution counting in the LLInt might require a bit of a rethink
about how the counting is expressed - currently it is implicit in bytecode, so there
is no easy way to "turn it on" in the LLInt. Also, right now there is no information
recorded about OSR exits or out-of-line stubs. But, even so, it's quite cool, and
gives you a peek into what JSC is doing that would otherwise not be possible.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::baselineVersion):
* bytecode/CodeOrigin.cpp:
(JSC::InlineCallFrame::baselineCodeBlock):
(JSC):
* bytecode/CodeOrigin.h:
(InlineCallFrame):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGDisassembler.cpp:
(JSC::DFG::Disassembler::dump):
(DFG):
(JSC::DFG::Disassembler::reportToProfiler):
(JSC::DFG::Disassembler::dumpHeader):
(JSC::DFG::Disassembler::append):
(JSC::DFG::Disassembler::createDumpList):
* dfg/DFGDisassembler.h:
(Disassembler):
(JSC::DFG::Disassembler::DumpedOp::DumpedOp):
(DumpedOp):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::dumpCodeOrigin):
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::JITCompiler):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGNode.h:
(Node):
(JSC::DFG::Node::hasExecutionCounter):
(JSC::DFG::Node::executionCounter):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* jit/JIT.cpp:
(JSC::JIT::JIT):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JIT):
* jit/JITDisassembler.cpp:
(JSC::JITDisassembler::dump):
(JSC::JITDisassembler::reportToProfiler):
(JSC):
(JSC::JITDisassembler::dumpHeader):
(JSC::JITDisassembler::firstSlowLabel):
(JSC::JITDisassembler::dumpVectorForInstructions):
(JSC::JITDisassembler::dumpForInstructions):
(JSC::JITDisassembler::reportInstructions):
* jit/JITDisassembler.h:
(JITDisassembler):
(DumpedOp):
* jsc.cpp:
(CommandLine::CommandLine):
(CommandLine):
(printUsageStatement):
(CommandLine::parseArguments):
(jscmain):
* profiler/ProfilerBytecode.cpp: Added.
(Profiler):
(JSC::Profiler::Bytecode::toJS):
* profiler/ProfilerBytecode.h: Added.
(Profiler):
(Bytecode):
(JSC::Profiler::Bytecode::Bytecode):
(JSC::Profiler::Bytecode::bytecodeIndex):
(JSC::Profiler::Bytecode::description):
(JSC::Profiler::getBytecodeIndexForBytecode):
* profiler/ProfilerBytecodes.cpp: Added.
(Profiler):
(JSC::Profiler::Bytecodes::Bytecodes):
(JSC::Profiler::Bytecodes::~Bytecodes):
(JSC::Profiler::Bytecodes::indexForBytecodeIndex):
(JSC::Profiler::Bytecodes::forBytecodeIndex):
(JSC::Profiler::Bytecodes::dump):
(JSC::Profiler::Bytecodes::toJS):
* profiler/ProfilerBytecodes.h: Added.
(Profiler):
(Bytecodes):
(JSC::Profiler::Bytecodes::append):
(JSC::Profiler::Bytecodes::id):
(JSC::Profiler::Bytecodes::hash):
(JSC::Profiler::Bytecodes::size):
(JSC::Profiler::Bytecodes::at):
* profiler/ProfilerCompilation.cpp: Added.
(Profiler):
(JSC::Profiler::Compilation::Compilation):
(JSC::Profiler::Compilation::~Compilation):
(JSC::Profiler::Compilation::addDescription):
(JSC::Profiler::Compilation::executionCounterFor):
(JSC::Profiler::Compilation::toJS):
* profiler/ProfilerCompilation.h: Added.
(Profiler):
(Compilation):
(JSC::Profiler::Compilation::bytecodes):
(JSC::Profiler::Compilation::kind):
* profiler/ProfilerCompilationKind.cpp: Added.
(WTF):
(WTF::printInternal):
* profiler/ProfilerCompilationKind.h: Added.
(Profiler):
(WTF):
* profiler/ProfilerCompiledBytecode.cpp: Added.
(Profiler):
(JSC::Profiler::CompiledBytecode::CompiledBytecode):
(JSC::Profiler::CompiledBytecode::~CompiledBytecode):
(JSC::Profiler::CompiledBytecode::toJS):
* profiler/ProfilerCompiledBytecode.h: Added.
(Profiler):
(CompiledBytecode):
(JSC::Profiler::CompiledBytecode::originStack):
(JSC::Profiler::CompiledBytecode::description):
* profiler/ProfilerDatabase.cpp: Added.
(Profiler):
(JSC::Profiler::Database::Database):
(JSC::Profiler::Database::~Database):
(JSC::Profiler::Database::addBytecodes):
(JSC::Profiler::Database::ensureBytecodesFor):
(JSC::Profiler::Database::notifyDestruction):
(JSC::Profiler::Database::newCompilation):
(JSC::Profiler::Database::toJS):
(JSC::Profiler::Database::toJSON):
(JSC::Profiler::Database::save):
* profiler/ProfilerDatabase.h: Added.
(Profiler):
(Database):
* profiler/ProfilerExecutionCounter.h: Added.
(Profiler):
(ExecutionCounter):
(JSC::Profiler::ExecutionCounter::ExecutionCounter):
(JSC::Profiler::ExecutionCounter::address):
(JSC::Profiler::ExecutionCounter::count):
* profiler/ProfilerOrigin.cpp: Added.
(Profiler):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::dump):
(JSC::Profiler::Origin::toJS):
* profiler/ProfilerOrigin.h: Added.
(JSC):
(Profiler):
(Origin):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::operator!):
(JSC::Profiler::Origin::bytecodes):
(JSC::Profiler::Origin::bytecodeIndex):
(JSC::Profiler::Origin::operator!=):
(JSC::Profiler::Origin::operator==):
(JSC::Profiler::Origin::hash):
(JSC::Profiler::Origin::isHashTableDeletedValue):
(JSC::Profiler::OriginHash::hash):
(JSC::Profiler::OriginHash::equal):
(OriginHash):
(WTF):
* profiler/ProfilerOriginStack.cpp: Added.
(Profiler):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::~OriginStack):
(JSC::Profiler::OriginStack::append):
(JSC::Profiler::OriginStack::operator==):
(JSC::Profiler::OriginStack::hash):
(JSC::Profiler::OriginStack::dump):
(JSC::Profiler::OriginStack::toJS):
* profiler/ProfilerOriginStack.h: Added.
(JSC):
(Profiler):
(OriginStack):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::operator!):
(JSC::Profiler::OriginStack::size):
(JSC::Profiler::OriginStack::fromBottom):
(JSC::Profiler::OriginStack::fromTop):
(JSC::Profiler::OriginStack::isHashTableDeletedValue):
(JSC::Profiler::OriginStackHash::hash):
(JSC::Profiler::OriginStackHash::equal):
(OriginStackHash):
(WTF):
* runtime/CommonIdentifiers.h:
* runtime/ExecutionHarness.h:
(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
(JSGlobalData):
* runtime/Options.h:
(JSC):
Source/WTF:
Made some minor changes to support the new profiler. FileOutputStream now has an
open() method, and DataLog uses it. StringPrintStream has a reset() method, which
allows you to reuse the same StringPrintStream for creating multiple strings.
SegmentedVector now has a const operator[]. And, WTFString now can do fromUTF8() on
a CString directly.
* wtf/DataLog.cpp:
(WTF::initializeLogFileOnce):
* wtf/FilePrintStream.cpp:
(WTF::FilePrintStream::open):
(WTF):
* wtf/FilePrintStream.h:
* wtf/SegmentedVector.h:
(WTF::SegmentedVector::at):
(SegmentedVector):
(WTF::SegmentedVector::operator[]):
* wtf/StringPrintStream.cpp:
(WTF::StringPrintStream::reset):
(WTF):
* wtf/StringPrintStream.h:
(StringPrintStream):
* wtf/text/WTFString.cpp:
(WTF::String::fromUTF8):
(WTF):
* wtf/text/WTFString.h:
(String):
Tools:
Added a tool that allows you to grok the output from JSC's new profiler. Currently,
this still gets confused a bit about the execution counts of a method running
standalone versus a method running inlined, but other than that, it's pretty cool.
See the attached "sampling profiling session" attached to the bug to see it in
action.
Also had to feed EFL's build system.
* DumpRenderTree/efl/CMakeLists.txt:
* Scripts/display-profiler-output: Added.
Canonical link: https://commits.webkit.org/122183@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@136601 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2012-12-05 01:26:13 +00:00
|
|
|
void StringPrintStream::reset()
|
|
|
|
{
|
|
|
|
m_next = 0;
|
|
|
|
m_buffer[0] = 0;
|
|
|
|
}
|
|
|
|
|
2020-06-23 18:15:49 +00:00
|
|
|
Expected<String, UTF8ConversionError> StringPrintStream::tryToString()
|
|
|
|
{
|
|
|
|
ASSERT(m_next == strlen(m_buffer));
|
|
|
|
if (m_next > String::MaxLength)
|
|
|
|
return makeUnexpected(UTF8ConversionError::OutOfMemory);
|
|
|
|
return String::fromUTF8(m_buffer, m_next);
|
|
|
|
}
|
|
|
|
|
2012-12-04 19:29:13 +00:00
|
|
|
String StringPrintStream::toString()
|
|
|
|
{
|
|
|
|
ASSERT(m_next == strlen(m_buffer));
|
|
|
|
return String::fromUTF8(m_buffer, m_next);
|
|
|
|
}
|
|
|
|
|
2016-06-02 23:07:48 +00:00
|
|
|
String StringPrintStream::toStringWithLatin1Fallback()
|
|
|
|
{
|
|
|
|
ASSERT(m_next == strlen(m_buffer));
|
|
|
|
return String::fromUTF8WithLatin1Fallback(m_buffer, m_next);
|
|
|
|
}
|
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
void StringPrintStream::increaseSize(size_t newSize)
|
|
|
|
{
|
2013-10-12 18:03:39 +00:00
|
|
|
ASSERT_WITH_SECURITY_IMPLICATION(newSize > m_size);
|
2012-11-29 06:01:40 +00:00
|
|
|
ASSERT(newSize > sizeof(m_inlineBuffer));
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
// Use exponential resizing to reduce thrashing.
|
|
|
|
m_size = newSize << 1;
|
2017-03-01 15:43:54 +00:00
|
|
|
|
2012-11-29 06:01:40 +00:00
|
|
|
// Use fastMalloc instead of fastRealloc because we know that for the sizes we're using,
|
|
|
|
// fastRealloc will just do malloc+free anyway. Also, this simplifies the code since
|
|
|
|
// we can't realloc the inline buffer.
|
|
|
|
char* newBuffer = static_cast<char*>(fastMalloc(m_size));
|
2018-02-16 21:38:53 +00:00
|
|
|
memcpy(newBuffer, m_buffer, m_next + 1);
|
2012-11-29 06:01:40 +00:00
|
|
|
if (m_buffer != m_inlineBuffer)
|
|
|
|
fastFree(m_buffer);
|
|
|
|
m_buffer = newBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace WTF
|
|
|
|
|