diff options
Diffstat (limited to 'deps/v8/test/cctest')
-rw-r--r-- | deps/v8/test/cctest/SConscript | 5 | ||||
-rw-r--r-- | deps/v8/test/cctest/cctest.gyp | 1 | ||||
-rw-r--r-- | deps/v8/test/cctest/log-eq-of-logging-and-traversal.js | 191 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 10 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-cpu-profiler.cc | 4 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-heap-profiler.cc | 4 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-lockers.cc | 12 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-log-stack-tracer.cc | 4 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-log-utils.cc | 140 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-log.cc | 867 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-profile-generator.cc | 4 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-regexp.cc | 6 |
12 files changed, 378 insertions, 870 deletions
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript index 0197178cf2..0ef5667abd 100644 --- a/deps/v8/test/cctest/SConscript +++ b/deps/v8/test/cctest/SConscript @@ -29,7 +29,7 @@ import sys from os.path import join, dirname, abspath root_dir = dirname(File('SConstruct').rfile().abspath) sys.path.append(join(root_dir, 'tools')) -Import('context object_files') +Import('context object_files tools') SOURCES = { @@ -65,7 +65,6 @@ SOURCES = { 'test-liveedit.cc', 'test-lock.cc', 'test-lockers.cc', - 'test-log-utils.cc', 'test-log.cc', 'test-mark-compact.cc', 'test-parsing.cc', @@ -107,7 +106,7 @@ SOURCES = { def Build(): cctest_files = context.GetRelevantSources(SOURCES) - env = Environment() + env = Environment(tools=tools) env.Replace(**context.flags['cctest']) context.ApplyEnvOverrides(env) # There seems to be a glitch in the way scons decides where to put diff --git a/deps/v8/test/cctest/cctest.gyp b/deps/v8/test/cctest/cctest.gyp index 1d54e8cf55..0a74ce3ca8 100644 --- a/deps/v8/test/cctest/cctest.gyp +++ b/deps/v8/test/cctest/cctest.gyp @@ -71,7 +71,6 @@ 'test-lock.cc', 'test-lockers.cc', 'test-log.cc', - 'test-log-utils.cc', 'test-mark-compact.cc', 'test-parsing.cc', 'test-profile-generator.cc', diff --git a/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js b/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js new file mode 100644 index 0000000000..e661efe023 --- /dev/null +++ b/deps/v8/test/cctest/log-eq-of-logging-and-traversal.js @@ -0,0 +1,191 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "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 THE COPYRIGHT +// OWNER 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. + +// This is a supplementary file for test-log/EquivalenceOfLoggingAndTraversal. + +function parseState(s) { + switch (s) { + case "": return Profile.CodeState.COMPILED; + case "~": return Profile.CodeState.OPTIMIZABLE; + case "*": return Profile.CodeState.OPTIMIZED; + } + throw new Error("unknown code state: " + s); +} + +function LogProcessor() { + LogReader.call(this, { + 'code-creation': { + parsers: [null, parseInt, parseInt, null, 'var-args'], + processor: this.processCodeCreation }, + 'code-move': { parsers: [parseInt, parseInt], + processor: this.processCodeMove }, + 'code-delete': { parsers: [parseInt], + processor: this.processCodeDelete }, + 'sfi-move': { parsers: [parseInt, parseInt], + processor: this.processFunctionMove }, + 'shared-library': null, + 'profiler': null, + 'tick': null }); + this.profile = new Profile(); + +} +LogProcessor.prototype.__proto__ = LogReader.prototype; + +LogProcessor.prototype.processCodeCreation = function( + type, start, size, name, maybe_func) { + if (type != "LazyCompile" && type != "Script" && type != "Function") return; + // Discard types to avoid discrepancies in "LazyCompile" vs. "Function". + type = ""; + if (maybe_func.length) { + var funcAddr = parseInt(maybe_func[0]); + var state = parseState(maybe_func[1]); + this.profile.addFuncCode(type, name, start, size, funcAddr, state); + } else { + this.profile.addCode(type, name, start, size); + } +}; + +LogProcessor.prototype.processCodeMove = function(from, to) { + this.profile.moveCode(from, to); +}; + +LogProcessor.prototype.processCodeDelete = function(start) { + this.profile.deleteCode(start); +}; + +LogProcessor.prototype.processFunctionMove = function(from, to) { + this.profile.moveFunc(from, to); +}; + +function RunTest() { + // _log must be provided externally. + var log_lines = _log.split("\n"); + var line, pos = 0, log_lines_length = log_lines.length; + if (log_lines_length < 2) + return "log_lines_length < 2"; + var logging_processor = new LogProcessor(); + for ( ; pos < log_lines_length; ++pos) { + line = log_lines[pos]; + if (line === "test-logging-done,\"\"") { + ++pos; + break; + } + logging_processor.processLogLine(line); + } + logging_processor.profile.cleanUpFuncEntries(); + var logging_entries = + logging_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses(); + if (logging_entries.length === 0) + return "logging_entries.length === 0"; + var traversal_processor = new LogProcessor(); + for ( ; pos < log_lines_length; ++pos) { + line = log_lines[pos]; + if (line === "test-traversal-done,\"\"") break; + traversal_processor.processLogLine(line); + } + var traversal_entries = + traversal_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses(); + if (traversal_entries.length === 0) + return "traversal_entries.length === 0"; + + function addressComparator(entryA, entryB) { + return entryA[0] < entryB[0] ? -1 : (entryA[0] > entryB[0] ? 1 : 0); + } + + logging_entries.sort(addressComparator); + traversal_entries.sort(addressComparator); + + function entityNamesEqual(entityA, entityB) { + if ("getRawName" in entityB && + entityNamesEqual.builtins.indexOf(entityB.getRawName()) !== -1) { + return true; + } + if (entityNamesEqual.builtins.indexOf(entityB.getName()) !== -1) return true; + return entityA.getName() === entityB.getName(); + } + entityNamesEqual.builtins = + ["Boolean", "Function", "Number", "Object", + "Script", "String", "RegExp", "Date", "Error"]; + + function entitiesEqual(entityA, entityB) { + if (entityA === null && entityB !== null) return true; + if (entityA !== null && entityB === null) return false; + return entityA.size === entityB.size && entityNamesEqual(entityA, entityB); + } + + var i = 0, j = 0, k = logging_entries.length, l = traversal_entries.length; + var comparison = []; + var equal = true; + // Do a merge-like comparison of entries. At the same address we expect to + // find the same entries. We skip builtins during log parsing, but compiled + // functions traversal may erroneously recognize them as functions, so we are + // expecting more functions in traversal vs. logging. + while (i < k && j < l) { + var entryA = logging_entries[i], entryB = traversal_entries[j]; + var cmp = addressComparator(entryA, entryB); + var entityA = entryA[1], entityB = entryB[1]; + var address = entryA[0]; + if (cmp < 0) { + ++i; + entityB = null; + } else if (cmp > 0) { + ++j; + entityA = null; + address = entryB[0]; + } else { + ++i; + ++j; + } + var entities_equal = entitiesEqual(entityA, entityB); + if (!entities_equal) equal = false; + comparison.push([entities_equal, address, entityA, entityB]); + } + if (i < k) equal = false; + while (i < k) { + var entryA = logging_entries[i++]; + comparison.push([false, entryA[0], entryA[1], null]); + } + return [equal, comparison]; +} + +var result = RunTest(); +if (typeof result !== "string") { + var out = []; + if (!result[0]) { + var comparison = result[1]; + for (var i = 0, l = comparison.length; i < l; ++i) { + var c = comparison[i]; + out.push((c[0] ? " " : "* ") + + c[1].toString(16) + " " + + (c[2] ? c[2] : "---") + " " + + (c[3] ? c[3] : "---")); + } + } + result[0] ? true : out.join("\n"); +} else { + result; +} diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 1531f905d1..8d8770f132 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -12633,9 +12633,10 @@ v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) { stackTrace->GetFrame(0)); checkStackFrame(origin, "foo", 6, 3, false, false, stackTrace->GetFrame(1)); - checkStackFrame(NULL, "", 1, 1, false, false, + // This is the source string inside the eval which has the call to foo. + checkStackFrame(NULL, "", 1, 5, false, false, stackTrace->GetFrame(2)); - // The last frame is an anonymous function that has the initial call. + // The last frame is an anonymous function which has the initial eval call. checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3)); @@ -12654,9 +12655,10 @@ v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) { bool is_eval = false; #endif // ENABLE_DEBUGGER_SUPPORT - checkStackFrame(NULL, "", 1, 1, is_eval, false, + // This is the source string inside the eval which has the call to baz. + checkStackFrame(NULL, "", 1, 5, is_eval, false, stackTrace->GetFrame(2)); - // The last frame is an anonymous function that has the initial call to foo. + // The last frame is an anonymous function which has the initial eval call. checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3)); diff --git a/deps/v8/test/cctest/test-cpu-profiler.cc b/deps/v8/test/cctest/test-cpu-profiler.cc index 7d898cedb3..9ff2a171a3 100644 --- a/deps/v8/test/cctest/test-cpu-profiler.cc +++ b/deps/v8/test/cctest/test-cpu-profiler.cc @@ -2,8 +2,6 @@ // // Tests of profiles generator and utilities. -#ifdef ENABLE_LOGGING_AND_PROFILING - #include "v8.h" #include "cpu-profiler-inl.h" #include "cctest.h" @@ -401,5 +399,3 @@ TEST(DeleteCpuProfileDifferentTokens) { CHECK_EQ(0, CpuProfiler::GetProfilesCount()); CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3)); } - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index a2426cc0fe..8675a0146c 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -2,8 +2,6 @@ // // Tests for heap profiler -#ifdef ENABLE_LOGGING_AND_PROFILING - #include "v8.h" #include "cctest.h" @@ -893,5 +891,3 @@ TEST(NodesIteration) { } CHECK_EQ(1, count); } - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-lockers.cc b/deps/v8/test/cctest/test-lockers.cc index 4579361f34..2b184e913d 100644 --- a/deps/v8/test/cctest/test-lockers.cc +++ b/deps/v8/test/cctest/test-lockers.cc @@ -314,7 +314,11 @@ class SeparateIsolatesLocksNonexclusiveThread : public JoinableThread { // Run parallel threads that lock and access different isolates in parallel TEST(SeparateIsolatesLocksNonexclusive) { +#ifdef V8_TARGET_ARCH_ARM + const int kNThreads = 50; +#else const int kNThreads = 100; +#endif v8::Isolate* isolate1 = v8::Isolate::New(); v8::Isolate* isolate2 = v8::Isolate::New(); i::List<JoinableThread*> threads(kNThreads); @@ -383,7 +387,11 @@ class LockerUnlockerThread : public JoinableThread { // Use unlocker inside of a Locker, multiple threads. TEST(LockerUnlocker) { +#ifdef V8_TARGET_ARCH_ARM + const int kNThreads = 50; +#else const int kNThreads = 100; +#endif i::List<JoinableThread*> threads(kNThreads); v8::Isolate* isolate = v8::Isolate::New(); for (int i = 0; i < kNThreads; i++) { @@ -431,7 +439,11 @@ class LockTwiceAndUnlockThread : public JoinableThread { // Use Unlocker inside two Lockers. TEST(LockTwiceAndUnlock) { +#ifdef V8_TARGET_ARCH_ARM + const int kNThreads = 50; +#else const int kNThreads = 100; +#endif i::List<JoinableThread*> threads(kNThreads); v8::Isolate* isolate = v8::Isolate::New(); for (int i = 0; i < kNThreads; i++) { diff --git a/deps/v8/test/cctest/test-log-stack-tracer.cc b/deps/v8/test/cctest/test-log-stack-tracer.cc index b967c7388c..2bcb3fe0b6 100644 --- a/deps/v8/test/cctest/test-log-stack-tracer.cc +++ b/deps/v8/test/cctest/test-log-stack-tracer.cc @@ -27,8 +27,6 @@ // // Tests of profiler-related functions from log.h -#ifdef ENABLE_LOGGING_AND_PROFILING - #include <stdlib.h> #include "v8.h" @@ -413,5 +411,3 @@ TEST(JsEntrySp) { CompileRun("js_entry_sp_level2();"); CHECK_EQ(0, GetJsEntrySp()); } - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-log-utils.cc b/deps/v8/test/cctest/test-log-utils.cc deleted file mode 100644 index 861be12ce8..0000000000 --- a/deps/v8/test/cctest/test-log-utils.cc +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2006-2009 the V8 project authors. All rights reserved. -// -// Tests of logging utilities from log-utils.h - -#ifdef ENABLE_LOGGING_AND_PROFILING - -#include "v8.h" - -#include "log-utils.h" -#include "cctest.h" - -using v8::internal::CStrVector; -using v8::internal::EmbeddedVector; -using v8::internal::LogDynamicBuffer; -using v8::internal::MutableCStrVector; -using v8::internal::ScopedVector; -using v8::internal::Vector; -using v8::internal::StrLength; - -// Fills 'ref_buffer' with test data: a sequence of two-digit -// hex numbers: '0001020304...'. Then writes 'ref_buffer' contents to 'dynabuf'. -static void WriteData(LogDynamicBuffer* dynabuf, Vector<char>* ref_buffer) { - static const char kHex[] = "0123456789ABCDEF"; - CHECK_GT(ref_buffer->length(), 0); - CHECK_GT(513, ref_buffer->length()); - for (int i = 0, half_len = ref_buffer->length() >> 1; i < half_len; ++i) { - (*ref_buffer)[i << 1] = kHex[i >> 4]; - (*ref_buffer)[(i << 1) + 1] = kHex[i & 15]; - } - if (ref_buffer->length() & 1) { - ref_buffer->last() = kHex[ref_buffer->length() >> 5]; - } - CHECK_EQ(ref_buffer->length(), - dynabuf->Write(ref_buffer->start(), ref_buffer->length())); -} - - -static int ReadData( - LogDynamicBuffer* dynabuf, int start_pos, i::Vector<char>* buffer) { - return dynabuf->Read(start_pos, buffer->start(), buffer->length()); -} - - -// Helper function used by CHECK_EQ to compare Vectors. Templatized to -// accept both "char" and "const char" vector contents. -template <typename E, typename V> -static inline void CheckEqualsHelper(const char* file, int line, - const char* expected_source, - const Vector<E>& expected, - const char* value_source, - const Vector<V>& value) { - if (expected.length() != value.length()) { - V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n" - "# Vectors lengths differ: %d expected, %d found\n" - "# Expected: %.*s\n" - "# Found: %.*s", - expected_source, value_source, - expected.length(), value.length(), - expected.length(), expected.start(), - value.length(), value.start()); - } - if (strncmp(expected.start(), value.start(), expected.length()) != 0) { - V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n" - "# Vectors contents differ:\n" - "# Expected: %.*s\n" - "# Found: %.*s", - expected_source, value_source, - expected.length(), expected.start(), - value.length(), value.start()); - } -} - - -TEST(DynaBufSingleBlock) { - LogDynamicBuffer dynabuf(32, 32, "", 0); - EmbeddedVector<char, 32> ref_buf; - WriteData(&dynabuf, &ref_buf); - EmbeddedVector<char, 32> buf; - CHECK_EQ(32, dynabuf.Read(0, buf.start(), buf.length())); - CHECK_EQ(32, ReadData(&dynabuf, 0, &buf)); - CHECK_EQ(ref_buf, buf); - - // Verify that we can't read and write past the end. - CHECK_EQ(0, dynabuf.Read(32, buf.start(), buf.length())); - CHECK_EQ(0, dynabuf.Write(buf.start(), buf.length())); -} - - -TEST(DynaBufCrossBlocks) { - LogDynamicBuffer dynabuf(32, 128, "", 0); - EmbeddedVector<char, 48> ref_buf; - WriteData(&dynabuf, &ref_buf); - CHECK_EQ(48, dynabuf.Write(ref_buf.start(), ref_buf.length())); - // Verify that we can't write data when remaining buffer space isn't enough. - CHECK_EQ(0, dynabuf.Write(ref_buf.start(), ref_buf.length())); - EmbeddedVector<char, 48> buf; - CHECK_EQ(48, ReadData(&dynabuf, 0, &buf)); - CHECK_EQ(ref_buf, buf); - CHECK_EQ(48, ReadData(&dynabuf, 48, &buf)); - CHECK_EQ(ref_buf, buf); - CHECK_EQ(0, ReadData(&dynabuf, 48 * 2, &buf)); -} - - -TEST(DynaBufReadTruncation) { - LogDynamicBuffer dynabuf(32, 128, "", 0); - EmbeddedVector<char, 128> ref_buf; - WriteData(&dynabuf, &ref_buf); - EmbeddedVector<char, 128> buf; - CHECK_EQ(128, ReadData(&dynabuf, 0, &buf)); - CHECK_EQ(ref_buf, buf); - // Try to read near the end with a buffer larger than remaining data size. - EmbeddedVector<char, 48> tail_buf; - CHECK_EQ(32, ReadData(&dynabuf, 128 - 32, &tail_buf)); - CHECK_EQ(ref_buf.SubVector(128 - 32, 128), tail_buf.SubVector(0, 32)); -} - - -TEST(DynaBufSealing) { - const char* seal = "Sealed"; - const int seal_size = StrLength(seal); - LogDynamicBuffer dynabuf(32, 128, seal, seal_size); - EmbeddedVector<char, 100> ref_buf; - WriteData(&dynabuf, &ref_buf); - // Try to write data that will not fit in the buffer. - CHECK_EQ(0, dynabuf.Write(ref_buf.start(), 128 - 100 - seal_size + 1)); - // Now the buffer is sealed, writing of any amount of data is forbidden. - CHECK_EQ(0, dynabuf.Write(ref_buf.start(), 1)); - EmbeddedVector<char, 100> buf; - CHECK_EQ(100, ReadData(&dynabuf, 0, &buf)); - CHECK_EQ(ref_buf, buf); - // Check the seal. - EmbeddedVector<char, 50> seal_buf; - CHECK_EQ(seal_size, ReadData(&dynabuf, 100, &seal_buf)); - CHECK_EQ(CStrVector(seal), seal_buf.SubVector(0, seal_size)); - // Verify that there's no data beyond the seal. - CHECK_EQ(0, ReadData(&dynabuf, 100 + seal_size, &buf)); -} - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-log.cc b/deps/v8/test/cctest/test-log.cc index 10a90bcf17..5704b07ace 100644 --- a/deps/v8/test/cctest/test-log.cc +++ b/deps/v8/test/cctest/test-log.cc @@ -2,8 +2,6 @@ // // Tests of logging functions from log.h -#ifdef ENABLE_LOGGING_AND_PROFILING - #ifdef __linux__ #include <math.h> #include <pthread.h> @@ -15,6 +13,7 @@ #include "log.h" #include "cpu-profiler.h" #include "v8threads.h" +#include "v8utils.h" #include "cctest.h" #include "vm-state-inl.h" @@ -25,269 +24,75 @@ using v8::internal::StrLength; namespace i = v8::internal; -static void SetUp() { - // Log to memory buffer. - i::FLAG_logfile = "*"; - i::FLAG_log = true; - LOGGER->Setup(); -} - -static void TearDown() { - LOGGER->TearDown(); -} - - -TEST(EmptyLog) { - SetUp(); - CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0)); - CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 0)); - CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 100)); - CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 100)); - TearDown(); -} - - -TEST(GetMessages) { - SetUp(); - LOGGER->StringEvent("aaa", "bbb"); - LOGGER->StringEvent("cccc", "dddd"); - CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0)); - char log_lines[100]; - memset(log_lines, 0, sizeof(log_lines)); - // See Logger::StringEvent. - const char* line_1 = "aaa,\"bbb\"\n"; - const int line_1_len = StrLength(line_1); - // The exact size. - CHECK_EQ(line_1_len, LOGGER->GetLogLines(0, log_lines, line_1_len)); - CHECK_EQ(line_1, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - // A bit more than the first line length. - CHECK_EQ(line_1_len, LOGGER->GetLogLines(0, log_lines, line_1_len + 3)); - log_lines[line_1_len] = '\0'; - CHECK_EQ(line_1, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - const char* line_2 = "cccc,\"dddd\"\n"; - const int line_2_len = StrLength(line_2); - // Now start with line_2 beginning. - CHECK_EQ(0, LOGGER->GetLogLines(line_1_len, log_lines, 0)); - CHECK_EQ(line_2_len, LOGGER->GetLogLines(line_1_len, log_lines, line_2_len)); - CHECK_EQ(line_2, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - CHECK_EQ(line_2_len, - LOGGER->GetLogLines(line_1_len, log_lines, line_2_len + 3)); - CHECK_EQ(line_2, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - // Now get entire buffer contents. - const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n"; - const int all_lines_len = StrLength(all_lines); - CHECK_EQ(all_lines_len, LOGGER->GetLogLines(0, log_lines, all_lines_len)); - CHECK_EQ(all_lines, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - CHECK_EQ(all_lines_len, LOGGER->GetLogLines(0, log_lines, all_lines_len + 3)); - CHECK_EQ(all_lines, log_lines); - memset(log_lines, 0, sizeof(log_lines)); - TearDown(); -} - - -static int GetLogLines(int start_pos, i::Vector<char>* buffer) { - return LOGGER->GetLogLines(start_pos, buffer->start(), buffer->length()); -} - - -TEST(BeyondWritePosition) { - SetUp(); - LOGGER->StringEvent("aaa", "bbb"); - LOGGER->StringEvent("cccc", "dddd"); - // See Logger::StringEvent. - const char* all_lines = "aaa,\"bbb\"\ncccc,\"dddd\"\n"; - const int all_lines_len = StrLength(all_lines); - EmbeddedVector<char, 100> buffer; - const int beyond_write_pos = all_lines_len; - CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos, buffer.start(), 1)); - CHECK_EQ(0, GetLogLines(beyond_write_pos, &buffer)); - CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos + 1, buffer.start(), 1)); - CHECK_EQ(0, GetLogLines(beyond_write_pos + 1, &buffer)); - CHECK_EQ(0, LOGGER->GetLogLines(beyond_write_pos + 100, buffer.start(), 1)); - CHECK_EQ(0, GetLogLines(beyond_write_pos + 100, &buffer)); - CHECK_EQ(0, LOGGER->GetLogLines(10 * 1024 * 1024, buffer.start(), 1)); - CHECK_EQ(0, GetLogLines(10 * 1024 * 1024, &buffer)); - TearDown(); -} - - -TEST(MemoryLoggingTurnedOff) { - // Log to stdout - i::FLAG_logfile = "-"; - i::FLAG_log = true; - LOGGER->Setup(); - CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 0)); - CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 0)); - CHECK_EQ(0, LOGGER->GetLogLines(0, NULL, 100)); - CHECK_EQ(0, LOGGER->GetLogLines(100, NULL, 100)); - LOGGER->TearDown(); -} - - -static void CompileAndRunScript(const char *src) { - v8::Script::Compile(v8::String::New(src))->Run(); -} - - -namespace v8 { -namespace internal { - -class LoggerTestHelper : public AllStatic { - public: - static bool IsSamplerActive() { return LOGGER->IsProfilerSamplerActive(); } - static void ResetSamplesTaken() { - reinterpret_cast<Sampler*>(LOGGER->ticker_)->ResetSamplesTaken(); - } - static bool has_samples_taken() { - return reinterpret_cast<Sampler*>(LOGGER->ticker_)->samples_taken() > 0; - } -}; - -} // namespace v8::internal -} // namespace v8 - -using v8::internal::LoggerTestHelper; - - namespace { class ScopedLoggerInitializer { public: explicit ScopedLoggerInitializer(bool prof_lazy) - : saved_prof_lazy_(i::FLAG_prof_lazy), + : saved_log_(i::FLAG_log), + saved_prof_lazy_(i::FLAG_prof_lazy), saved_prof_(i::FLAG_prof), saved_prof_auto_(i::FLAG_prof_auto), + temp_file_(NULL), + // Need to run this prior to creating the scope. trick_to_run_init_flags_(init_flags_(prof_lazy)), - need_to_set_up_logger_(i::V8::IsRunning()), scope_(), env_(v8::Context::New()) { - if (need_to_set_up_logger_) LOGGER->Setup(); env_->Enter(); } ~ScopedLoggerInitializer() { env_->Exit(); LOGGER->TearDown(); + if (temp_file_ != NULL) fclose(temp_file_); i::FLAG_prof_lazy = saved_prof_lazy_; i::FLAG_prof = saved_prof_; i::FLAG_prof_auto = saved_prof_auto_; + i::FLAG_log = saved_log_; } v8::Handle<v8::Context>& env() { return env_; } + FILE* StopLoggingGetTempFile() { + temp_file_ = LOGGER->TearDown(); + CHECK_NE(NULL, temp_file_); + fflush(temp_file_); + rewind(temp_file_); + return temp_file_; + } + private: static bool init_flags_(bool prof_lazy) { + i::FLAG_log = true; i::FLAG_prof = true; i::FLAG_prof_lazy = prof_lazy; i::FLAG_prof_auto = false; - i::FLAG_logfile = "*"; + i::FLAG_logfile = i::Log::kLogToTemporaryFile; return prof_lazy; } + const bool saved_log_; const bool saved_prof_lazy_; const bool saved_prof_; const bool saved_prof_auto_; + FILE* temp_file_; const bool trick_to_run_init_flags_; - const bool need_to_set_up_logger_; v8::HandleScope scope_; v8::Handle<v8::Context> env_; DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer); }; - -class LogBufferMatcher { - public: - LogBufferMatcher() { - // Skip all initially logged stuff. - log_pos_ = GetLogLines(0, &buffer_); - } - - int log_pos() { return log_pos_; } - - int GetNextChunk() { - int chunk_size = GetLogLines(log_pos_, &buffer_); - CHECK_GT(buffer_.length(), chunk_size); - buffer_[chunk_size] = '\0'; - log_pos_ += chunk_size; - return chunk_size; - } - - const char* Find(const char* substr) { - return strstr(buffer_.start(), substr); - } - - const char* Find(const i::Vector<char>& substr) { - return Find(substr.start()); - } - - bool IsInSequence(const char* s1, const char* s2) { - const char* s1_pos = Find(s1); - const char* s2_pos = Find(s2); - CHECK_NE(NULL, s1_pos); - CHECK_NE(NULL, s2_pos); - return s1_pos < s2_pos; - } - - void PrintBuffer() { - puts(buffer_.start()); - } - - private: - EmbeddedVector<char, 102400> buffer_; - int log_pos_; -}; - } // namespace -static void CheckThatProfilerWorks(LogBufferMatcher* matcher) { - CHECK(i::RuntimeProfiler::IsEnabled() || - !LoggerTestHelper::IsSamplerActive()); - LoggerTestHelper::ResetSamplesTaken(); - - LOGGER->ResumeProfiler(); - CHECK(LoggerTestHelper::IsSamplerActive()); - - // Verify that the current map of compiled functions has been logged. - CHECK_GT(matcher->GetNextChunk(), 0); - const char* code_creation = "\ncode-creation,"; // eq. to /^code-creation,/ - CHECK_NE(NULL, matcher->Find(code_creation)); - - // Force compiler to generate new code by parametrizing source. - EmbeddedVector<char, 100> script_src; - i::OS::SNPrintF(script_src, - "function f%d(x) { return %d * x; }" - "for (var i = 0; i < 10000; ++i) { f%d(i); }", - matcher->log_pos(), matcher->log_pos(), matcher->log_pos()); - // Run code for 200 msecs to get some ticks. - const double end_time = i::OS::TimeCurrentMillis() + 200; - while (i::OS::TimeCurrentMillis() < end_time) { - CompileAndRunScript(script_src.start()); - // Yield CPU to give Profiler thread a chance to process ticks. - i::OS::Sleep(1); - } - - LOGGER->PauseProfiler(); - CHECK(i::RuntimeProfiler::IsEnabled() || - !LoggerTestHelper::IsSamplerActive()); - - // Wait 50 msecs to allow Profiler thread to process the last - // tick sample it has got. - i::OS::Sleep(50); - - // Now we must have compiler and tick records. - CHECK_GT(matcher->GetNextChunk(), 0); - matcher->PrintBuffer(); - CHECK_NE(NULL, matcher->Find(code_creation)); - const char* tick = "\ntick,"; - const bool ticks_found = matcher->Find(tick) != NULL; - CHECK_EQ(LoggerTestHelper::has_samples_taken(), ticks_found); +static const char* StrNStr(const char* s1, const char* s2, int n) { + if (s1[n] == '\0') return strstr(s1, s2); + i::ScopedVector<char> str(n + 1); + i::OS::StrNCpy(str, s1, static_cast<size_t>(n)); + str[n] = '\0'; + char* found = strstr(str.start(), s2); + return found != NULL ? s1 + (found - str.start()) : NULL; } @@ -296,29 +101,61 @@ TEST(ProfLazyMode) { if (!i::V8::UseCrankshaft()) return; - // No sampling should happen prior to resuming profiler unless we - // are runtime profiling. - CHECK(i::RuntimeProfiler::IsEnabled() || - !LoggerTestHelper::IsSamplerActive()); + LOGGER->StringEvent("test-start", ""); + CompileRun("var a = (function(x) { return x + 1; })(10);"); + LOGGER->StringEvent("test-profiler-start", ""); + v8::V8::ResumeProfiler(); + CompileRun( + "var b = (function(x) { return x + 2; })(10);\n" + "var c = (function(x) { return x + 3; })(10);\n" + "var d = (function(x) { return x + 4; })(10);\n" + "var e = (function(x) { return x + 5; })(10);"); + v8::V8::PauseProfiler(); + LOGGER->StringEvent("test-profiler-stop", ""); + CompileRun("var f = (function(x) { return x + 6; })(10);"); + // Check that profiling can be resumed again. + LOGGER->StringEvent("test-profiler-start-2", ""); + v8::V8::ResumeProfiler(); + CompileRun( + "var g = (function(x) { return x + 7; })(10);\n" + "var h = (function(x) { return x + 8; })(10);\n" + "var i = (function(x) { return x + 9; })(10);\n" + "var j = (function(x) { return x + 10; })(10);"); + v8::V8::PauseProfiler(); + LOGGER->StringEvent("test-profiler-stop-2", ""); + LOGGER->StringEvent("test-stop", ""); + + bool exists = false; + i::Vector<const char> log( + i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); + CHECK(exists); + + const char* test_start_position = + StrNStr(log.start(), "test-start,", log.length()); + CHECK_NE(NULL, test_start_position); + const char* test_profiler_start_position = + StrNStr(log.start(), "test-profiler-start,", log.length()); + CHECK_NE(NULL, test_profiler_start_position); + CHECK_GT(test_profiler_start_position, test_start_position); + const char* test_profiler_stop_position = + StrNStr(log.start(), "test-profiler-stop,", log.length()); + CHECK_NE(NULL, test_profiler_stop_position); + CHECK_GT(test_profiler_stop_position, test_profiler_start_position); + const char* test_profiler_start_2_position = + StrNStr(log.start(), "test-profiler-start-2,", log.length()); + CHECK_NE(NULL, test_profiler_start_2_position); + CHECK_GT(test_profiler_start_2_position, test_profiler_stop_position); - LogBufferMatcher matcher; // Nothing must be logged until profiling is resumed. - CHECK_EQ(0, matcher.log_pos()); - - CompileAndRunScript("var a = (function(x) { return x + 1; })(10);"); - + CHECK_EQ(NULL, StrNStr(test_start_position, + "code-creation,", + static_cast<int>(test_profiler_start_position - + test_start_position))); // Nothing must be logged while profiling is suspended. - CHECK_EQ(0, matcher.GetNextChunk()); - - CheckThatProfilerWorks(&matcher); - - CompileAndRunScript("var a = (function(x) { return x + 1; })(10);"); - - // No new data beyond last retrieved position. - CHECK_EQ(0, matcher.GetNextChunk()); - - // Check that profiling can be resumed again. - CheckThatProfilerWorks(&matcher); + CHECK_EQ(NULL, StrNStr(test_profiler_stop_position, + "code-creation,", + static_cast<int>(test_profiler_start_2_position - + test_profiler_stop_position))); } @@ -383,7 +220,7 @@ class LoopingJsThread : public LoopingThread { { v8::Context::Scope context_scope(context); SignalRunning(); - CompileAndRunScript( + CompileRun( "var j; for (var i=0; i<10000; ++i) { j = Math.sin(i); }"); } context.Dispose(); @@ -531,34 +368,34 @@ static v8::Handle<v8::Value> ObjMethod1(const v8::Arguments& args) { TEST(LogCallbacks) { ScopedLoggerInitializer initialize_logger(false); - LogBufferMatcher matcher; v8::Persistent<v8::FunctionTemplate> obj = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()); - obj->SetClassName(v8::String::New("Obj")); + obj->SetClassName(v8_str("Obj")); v8::Handle<v8::ObjectTemplate> proto = obj->PrototypeTemplate(); v8::Local<v8::Signature> signature = v8::Signature::New(obj); - proto->Set(v8::String::New("method1"), + proto->Set(v8_str("method1"), v8::FunctionTemplate::New(ObjMethod1, v8::Handle<v8::Value>(), signature), static_cast<v8::PropertyAttribute>(v8::DontDelete)); initialize_logger.env()->Global()->Set(v8_str("Obj"), obj->GetFunction()); - CompileAndRunScript("Obj.prototype.method1.toString();"); + CompileRun("Obj.prototype.method1.toString();"); LOGGER->LogCompiledFunctions(); - CHECK_GT(matcher.GetNextChunk(), 0); - const char* callback_rec = "code-creation,Callback,"; - char* pos = const_cast<char*>(matcher.Find(callback_rec)); - CHECK_NE(NULL, pos); - pos += strlen(callback_rec); - EmbeddedVector<char, 100> ref_data; + bool exists = false; + i::Vector<const char> log( + i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); + CHECK(exists); + + i::EmbeddedVector<char, 100> ref_data; i::OS::SNPrintF(ref_data, - "0x%" V8PRIxPTR ",1,\"method1\"", ObjMethod1); - *(pos + strlen(ref_data.start())) = '\0'; - CHECK_EQ(ref_data.start(), pos); + "code-creation,Callback,0x%" V8PRIxPTR ",1,\"method1\"\0", + ObjMethod1); + + CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length())); obj.Dispose(); } @@ -581,34 +418,41 @@ static v8::Handle<v8::Value> Prop2Getter(v8::Local<v8::String> property, TEST(LogAccessorCallbacks) { ScopedLoggerInitializer initialize_logger(false); - LogBufferMatcher matcher; v8::Persistent<v8::FunctionTemplate> obj = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()); - obj->SetClassName(v8::String::New("Obj")); + obj->SetClassName(v8_str("Obj")); v8::Handle<v8::ObjectTemplate> inst = obj->InstanceTemplate(); - inst->SetAccessor(v8::String::New("prop1"), Prop1Getter, Prop1Setter); - inst->SetAccessor(v8::String::New("prop2"), Prop2Getter); + inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter); + inst->SetAccessor(v8_str("prop2"), Prop2Getter); LOGGER->LogAccessorCallbacks(); - CHECK_GT(matcher.GetNextChunk(), 0); - matcher.PrintBuffer(); + + bool exists = false; + i::Vector<const char> log( + i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); + CHECK(exists); EmbeddedVector<char, 100> prop1_getter_record; i::OS::SNPrintF(prop1_getter_record, "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"", Prop1Getter); - CHECK_NE(NULL, matcher.Find(prop1_getter_record)); + CHECK_NE(NULL, + StrNStr(log.start(), prop1_getter_record.start(), log.length())); + EmbeddedVector<char, 100> prop1_setter_record; i::OS::SNPrintF(prop1_setter_record, "code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"", Prop1Setter); - CHECK_NE(NULL, matcher.Find(prop1_setter_record)); + CHECK_NE(NULL, + StrNStr(log.start(), prop1_setter_record.start(), log.length())); + EmbeddedVector<char, 100> prop2_getter_record; i::OS::SNPrintF(prop2_getter_record, "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"", Prop2Getter); - CHECK_NE(NULL, matcher.Find(prop2_getter_record)); + CHECK_NE(NULL, + StrNStr(log.start(), prop2_getter_record.start(), log.length())); obj.Dispose(); } @@ -625,377 +469,6 @@ TEST(IsLoggingPreserved) { } -static inline bool IsStringEqualTo(const char* r, const char* s) { - return strncmp(r, s, strlen(r)) == 0; -} - - -static bool Consume(const char* str, char** buf) { - if (IsStringEqualTo(str, *buf)) { - *buf += strlen(str); - return true; - } - return false; -} - - -namespace { - -// A code entity is a pointer to a position of code-creation event in buffer log -// offset to a point where entity size begins, i.e.: '255,"func"\n'. This makes -// comparing code entities pretty easy. -typedef char* CodeEntityInfo; - -class Interval { - public: - Interval() - : min_addr_(reinterpret_cast<Address>(-1)), - max_addr_(reinterpret_cast<Address>(0)), next_(NULL) {} - - ~Interval() { delete next_; } - - size_t Length() { - size_t result = max_addr_ - min_addr_ + 1; - if (next_ != NULL) result += next_->Length(); - return result; - } - - void CloneFrom(Interval* src) { - while (src != NULL) { - RegisterAddress(src->min_addr_); - RegisterAddress(src->max_addr_); - src = src->next_; - } - } - - bool Contains(Address addr) { - if (min_addr_ <= addr && addr <= max_addr_) { - return true; - } - if (next_ != NULL) { - return next_->Contains(addr); - } else { - return false; - } - } - - size_t GetIndex(Address addr) { - if (min_addr_ <= addr && addr <= max_addr_) { - return addr - min_addr_; - } - CHECK_NE(NULL, next_); - return (max_addr_ - min_addr_ + 1) + next_->GetIndex(addr); - } - - Address GetMinAddr() { - return next_ == NULL ? min_addr_ : i::Min(min_addr_, next_->GetMinAddr()); - } - - Address GetMaxAddr() { - return next_ == NULL ? max_addr_ : i::Max(max_addr_, next_->GetMaxAddr()); - } - - void RegisterAddress(Address addr) { - if (min_addr_ == reinterpret_cast<Address>(-1) - || (size_t)(addr > min_addr_ ? - addr - min_addr_ : min_addr_ - addr) < MAX_DELTA) { - if (addr < min_addr_) min_addr_ = addr; - if (addr > max_addr_) max_addr_ = addr; - } else { - if (next_ == NULL) next_ = new Interval(); - next_->RegisterAddress(addr); - } - } - - Address raw_min_addr() { return min_addr_; } - - Address raw_max_addr() { return max_addr_; } - - Interval* get_next() { return next_; } - - private: - static const size_t MAX_DELTA = 0x100000; - Address min_addr_; - Address max_addr_; - Interval* next_; -}; - - -// A structure used to return log parsing results. -class ParseLogResult { - public: - ParseLogResult() - : entities_map(NULL), entities(NULL), - max_entities(0) {} - - ~ParseLogResult() { - i::DeleteArray(entities_map); - i::DeleteArray(entities); - } - - void AllocateEntities() { - // Make sure that the test doesn't operate on a bogus log. - CHECK_GT(max_entities, 0); - CHECK_GT(bounds.GetMinAddr(), 0); - CHECK_GT(bounds.GetMaxAddr(), bounds.GetMinAddr()); - - entities = i::NewArray<CodeEntityInfo>(max_entities); - for (int i = 0; i < max_entities; ++i) { - entities[i] = NULL; - } - const size_t map_length = bounds.Length(); - entities_map = i::NewArray<int>(static_cast<int>(map_length)); - for (size_t i = 0; i < map_length; ++i) { - entities_map[i] = -1; - } - } - - bool HasIndexForAddress(Address addr) { - return bounds.Contains(addr); - } - - size_t GetIndexForAddress(Address addr) { - CHECK(HasIndexForAddress(addr)); - return bounds.GetIndex(addr); - } - - CodeEntityInfo GetEntity(Address addr) { - if (HasIndexForAddress(addr)) { - size_t idx = GetIndexForAddress(addr); - int item = entities_map[idx]; - return item != -1 ? entities[item] : NULL; - } - return NULL; - } - - void ParseAddress(char* start) { - Address addr = - reinterpret_cast<Address>(strtoul(start, NULL, 16)); // NOLINT - bounds.RegisterAddress(addr); - } - - Address ConsumeAddress(char** start) { - char* end_ptr; - Address addr = - reinterpret_cast<Address>(strtoul(*start, &end_ptr, 16)); // NOLINT - CHECK(HasIndexForAddress(addr)); - *start = end_ptr; - return addr; - } - - Interval bounds; - // Memory map of entities start addresses. - int* entities_map; - // An array of code entities. - CodeEntityInfo* entities; - // Maximal entities count. Actual entities count can be lower, - // empty entity slots are pointing to NULL. - int max_entities; -}; - -} // namespace - - -typedef void (*ParserBlock)(char* start, char* end, ParseLogResult* result); - -static void ParserCycle( - char* start, char* end, ParseLogResult* result, - ParserBlock block_creation, ParserBlock block_delete, - ParserBlock block_move) { - - const char* code_creation = "code-creation,"; - const char* code_delete = "code-delete,"; - const char* code_move = "code-move,"; - - const char* lazy_compile = "LazyCompile,"; - const char* script = "Script,"; - const char* function = "Function,"; - - while (start < end) { - if (Consume(code_creation, &start)) { - if (Consume(lazy_compile, &start) - || Consume(script, &start) - || Consume(function, &start)) { - block_creation(start, end, result); - } - } else if (Consume(code_delete, &start)) { - block_delete(start, end, result); - } else if (Consume(code_move, &start)) { - block_move(start, end, result); - } - while (start < end && *start != '\n') ++start; - ++start; - } -} - - -static void Pass1CodeCreation(char* start, char* end, ParseLogResult* result) { - result->ParseAddress(start); - ++result->max_entities; -} - - -static void Pass1CodeDelete(char* start, char* end, ParseLogResult* result) { - result->ParseAddress(start); -} - - -static void Pass1CodeMove(char* start, char* end, ParseLogResult* result) { - result->ParseAddress(start); - // Skip old address. - while (start < end && *start != ',') ++start; - CHECK_GT(end, start); - ++start; // Skip ','. - result->ParseAddress(start); -} - - -static void Pass2CodeCreation(char* start, char* end, ParseLogResult* result) { - Address addr = result->ConsumeAddress(&start); - CHECK_GT(end, start); - ++start; // Skip ','. - - size_t idx = result->GetIndexForAddress(addr); - result->entities_map[idx] = -1; - for (int i = 0; i < result->max_entities; ++i) { - // Find an empty slot and fill it. - if (result->entities[i] == NULL) { - result->entities[i] = start; - result->entities_map[idx] = i; - break; - } - } - // Make sure that a slot was found. - CHECK_GE(result->entities_map[idx], 0); -} - - -static void Pass2CodeDelete(char* start, char* end, ParseLogResult* result) { - Address addr = result->ConsumeAddress(&start); - size_t idx = result->GetIndexForAddress(addr); - // There can be code deletes that are not related to JS code. - if (result->entities_map[idx] >= 0) { - result->entities[result->entities_map[idx]] = NULL; - result->entities_map[idx] = -1; - } -} - - -static void Pass2CodeMove(char* start, char* end, ParseLogResult* result) { - Address from_addr = result->ConsumeAddress(&start); - CHECK_GT(end, start); - ++start; // Skip ','. - Address to_addr = result->ConsumeAddress(&start); - CHECK_GT(end, start); - - size_t from_idx = result->GetIndexForAddress(from_addr); - size_t to_idx = result->GetIndexForAddress(to_addr); - // There can be code moves that are not related to JS code. - if (from_idx != to_idx && result->entities_map[from_idx] >= 0) { - CHECK_EQ(-1, result->entities_map[to_idx]); - result->entities_map[to_idx] = result->entities_map[from_idx]; - result->entities_map[from_idx] = -1; - }; -} - - -static void ParseLog(char* start, char* end, ParseLogResult* result) { - // Pass 1: Calculate boundaries of addresses and entities count. - ParserCycle(start, end, result, - Pass1CodeCreation, Pass1CodeDelete, Pass1CodeMove); - - printf("min_addr: %p, max_addr: %p, entities: %d\n", - result->bounds.GetMinAddr(), result->bounds.GetMaxAddr(), - result->max_entities); - - result->AllocateEntities(); - - // Pass 2: Fill in code entries data. - ParserCycle(start, end, result, - Pass2CodeCreation, Pass2CodeDelete, Pass2CodeMove); -} - - -static inline void PrintCodeEntityInfo(CodeEntityInfo entity) { - const int max_len = 50; - if (entity != NULL) { - char* eol = strchr(entity, '\n'); - int len = static_cast<int>(eol - entity); - len = len <= max_len ? len : max_len; - printf("%-*.*s ", max_len, len, entity); - } else { - printf("%*s", max_len + 1, ""); - } -} - - -static void PrintCodeEntitiesInfo( - bool is_equal, Address addr, - CodeEntityInfo l_entity, CodeEntityInfo r_entity) { - printf("%c %p ", is_equal ? ' ' : '*', addr); - PrintCodeEntityInfo(l_entity); - PrintCodeEntityInfo(r_entity); - printf("\n"); -} - - -static inline int StrChrLen(const char* s, char c) { - return static_cast<int>(strchr(s, c) - s); -} - - -static bool AreFuncSizesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) { - int ref_len = StrChrLen(ref_s, ','); - int new_len = StrChrLen(new_s, ','); - return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; -} - - -static bool AreFuncNamesEqual(CodeEntityInfo ref_s, CodeEntityInfo new_s) { - // Skip size. - ref_s = strchr(ref_s, ',') + 1; - new_s = strchr(new_s, ',') + 1; - CHECK_EQ('"', ref_s[0]); - CHECK_EQ('"', new_s[0]); - int ref_len = StrChrLen(ref_s + 1, '\"'); - int new_len = StrChrLen(new_s + 1, '\"'); - // A special case for ErrorPrototype. Haven't yet figured out why they - // are different. - const char* error_prototype = "\"ErrorPrototype"; - if (IsStringEqualTo(error_prototype, ref_s) - && IsStringEqualTo(error_prototype, new_s)) { - return true; - } - // Built-in objects have problems too. - const char* built_ins[] = { - "\"Boolean\"", "\"Function\"", "\"Number\"", - "\"Object\"", "\"Script\"", "\"String\"" - }; - for (size_t i = 0; i < sizeof(built_ins) / sizeof(*built_ins); ++i) { - if (IsStringEqualTo(built_ins[i], new_s)) { - return true; - } - } - return ref_len == new_len && strncmp(ref_s, new_s, ref_len) == 0; -} - - -static bool AreEntitiesEqual(CodeEntityInfo ref_e, CodeEntityInfo new_e) { - if (ref_e == NULL && new_e != NULL) return true; - if (ref_e != NULL && new_e != NULL) { - return AreFuncSizesEqual(ref_e, new_e) && AreFuncNamesEqual(ref_e, new_e); - } - if (ref_e != NULL && new_e == NULL) { - // args_count entities (argument adapters) are not found by heap traversal, - // but they are not needed because they doesn't contain any code. - ref_e = strchr(ref_e, ',') + 1; - const char* args_count = "\"args_count:"; - return IsStringEqualTo(args_count, ref_e); - } - return false; -} - - // Test that logging of code create / move / delete events // is equivalent to traversal of a resulting heap. TEST(EquivalenceOfLoggingAndTraversal) { @@ -1008,86 +481,68 @@ TEST(EquivalenceOfLoggingAndTraversal) { // P.S. No, V8 can't be re-initialized after disposal, see include/v8.h. CHECK(!i::V8::IsRunning()); - i::FLAG_logfile = "*"; - i::FLAG_log = true; - i::FLAG_log_code = true; - - // Make sure objects move. - bool saved_always_compact = i::FLAG_always_compact; - if (!i::FLAG_never_compact) { - i::FLAG_always_compact = true; - } - - v8::HandleScope scope; - v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>(); - v8::Handle<v8::Context> env = v8::Context::New( - 0, v8::Handle<v8::ObjectTemplate>(), global_object); - env->Enter(); + // Start with profiling to capture all code events from the beginning. + ScopedLoggerInitializer initialize_logger(false); // Compile and run a function that creates other functions. - CompileAndRunScript( + CompileRun( "(function f(obj) {\n" " obj.test =\n" " (function a(j) { return function b() { return j; } })(100);\n" "})(this);"); - HEAP->CollectAllGarbage(false); - - EmbeddedVector<char, 204800> buffer; - int log_size; - ParseLogResult ref_result; - - // Retrieve the log. - { - // Make sure that no GCs occur prior to LogCompiledFunctions call. - i::AssertNoAllocation no_alloc; - - log_size = GetLogLines(0, &buffer); - CHECK_GT(log_size, 0); - CHECK_GT(buffer.length(), log_size); - - // Fill a map of compiled code objects. - ParseLog(buffer.start(), buffer.start() + log_size, &ref_result); - } + v8::V8::PauseProfiler(); + HEAP->CollectAllGarbage(true); + LOGGER->StringEvent("test-logging-done", ""); // Iterate heap to find compiled functions, will write to log. LOGGER->LogCompiledFunctions(); - char* new_log_start = buffer.start() + log_size; - const int new_log_size = LOGGER->GetLogLines( - log_size, new_log_start, buffer.length() - log_size); - CHECK_GT(new_log_size, 0); - CHECK_GT(buffer.length(), log_size + new_log_size); - - // Fill an equivalent map of compiled code objects. - ParseLogResult new_result; - ParseLog(new_log_start, new_log_start + new_log_size, &new_result); - - // Test their actual equivalence. - Interval combined; - combined.CloneFrom(&ref_result.bounds); - combined.CloneFrom(&new_result.bounds); - Interval* iter = &combined; - bool results_equal = true; - - while (iter != NULL) { - for (Address addr = iter->raw_min_addr(); - addr <= iter->raw_max_addr(); ++addr) { - CodeEntityInfo ref_entity = ref_result.GetEntity(addr); - CodeEntityInfo new_entity = new_result.GetEntity(addr); - if (ref_entity != NULL || new_entity != NULL) { - const bool equal = AreEntitiesEqual(ref_entity, new_entity); - if (!equal) results_equal = false; - PrintCodeEntitiesInfo(equal, addr, ref_entity, new_entity); - } + LOGGER->StringEvent("test-traversal-done", ""); + + bool exists = false; + i::Vector<const char> log( + i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true)); + CHECK(exists); + v8::Handle<v8::String> log_str = v8::String::New(log.start(), log.length()); + initialize_logger.env()->Global()->Set(v8_str("_log"), log_str); + + const char* scripts[] = { + "tools/splaytree.js", "tools/codemap.js", "tools/csvparser.js", + "tools/consarray.js", "tools/profile.js", "tools/profile_view.js", + "tools/logreader.js", "test/cctest/log-eq-of-logging-and-traversal.js" + }; + int scripts_count = sizeof(scripts) / sizeof(scripts[0]); + v8::Handle<v8::Value> last_result; + for (int i = 0; i < scripts_count; ++i) { + bool exists = true; + i::Vector<const char> source(i::ReadFile(scripts[i], &exists, true)); + CHECK(exists); + CHECK_GT(source.length(), 0); + v8::Handle<v8::String> source_str = + v8::String::New(source.start(), source.length()); + v8::TryCatch try_catch; + v8::Handle<v8::Script> script = + v8::Script::Compile(source_str, v8_str(scripts[i])); + if (script.IsEmpty()) { + v8::String::Utf8Value exception(try_catch.Exception()); + printf("compile %s: %s\n", scripts[i], *exception); + CHECK(false); + } + last_result = script->Run(); + if (last_result.IsEmpty()) { + v8::String::Utf8Value exception(try_catch.Exception()); + printf("run %s: %s\n", scripts[i], *exception); + CHECK(false); } - iter = iter->get_next(); } - // Make sure that all log data is written prior crash due to CHECK failure. - fflush(stdout); - CHECK(results_equal); - - env->Exit(); - LOGGER->TearDown(); - i::FLAG_always_compact = saved_always_compact; + // The result either be a "true" literal or problem description. + if (!last_result->IsTrue()) { + v8::Local<v8::String> s = last_result->ToString(); + i::ScopedVector<char> data(s->Length() + 1); + CHECK_NE(NULL, data.start()); + s->WriteAscii(data.start()); + printf("%s\n", data.start()); + // Make sure that our output is written prior crash due to CHECK failure. + fflush(stdout); + CHECK(false); + } } - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-profile-generator.cc b/deps/v8/test/cctest/test-profile-generator.cc index fbe5834e54..6d30443178 100644 --- a/deps/v8/test/cctest/test-profile-generator.cc +++ b/deps/v8/test/cctest/test-profile-generator.cc @@ -2,8 +2,6 @@ // // Tests of profiles generator and utilities. -#ifdef ENABLE_LOGGING_AND_PROFILING - #include "v8.h" #include "profile-generator-inl.h" #include "cctest.h" @@ -824,5 +822,3 @@ TEST(Issue51919) { for (int i = 0; i < CpuProfilesCollection::kMaxSimultaneousProfiles; ++i) i::DeleteArray(titles[i]); } - -#endif // ENABLE_LOGGING_AND_PROFILING diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index 6588c68b7d..9f18b600b2 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -41,19 +41,25 @@ #ifdef V8_INTERPRETED_REGEXP #include "interpreter-irregexp.h" #else // V8_INTERPRETED_REGEXP +#include "macro-assembler.h" +#include "code.h" #ifdef V8_TARGET_ARCH_ARM +#include "arm/assembler-arm.h" #include "arm/macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h" #endif #ifdef V8_TARGET_ARCH_MIPS +#include "mips/assembler-mips.h" #include "mips/macro-assembler-mips.h" #include "mips/regexp-macro-assembler-mips.h" #endif #ifdef V8_TARGET_ARCH_X64 +#include "x64/assembler-x64.h" #include "x64/macro-assembler-x64.h" #include "x64/regexp-macro-assembler-x64.h" #endif #ifdef V8_TARGET_ARCH_IA32 +#include "ia32/assembler-ia32.h" #include "ia32/macro-assembler-ia32.h" #include "ia32/regexp-macro-assembler-ia32.h" #endif |