diff options
Diffstat (limited to 'Source/JavaScriptCore/tools')
-rw-r--r-- | Source/JavaScriptCore/tools/CodeProfile.cpp | 16 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/CodeProfile.h | 12 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/CodeProfiling.cpp | 14 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/FunctionOverrides.cpp | 250 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/FunctionOverrides.h | 64 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/JSDollarVM.cpp | 36 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/JSDollarVM.h | 60 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp | 428 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/JSDollarVMPrototype.h | 81 | ||||
-rw-r--r-- | Source/JavaScriptCore/tools/ProfileTreeNode.h | 2 |
10 files changed, 940 insertions, 23 deletions
diff --git a/Source/JavaScriptCore/tools/CodeProfile.cpp b/Source/JavaScriptCore/tools/CodeProfile.cpp index de86e52ef..c64f1d5a6 100644 --- a/Source/JavaScriptCore/tools/CodeProfile.cpp +++ b/Source/JavaScriptCore/tools/CodeProfile.cpp @@ -33,7 +33,7 @@ #include <wtf/Vector.h> #include <wtf/text/WTFString.h> -#if PLATFORM(MAC) +#if OS(DARWIN) #include <cxxabi.h> #include <dlfcn.h> #include <execinfo.h> @@ -56,7 +56,7 @@ const char* CodeProfile::s_codeTypeNames[CodeProfile::NumberOfCodeTypes] = { // Helper function, find the symbol name for a pc in JSC. static const char* symbolName(void* address) { -#if PLATFORM(MAC) +#if OS(DARWIN) Dl_info info; if (!dladdr(address, &info) || !info.dli_sname) return "<unknown>"; @@ -74,7 +74,7 @@ static const char* symbolName(void* address) static bool truncateTrace(const char* symbolName) { return !strcmp(symbolName, "JSC::BytecodeGenerator::generate()") - || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char> >::parseInner()") + || !strcmp(symbolName, "JSC::Parser<JSC::Lexer<unsigned char>>::parseInner()") || !strcmp(symbolName, "WTF::fastMalloc(unsigned long)") || !strcmp(symbolName, "WTF::calculateUTCOffset()") || !strcmp(symbolName, "JSC::DFG::ByteCodeParser::parseCodeBlock()"); @@ -105,9 +105,9 @@ void CodeProfile::sample(void* pc, void** framePointer) type = RegExpCode; else { CodeBlock* codeBlock = static_cast<CodeBlock*>(ownerUID); - if (codeBlock->getJITType() == JITCode::DFGJIT) + if (codeBlock->jitType() == JITCode::DFGJIT) type = DFGJIT; - else if (codeBlock->canCompileWithDFGState() != DFG::CanCompile) + else if (!canCompile(codeBlock->capabilityLevelState())) type = BaselineOnly; else if (codeBlock->replacement()) type = BaselineOSR; @@ -123,7 +123,7 @@ void CodeProfile::sample(void* pc, void** framePointer) if (type != EngineFrame) return; -#if PLATFORM(MAC) && CPU(X86_64) +#if OS(DARWIN) && CPU(X86_64) // Walk up the stack. pc = framePointer[1]; framePointer = reinterpret_cast<void**>(*framePointer); @@ -143,7 +143,7 @@ void CodeProfile::sample(void* pc, void** framePointer) void CodeProfile::report() { - dataLogF("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNo); + dataLogF("<CodeProfiling %s:%d>\n", m_file.data(), m_lineNumber); // How many frames of C-code to print - 0, if not verbose, 1 if verbose, up to 1024 if very verbose. unsigned recursionLimit = CodeProfiling::beVeryVerbose() ? 1024 : CodeProfiling::beVerbose(); @@ -186,7 +186,7 @@ void CodeProfile::report() for (size_t i = 0 ; i < m_children.size(); ++i) m_children[i]->report(); - dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNo); + dataLogF("</CodeProfiling %s:%d>\n", m_file.data(), m_lineNumber); } } diff --git a/Source/JavaScriptCore/tools/CodeProfile.h b/Source/JavaScriptCore/tools/CodeProfile.h index db380eedb..37ed22e46 100644 --- a/Source/JavaScriptCore/tools/CodeProfile.h +++ b/Source/JavaScriptCore/tools/CodeProfile.h @@ -37,11 +37,11 @@ class CodeProfile { public: CodeProfile(const SourceCode& source, CodeProfile* parent) : m_file(source.provider()->url().utf8()) - , m_lineNo(source.firstLine()) + , m_lineNumber(source.firstLine()) , m_parent(parent) { if (parent) - parent->addChild(this); + parent->addChild(std::unique_ptr<CodeProfile>(this)); } void sample(void* pc, void** framePointer); @@ -52,9 +52,9 @@ public: return m_parent; } - void addChild(CodeProfile* child) + void addChild(std::unique_ptr<CodeProfile> child) { - m_children.append(adoptPtr(child)); + m_children.append(WTFMove(child)); } private: @@ -80,9 +80,9 @@ private: }; CString m_file; - unsigned m_lineNo; + unsigned m_lineNumber; CodeProfile* m_parent; - Vector< OwnPtr<CodeProfile> > m_children; + Vector<std::unique_ptr<CodeProfile>> m_children; TieredMMapArray<CodeRecord> m_samples; static const char* s_codeTypeNames[NumberOfCodeTypes]; diff --git a/Source/JavaScriptCore/tools/CodeProfiling.cpp b/Source/JavaScriptCore/tools/CodeProfiling.cpp index f545be903..302b5f929 100644 --- a/Source/JavaScriptCore/tools/CodeProfiling.cpp +++ b/Source/JavaScriptCore/tools/CodeProfiling.cpp @@ -33,7 +33,7 @@ #include <signal.h> #endif -#if OS(LINUX) +#if OS(LINUX) || OS(DARWIN) #include <sys/time.h> #endif @@ -48,7 +48,7 @@ WTF::MetaAllocatorTracker* CodeProfiling::s_tracker = 0; #pragma clang diagnostic ignored "-Wmissing-noreturn" #endif -#if (PLATFORM(MAC) && CPU(X86_64)) || (OS(LINUX) && CPU(X86) && !OS(ANDROID)) +#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86)) // Helper function to start & stop the timer. // Presently we're using the wall-clock timer, since this seems to give the best results. static void setProfileTimer(unsigned usec) @@ -66,14 +66,14 @@ static void setProfileTimer(unsigned usec) #pragma clang diagnostic pop #endif -#if PLATFORM(MAC) && CPU(X86_64) +#if OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64) static void profilingTimer(int, siginfo_t*, void* uap) { mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext; CodeProfiling::sample(reinterpret_cast<void*>(context->__ss.__rip), reinterpret_cast<void**>(context->__ss.__rbp)); } -#elif OS(LINUX) && CPU(X86) && !OS(ANDROID) +#elif OS(LINUX) && CPU(X86) static void profilingTimer(int, siginfo_t*, void* uap) { mcontext_t context = static_cast<ucontext_t*>(uap)->uc_mcontext; @@ -92,7 +92,6 @@ void CodeProfiling::sample(void* pc, void** framePointer) void CodeProfiling::notifyAllocator(WTF::MetaAllocator* allocator) { -#if !OS(WINCE) // Check for JSC_CODE_PROFILING. const char* codeProfilingMode = getenv("JSC_CODE_PROFILING"); if (!codeProfilingMode) @@ -119,7 +118,6 @@ void CodeProfiling::notifyAllocator(WTF::MetaAllocator* allocator) ASSERT(!s_tracker); s_tracker = new WTF::MetaAllocatorTracker(); allocator->trackAllocations(s_tracker); -#endif } void* CodeProfiling::getOwnerUIDForPC(void* address) @@ -143,7 +141,7 @@ void CodeProfiling::begin(const SourceCode& source) if (alreadyProfiling) return; -#if (PLATFORM(MAC) && CPU(X86_64)) || (OS(LINUX) && CPU(X86) && !OS(ANDROID)) +#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86)) // Regsiter a signal handler & itimer. struct sigaction action; action.sa_sigaction = reinterpret_cast<void (*)(int, siginfo_t *, void *)>(profilingTimer); @@ -167,7 +165,7 @@ void CodeProfiling::end() if (s_profileStack) return; -#if (PLATFORM(MAC) && CPU(X86_64)) || (OS(LINUX) && CPU(X86) && !OS(ANDROID)) +#if (OS(DARWIN) && !PLATFORM(EFL) && !PLATFORM(GTK) && CPU(X86_64)) || (OS(LINUX) && CPU(X86)) // Stop profiling setProfileTimer(0); #endif diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.cpp b/Source/JavaScriptCore/tools/FunctionOverrides.cpp new file mode 100644 index 000000000..2e328c167 --- /dev/null +++ b/Source/JavaScriptCore/tools/FunctionOverrides.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FunctionOverrides.h" + +#include <stdio.h> +#include <string.h> +#include <wtf/DataLog.h> +#include <wtf/NeverDestroyed.h> +#include <wtf/text/CString.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/text/StringHash.h> + +namespace JSC { + +/* + The overrides file defines function bodies that we will want to override with + a replacement for debugging purposes. The overrides file may contain + 'override' and 'with' clauses like these: + + // Example 1: function foo1(a) + override !@#$%{ print("In foo1"); }!@#$% + with abc{ + print("I am overridden"); + }abc + + // Example 2: function foo2(a) + override %%%{ + print("foo2's body has a string with }%% in it."); + // Because }%% appears in the function body here, we cannot use + // %% or % as the delimiter. %%% is ok though. + }%%% + with %%%{ + print("Overridden foo2"); + }%%% + + 1. Comments are lines starting with //. All comments will be ignored. + + 2. An 'override' clause is used to specify the original function body we + want to override. The with clause is used to specify the overriding + function body. + + An 'override' clause must be followed immediately by a 'with' clause. + + 3. An 'override' clause must be of the form: + override <delimiter>{...function body...}<delimiter> + + The override keyword must be at the start of the line. + + <delimiter> may be any string of any ASCII characters (except for '{', + '}', and whitespace characters) as long as the pattern of "}<delimiter>" + does not appear in the function body e.g. the override clause of Example 2 + above illustrates this. + + The start and end <delimiter> must be identical. + + The space between the override keyword and the start <delimiter> is + required. + + All characters between the pair of delimiters will be considered to + be part of the function body string. This allows us to also work + with script source that are multi-lined i.e. newlines are allowed. + + 4. A 'with' clause is identical in form to an 'override' clause except that + it uses the 'with' keyword instead of the 'override' keyword. + */ + +FunctionOverrides& FunctionOverrides::overrides() +{ + static LazyNeverDestroyed<FunctionOverrides> overrides; + static std::once_flag initializeListFlag; + std::call_once(initializeListFlag, [] { + const char* overridesFileName = Options::functionOverrides(); + overrides.construct(overridesFileName); + }); + return overrides; +} + +FunctionOverrides::FunctionOverrides(const char* overridesFileName) +{ + parseOverridesInFile(overridesFileName); +} + +static void initializeOverrideInfo(const SourceCode& origCode, const String& newBody, FunctionOverrides::OverrideInfo& info) +{ + String origProviderStr = origCode.provider()->source().toString(); + unsigned origBraceStart = origCode.startOffset(); + unsigned origFunctionStart = origProviderStr.reverseFind("function", origBraceStart); + unsigned headerLength = origBraceStart - origFunctionStart; + String origHeader = origProviderStr.substring(origFunctionStart, headerLength); + + String newProviderStr; + newProviderStr.append(origHeader); + newProviderStr.append(newBody); + + RefPtr<SourceProvider> newProvider = StringSourceProvider::create(newProviderStr, "<overridden>"); + + info.firstLine = 1; + info.lineCount = 1; // Faking it. This doesn't really matter for now. + info.startColumn = 1; + info.endColumn = 1; // Faking it. This doesn't really matter for now. + info.parametersStartOffset = newProviderStr.find("("); + info.typeProfilingStartOffset = newProviderStr.find("{"); + info.typeProfilingEndOffset = newProviderStr.length() - 1; + + info.sourceCode = + SourceCode(newProvider.release(), info.typeProfilingStartOffset, info.typeProfilingEndOffset + 1, 1, 1); +} + +bool FunctionOverrides::initializeOverrideFor(const SourceCode& origCode, FunctionOverrides::OverrideInfo& result) +{ + ASSERT(Options::functionOverrides()); + FunctionOverrides& overrides = FunctionOverrides::overrides(); + + auto it = overrides.m_entries.find(origCode.view().toString()); + if (it == overrides.m_entries.end()) + return false; + + initializeOverrideInfo(origCode, it->value, result); + return true; +} + +#define SYNTAX_ERROR "SYNTAX ERROR" +#define IO_ERROR "IO ERROR" +#define FAIL_WITH_ERROR(error, errorMessageInBrackets) \ + do { \ + dataLog("functionOverrides ", error, ": "); \ + dataLog errorMessageInBrackets; \ + exit(EXIT_FAILURE); \ + } while (false) + +static bool hasDisallowedCharacters(const char* str, size_t length) +{ + while (length--) { + char c = *str++; + // '{' is also disallowed, but we don't need to check for it because + // parseClause() searches for '{' as the end of the start delimiter. + // As a result, the parsed delimiter string will never include '{'. + if (c == '}' || isASCIISpace(c)) + return true; + } + return false; +} + +static String parseClause(const char* keyword, size_t keywordLength, FILE* file, const char* line, char* buffer, size_t bufferSize) +{ + const char* keywordPos = strstr(line, keyword); + if (!keywordPos) + FAIL_WITH_ERROR(SYNTAX_ERROR, ("Expecting '", keyword, "' clause:\n", line, "\n")); + if (keywordPos != line) + FAIL_WITH_ERROR(SYNTAX_ERROR, ("Cannot have any characters before '", keyword, "':\n", line, "\n")); + if (line[keywordLength] != ' ') + FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' must be followed by a ' ':\n", line, "\n")); + + const char* delimiterStart = &line[keywordLength + 1]; + const char* delimiterEnd = strstr(delimiterStart, "{"); + if (!delimiterEnd) + FAIL_WITH_ERROR(SYNTAX_ERROR, ("Missing { after '", keyword, "' clause start delimiter:\n", line, "\n")); + + size_t delimiterLength = delimiterEnd - delimiterStart; + String delimiter(delimiterStart, delimiterLength); + + if (hasDisallowedCharacters(delimiterStart, delimiterLength)) + FAIL_WITH_ERROR(SYNTAX_ERROR, ("Delimiter '", delimiter, "' cannot have '{', '}', or whitespace:\n", line, "\n")); + + String terminatorString; + terminatorString.append("}"); + terminatorString.append(delimiter); + + const char* terminator = terminatorString.ascii().data(); + line = delimiterEnd; // Start from the {. + + StringBuilder builder; + do { + const char* p = strstr(line, terminator); + if (p) { + if (p[strlen(terminator)] != '\n') + FAIL_WITH_ERROR(SYNTAX_ERROR, ("Unexpected characters after '", keyword, "' clause end delimiter '", delimiter, "':\n", line, "\n")); + + builder.append(line, p - line + 1); + return builder.toString(); + } + builder.append(line); + + } while ((line = fgets(buffer, bufferSize, file))); + + FAIL_WITH_ERROR(SYNTAX_ERROR, ("'", keyword, "' clause end delimiter '", delimiter, "' not found:\n", builder.toString(), "\n", "Are you missing a '}' before the delimiter?\n")); +} + +void FunctionOverrides::parseOverridesInFile(const char* fileName) +{ + if (!fileName) + return; + + FILE* file = fopen(fileName, "r"); + if (!file) + FAIL_WITH_ERROR(IO_ERROR, ("Failed to open file ", fileName, ". Did you add the file-read-data entitlement to WebProcess.sb?\n")); + + char* line; + char buffer[BUFSIZ]; + while ((line = fgets(buffer, sizeof(buffer), file))) { + if (strstr(line, "//") == line) + continue; + + if (line[0] == '\n' || line[0] == '\0') + continue; + + size_t keywordLength; + + keywordLength = sizeof("override") - 1; + String keyStr = parseClause("override", keywordLength, file, line, buffer, sizeof(buffer)); + + line = fgets(buffer, sizeof(buffer), file); + + keywordLength = sizeof("with") - 1; + String valueStr = parseClause("with", keywordLength, file, line, buffer, sizeof(buffer)); + + m_entries.add(keyStr, valueStr); + } + + int result = fclose(file); + if (result) + dataLogF("Failed to close file %s: %s\n", fileName, strerror(errno)); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/tools/FunctionOverrides.h b/Source/JavaScriptCore/tools/FunctionOverrides.h new file mode 100644 index 000000000..a0d8ad47a --- /dev/null +++ b/Source/JavaScriptCore/tools/FunctionOverrides.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FunctionOverrides_h +#define FunctionOverrides_h + +#include "Options.h" +#include "SourceCode.h" +#include <wtf/HashMap.h> +#include <wtf/text/WTFString.h> + +namespace JSC { + +class ScriptExecutable; + +class FunctionOverrides { +public: + struct OverrideInfo { + SourceCode sourceCode; + unsigned firstLine; + unsigned lineCount; + unsigned startColumn; + unsigned endColumn; + unsigned parametersStartOffset; + unsigned typeProfilingStartOffset; + unsigned typeProfilingEndOffset; + }; + + static FunctionOverrides& overrides(); + FunctionOverrides(const char* functionOverridesFileName); + + static bool initializeOverrideFor(const SourceCode& origCode, OverrideInfo& result); + +private: + void parseOverridesInFile(const char* fileName); + + HashMap<String, String> m_entries; +}; + +} // namespace JSC + +#endif // FunctionOverrides_h diff --git a/Source/JavaScriptCore/tools/JSDollarVM.cpp b/Source/JavaScriptCore/tools/JSDollarVM.cpp new file mode 100644 index 000000000..ee5c3d18e --- /dev/null +++ b/Source/JavaScriptCore/tools/JSDollarVM.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSDollarVM.h" + +#include "JSCJSValueInlines.h" +#include "StructureInlines.h" + +namespace JSC { + +const ClassInfo JSDollarVM::s_info = { "DollarVM", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVM) }; + +} // namespace JSC diff --git a/Source/JavaScriptCore/tools/JSDollarVM.h b/Source/JavaScriptCore/tools/JSDollarVM.h new file mode 100644 index 000000000..6b5be038f --- /dev/null +++ b/Source/JavaScriptCore/tools/JSDollarVM.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSDollarVM_h +#define JSDollarVM_h + +#include "JSObject.h" + +namespace JSC { + +class JSDollarVM : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + DECLARE_EXPORT_INFO; + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + static JSDollarVM* create(VM& vm, Structure* structure) + { + JSDollarVM* instance = new (NotNull, allocateCell<JSDollarVM>(vm.heap)) JSDollarVM(vm, structure); + instance->finishCreation(vm); + return instance; + } + +private: + JSDollarVM(VM& vm, Structure* structure) + : Base(vm, structure) + { + } +}; + +} // namespace JSC + +#endif // JSDollarVM_h diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp new file mode 100644 index 000000000..2d87eaacc --- /dev/null +++ b/Source/JavaScriptCore/tools/JSDollarVMPrototype.cpp @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSDollarVMPrototype.h" + +#include "CodeBlock.h" +#include "Heap.h" +#include "HeapIterationScope.h" +#include "JSCInlines.h" +#include "JSFunction.h" +#include "StackVisitor.h" +#include <wtf/DataLog.h> + +namespace JSC { + +const ClassInfo JSDollarVMPrototype::s_info = { "DollarVMPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDollarVMPrototype) }; + + +bool JSDollarVMPrototype::currentThreadOwnsJSLock(ExecState* exec) +{ + return exec->vm().apiLock().currentThreadIsHoldingLock(); +} + +static bool ensureCurrentThreadOwnsJSLock(ExecState* exec) +{ + if (JSDollarVMPrototype::currentThreadOwnsJSLock(exec)) + return true; + dataLog("ERROR: current thread does not own the JSLock\n"); + return false; +} + +void JSDollarVMPrototype::addFunction(VM& vm, JSGlobalObject* globalObject, const char* name, NativeFunction function, unsigned arguments) +{ + Identifier identifier = Identifier::fromString(&vm, name); + putDirect(vm, identifier, JSFunction::create(vm, globalObject, arguments, identifier.string(), function)); +} + +static EncodedJSValue JSC_HOST_CALL functionCrash(ExecState*) +{ + CRASH(); + return JSValue::encode(jsUndefined()); +} + +static EncodedJSValue JSC_HOST_CALL functionDFGTrue(ExecState*) +{ + return JSValue::encode(jsBoolean(false)); +} + +class CallerFrameJITTypeFunctor { +public: + CallerFrameJITTypeFunctor() + : m_currentFrame(0) + , m_jitType(JITCode::None) + { + } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + if (m_currentFrame++ > 1) { + m_jitType = visitor->codeBlock()->jitType(); + return StackVisitor::Done; + } + return StackVisitor::Continue; + } + + JITCode::JITType jitType() { return m_jitType; } + +private: + unsigned m_currentFrame; + JITCode::JITType m_jitType; +}; + +static EncodedJSValue JSC_HOST_CALL functionLLintTrue(ExecState* exec) +{ + if (!exec) + return JSValue::encode(jsUndefined()); + CallerFrameJITTypeFunctor functor; + exec->iterate(functor); + return JSValue::encode(jsBoolean(functor.jitType() == JITCode::InterpreterThunk)); +} + +static EncodedJSValue JSC_HOST_CALL functionJITTrue(ExecState* exec) +{ + if (!exec) + return JSValue::encode(jsUndefined()); + CallerFrameJITTypeFunctor functor; + exec->iterate(functor); + return JSValue::encode(jsBoolean(functor.jitType() == JITCode::BaselineJIT)); +} + +void JSDollarVMPrototype::gc(ExecState* exec) +{ + if (!ensureCurrentThreadOwnsJSLock(exec)) + return; + exec->heap()->collectAllGarbage(); +} + +static EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec) +{ + JSDollarVMPrototype::gc(exec); + return JSValue::encode(jsUndefined()); +} + +void JSDollarVMPrototype::edenGC(ExecState* exec) +{ + if (!ensureCurrentThreadOwnsJSLock(exec)) + return; + exec->heap()->collectAndSweep(EdenCollection); +} + +static EncodedJSValue JSC_HOST_CALL functionEdenGC(ExecState* exec) +{ + JSDollarVMPrototype::edenGC(exec); + return JSValue::encode(jsUndefined()); +} + +bool JSDollarVMPrototype::isInHeap(Heap* heap, void* ptr) +{ + return isInObjectSpace(heap, ptr) || isInStorageSpace(heap, ptr); +} + +bool JSDollarVMPrototype::isInObjectSpace(Heap* heap, void* ptr) +{ + MarkedBlock* candidate = MarkedBlock::blockFor(ptr); + return heap->objectSpace().blocks().set().contains(candidate); +} + +bool JSDollarVMPrototype::isInStorageSpace(Heap* heap, void* ptr) +{ + CopiedBlock* candidate = CopiedSpace::blockFor(ptr); + return heap->storageSpace().contains(candidate); +} + +struct CellAddressCheckFunctor : MarkedBlock::CountFunctor { + CellAddressCheckFunctor(JSCell* candidate) + : candidate(candidate) + { + } + + IterationStatus operator()(JSCell* cell) + { + if (cell == candidate) { + found = true; + return IterationStatus::Done; + } + return IterationStatus::Continue; + } + + JSCell* candidate; + bool found { false }; +}; + +bool JSDollarVMPrototype::isValidCell(Heap* heap, JSCell* candidate) +{ + HeapIterationScope iterationScope(*heap); + CellAddressCheckFunctor functor(candidate); + heap->objectSpace().forEachLiveCell(iterationScope, functor); + return functor.found; +} + +bool JSDollarVMPrototype::isValidCodeBlock(ExecState* exec, CodeBlock* candidate) +{ + if (!ensureCurrentThreadOwnsJSLock(exec)) + return false; + + struct CodeBlockValidationFunctor { + CodeBlockValidationFunctor(CodeBlock* candidate) + : candidate(candidate) + { + } + + bool operator()(CodeBlock* codeBlock) + { + if (codeBlock == candidate) + found = true; + return found; + } + + CodeBlock* candidate; + bool found { false }; + }; + + VM& vm = exec->vm(); + CodeBlockValidationFunctor functor(candidate); + vm.heap.forEachCodeBlock(functor); + return functor.found; +} + +CodeBlock* JSDollarVMPrototype::codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber) +{ + if (!ensureCurrentThreadOwnsJSLock(topCallFrame)) + return nullptr; + + if (!topCallFrame) + return nullptr; + + struct FetchCodeBlockFunctor { + public: + FetchCodeBlockFunctor(unsigned targetFrameNumber) + : targetFrame(targetFrameNumber) + { + } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + currentFrame++; + if (currentFrame == targetFrame) { + codeBlock = visitor->codeBlock(); + return StackVisitor::Done; + } + return StackVisitor::Continue; + } + + unsigned targetFrame; + unsigned currentFrame { 0 }; + CodeBlock* codeBlock { nullptr }; + }; + + FetchCodeBlockFunctor functor(frameNumber); + topCallFrame->iterate(functor); + return functor.codeBlock; +} + +static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return JSValue::encode(jsUndefined()); + + JSValue value = exec->uncheckedArgument(0); + if (!value.isUInt32()) + return JSValue::encode(jsUndefined()); + + // We need to inc the frame number because the caller would consider + // its own frame as frame 0. Hence, we need discount the frame for this + // function. + unsigned frameNumber = value.asUInt32() + 1; + CodeBlock* codeBlock = JSDollarVMPrototype::codeBlockForFrame(exec, frameNumber); + return JSValue::encode(JSValue(bitwise_cast<double>(reinterpret_cast<uint64_t>(codeBlock)))); +} + +static CodeBlock* codeBlockFromArg(ExecState* exec) +{ + if (exec->argumentCount() < 1) + return nullptr; + + JSValue value = exec->uncheckedArgument(0); + if (!value.isDouble()) { + dataLog("Invalid codeBlock: ", value, "\n"); + return nullptr; + } + + CodeBlock* codeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble())); + if (JSDollarVMPrototype::isValidCodeBlock(exec, codeBlock)) + return codeBlock; + + dataLogF("Invalid codeBlock: %p ", codeBlock); + dataLog(value, "\n"); + return nullptr; + +} + +static EncodedJSValue JSC_HOST_CALL functionPrintSourceFor(ExecState* exec) +{ + CodeBlock* codeBlock = codeBlockFromArg(exec); + if (codeBlock) + codeBlock->dumpSource(); + return JSValue::encode(jsUndefined()); +} + +static EncodedJSValue JSC_HOST_CALL functionPrintByteCodeFor(ExecState* exec) +{ + CodeBlock* codeBlock = codeBlockFromArg(exec); + if (codeBlock) + codeBlock->dumpBytecode(); + return JSValue::encode(jsUndefined()); +} + +static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec) +{ + for (unsigned i = 0; i < exec->argumentCount(); ++i) { + if (i) + dataLog(" "); + String argStr = exec->uncheckedArgument(i).toString(exec)->value(exec); + if (exec->hadException()) + return JSValue::encode(jsUndefined()); + dataLog(argStr); + } + return JSValue::encode(jsUndefined()); +} + +class PrintFrameFunctor { +public: + enum Action { + PrintOne, + PrintAll + }; + + PrintFrameFunctor(Action action, unsigned framesToSkip) + : m_action(action) + , m_framesToSkip(framesToSkip) + { + } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + m_currentFrame++; + if (m_currentFrame > m_framesToSkip) + visitor->print(2); + + if (m_action == PrintOne && m_currentFrame > m_framesToSkip) + return StackVisitor::Done; + return StackVisitor::Continue; + } + +private: + Action m_action; + unsigned m_framesToSkip; + unsigned m_currentFrame { 0 }; +}; + +static void printCallFrame(CallFrame* callFrame, unsigned framesToSkip) +{ + if (!ensureCurrentThreadOwnsJSLock(callFrame)) + return; + PrintFrameFunctor functor(PrintFrameFunctor::PrintOne, framesToSkip); + callFrame->iterate(functor); +} + +void JSDollarVMPrototype::printCallFrame(CallFrame* callFrame) +{ + JSC::printCallFrame(callFrame, 0); +} + +static void printStack(CallFrame* topCallFrame, unsigned framesToSkip) +{ + if (!ensureCurrentThreadOwnsJSLock(topCallFrame)) + return; + if (!topCallFrame) + return; + PrintFrameFunctor functor(PrintFrameFunctor::PrintAll, framesToSkip); + topCallFrame->iterate(functor); +} + +void JSDollarVMPrototype::printStack(CallFrame* topCallFrame) +{ + JSC::printStack(topCallFrame, 0); +} + +static EncodedJSValue JSC_HOST_CALL functionPrintCallFrame(ExecState* exec) +{ + // When the callers call this function, they are expecting to print their + // own frame. So skip 1 for this frame. + printCallFrame(exec, 1); + return JSValue::encode(jsUndefined()); +} + +static EncodedJSValue JSC_HOST_CALL functionPrintStack(ExecState* exec) +{ + // When the callers call this function, they are expecting to print the + // stack starting their own frame. So skip 1 for this frame. + printStack(exec, 1); + return JSValue::encode(jsUndefined()); +} + +void JSDollarVMPrototype::printValue(JSValue value) +{ + dataLog(value); +} + +static EncodedJSValue JSC_HOST_CALL functionPrintValue(ExecState* exec) +{ + for (unsigned i = 0; i < exec->argumentCount(); ++i) { + if (i) + dataLog(" "); + dataLog(exec->uncheckedArgument(i)); + } + return JSValue::encode(jsUndefined()); +} + +void JSDollarVMPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + + addFunction(vm, globalObject, "crash", functionCrash, 0); + + putDirectNativeFunction(vm, globalObject, Identifier::fromString(&vm, "dfgTrue"), 0, functionDFGTrue, DFGTrueIntrinsic, DontEnum); + + addFunction(vm, globalObject, "llintTrue", functionLLintTrue, 0); + addFunction(vm, globalObject, "jitTrue", functionJITTrue, 0); + + addFunction(vm, globalObject, "gc", functionGC, 0); + addFunction(vm, globalObject, "edenGC", functionEdenGC, 0); + + addFunction(vm, globalObject, "codeBlockForFrame", functionCodeBlockForFrame, 1); + addFunction(vm, globalObject, "printSourceFor", functionPrintSourceFor, 1); + addFunction(vm, globalObject, "printByteCodeFor", functionPrintByteCodeFor, 1); + + addFunction(vm, globalObject, "print", functionPrint, 1); + addFunction(vm, globalObject, "printCallFrame", functionPrintCallFrame, 0); + addFunction(vm, globalObject, "printStack", functionPrintStack, 0); + + addFunction(vm, globalObject, "printValue", functionPrintValue, 1); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/tools/JSDollarVMPrototype.h b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h new file mode 100644 index 000000000..4c58be299 --- /dev/null +++ b/Source/JavaScriptCore/tools/JSDollarVMPrototype.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2015 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSDollarVMPrototype_h +#define JSDollarVMPrototype_h + +#include "JSObject.h" + +namespace JSC { + +class Heap; + +class JSDollarVMPrototype : public JSNonFinalObject { +public: + typedef JSNonFinalObject Base; + + DECLARE_INFO; + + static JSDollarVMPrototype* create(VM& vm, JSGlobalObject* globalObject, Structure* structure) + { + JSDollarVMPrototype* prototype = new (NotNull, allocateCell<JSDollarVMPrototype>(vm.heap)) JSDollarVMPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); + } + + // The following are exported because they are designed to be callable from + // lldb. The JS versions are implemented on top of these. + + JS_EXPORT_PRIVATE static bool currentThreadOwnsJSLock(ExecState*); + JS_EXPORT_PRIVATE static void gc(ExecState*); + JS_EXPORT_PRIVATE static void edenGC(ExecState*); + JS_EXPORT_PRIVATE static bool isInHeap(Heap*, void*); + JS_EXPORT_PRIVATE static bool isInObjectSpace(Heap*, void*); + JS_EXPORT_PRIVATE static bool isInStorageSpace(Heap*, void*); + JS_EXPORT_PRIVATE static bool isValidCell(Heap*, JSCell*); + JS_EXPORT_PRIVATE static bool isValidCodeBlock(ExecState*, CodeBlock*); + JS_EXPORT_PRIVATE static CodeBlock* codeBlockForFrame(CallFrame* topCallFrame, unsigned frameNumber); + JS_EXPORT_PRIVATE static void printCallFrame(CallFrame*); + JS_EXPORT_PRIVATE static void printStack(CallFrame* topCallFrame); + JS_EXPORT_PRIVATE static void printValue(JSValue); + +private: + JSDollarVMPrototype(VM& vm, Structure* structure) + : Base(vm, structure) + { + } + + void finishCreation(VM&, JSGlobalObject*); + void addFunction(VM&, JSGlobalObject*, const char* name, NativeFunction, unsigned arguments); +}; + +} // namespace JSC + +#endif // JSDollarVMPrototype_h diff --git a/Source/JavaScriptCore/tools/ProfileTreeNode.h b/Source/JavaScriptCore/tools/ProfileTreeNode.h index 4daa7df4c..88d57f3dd 100644 --- a/Source/JavaScriptCore/tools/ProfileTreeNode.h +++ b/Source/JavaScriptCore/tools/ProfileTreeNode.h @@ -30,7 +30,7 @@ namespace JSC { class ProfileTreeNode { typedef HashMap<String, ProfileTreeNode> Map; - typedef Map::ValueType MapEntry; + typedef Map::KeyValuePairType MapEntry; public: ProfileTreeNode() |