Commit 08dba83a authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[d8] Support more console functions

- console.assert now fails properly
- console.trace dumps a low-level stack trace
- console.time/End dumps a timer event to the log file
- console.timeStamp dumps a timer event to the log

Drive-by-fixes:
- simplify test-log.cc
- fix test-log.cc log parser JS helper
- always start the default timer int the logger

Change-Id: I0bb26b9410a4e0d1d5bc8621d8b2243922fe3f29
Reviewed-on: https://chromium-review.googlesource.com/702459Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48531}
parent ce96e422
......@@ -35,10 +35,7 @@ namespace internal {
V(Profile, profile) \
V(ProfileEnd, profileEnd) \
V(Timeline, timeline) \
V(TimelineEnd, timelineEnd) \
V(Time, time) \
V(TimeEnd, timeEnd) \
V(TimeStamp, timeStamp)
V(TimelineEnd, timelineEnd)
namespace {
void ConsoleCall(
......@@ -63,6 +60,20 @@ void ConsoleCall(
wrapper,
v8::debug::ConsoleContext(context_id, Utils::ToLocal(context_name)));
}
void LogTimerEvent(Isolate* isolate, BuiltinArguments args,
Logger::StartEnd se) {
if (!isolate->logger()->is_logging()) return;
HandleScope scope(isolate);
std::unique_ptr<char[]> name;
const char* raw_name = "default";
if (args.length() > 1 && args[1]->IsString()) {
// Try converting the first argument to a string.
name = args.at<String>(1)->ToCString();
raw_name = name.get();
}
LOG(isolate, TimerEvent(se, raw_name));
}
} // namespace
#define CONSOLE_BUILTIN_IMPLEMENTATION(call, name) \
......@@ -74,6 +85,27 @@ void ConsoleCall(
CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_IMPLEMENTATION)
#undef CONSOLE_BUILTIN_IMPLEMENTATION
BUILTIN(ConsoleTime) {
LogTimerEvent(isolate, args, Logger::START);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::Time);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->undefined_value();
}
BUILTIN(ConsoleTimeEnd) {
LogTimerEvent(isolate, args, Logger::END);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeEnd);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->undefined_value();
}
BUILTIN(ConsoleTimeStamp) {
LogTimerEvent(isolate, args, Logger::STAMP);
ConsoleCall(isolate, args, &debug::ConsoleDelegate::TimeStamp);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->undefined_value();
}
namespace {
void InstallContextFunction(Handle<JSObject> target, const char* name,
Builtins::Name call, int context_id,
......@@ -120,6 +152,12 @@ BUILTIN(ConsoleContext) {
args.at(1));
CONSOLE_METHOD_LIST(CONSOLE_BUILTIN_SETUP)
#undef CONSOLE_BUILTIN_SETUP
InstallContextFunction(context, "time", Builtins::kConsoleTime, id,
args.at(1));
InstallContextFunction(context, "timeEnd", Builtins::kConsoleTimeEnd, id,
args.at(1));
InstallContextFunction(context, "timeStamp", Builtins::kConsoleTimeStamp, id,
args.at(1));
return *context;
}
......
......@@ -4,15 +4,17 @@
#include "src/d8-console.h"
#include "src/d8.h"
#include "src/isolate.h"
namespace v8 {
namespace {
void WriteToFile(FILE* file, Isolate* isolate,
void WriteToFile(const char* action, FILE* file, Isolate* isolate,
const debug::ConsoleCallArguments& args) {
fprintf(file, "console.%s: ", action);
for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope(isolate);
if (i != 0) fprintf(file, " ");
if (i > 0) fprintf(file, " ");
Local<Value> arg = args[i];
Local<String> str_obj;
......@@ -35,29 +37,48 @@ D8Console::D8Console(Isolate* isolate) : isolate_(isolate) {
default_timer_ = base::TimeTicks::HighResolutionNow();
}
void D8Console::Assert(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
Local<Boolean> arg;
if (args.Length() > 0) {
if (!args[0]->ToBoolean(isolate_->GetCurrentContext()).ToLocal(&arg)) {
return;
}
} else {
// No arguments given, the "first" argument is undefined which is false-ish.
arg = v8::False(isolate_);
}
if (arg->IsTrue()) return;
WriteToFile("assert", stdout, isolate_, args);
isolate_->ThrowException(v8::Exception::Error(
v8::String::NewFromUtf8(isolate_, "console.assert failed",
v8::NewStringType::kNormal)
.ToLocalChecked()));
}
void D8Console::Log(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
WriteToFile(stdout, isolate_, args);
WriteToFile("log", stdout, isolate_, args);
}
void D8Console::Error(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
WriteToFile(stderr, isolate_, args);
WriteToFile("error", stderr, isolate_, args);
}
void D8Console::Warn(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
WriteToFile(stdout, isolate_, args);
WriteToFile("warn", stdout, isolate_, args);
}
void D8Console::Info(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
WriteToFile(stdout, isolate_, args);
WriteToFile("info", stdout, isolate_, args);
}
void D8Console::Debug(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
WriteToFile(stdout, isolate_, args);
WriteToFile("debug", stdout, isolate_, args);
}
void D8Console::Time(const debug::ConsoleCallArguments& args,
......@@ -84,11 +105,11 @@ void D8Console::Time(const debug::ConsoleCallArguments& args,
void D8Console::TimeEnd(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
base::TimeDelta delta;
base::TimeTicks now = base::TimeTicks::HighResolutionNow();
if (args.Length() == 0) {
delta = base::TimeTicks::HighResolutionNow() - default_timer_;
printf("default: ");
printf("console.timeEnd: default, %f\n", delta.InMillisecondsF());
} else {
base::TimeTicks now = base::TimeTicks::HighResolutionNow();
Local<Value> arg = args[0];
Local<String> label;
v8::TryCatch try_catch(isolate_);
......@@ -99,9 +120,30 @@ void D8Console::TimeEnd(const debug::ConsoleCallArguments& args,
if (find != timers_.end()) {
delta = now - find->second;
}
printf("%s: ", *utf8);
printf("console.timeEnd: %s, %f\n", *utf8, delta.InMillisecondsF());
}
printf("%f\n", delta.InMillisecondsF());
}
void D8Console::TimeStamp(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
base::TimeDelta delta = base::TimeTicks::HighResolutionNow() - default_timer_;
if (args.Length() == 0) {
printf("console.timeStamp: default, %f\n", delta.InMillisecondsF());
} else {
Local<Value> arg = args[0];
Local<String> label;
v8::TryCatch try_catch(isolate_);
if (!arg->ToString(isolate_->GetCurrentContext()).ToLocal(&label)) return;
v8::String::Utf8Value utf8(isolate_, label);
std::string string(*utf8);
printf("console.timeStamp: %s, %f\n", *utf8, delta.InMillisecondsF());
}
}
void D8Console::Trace(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
i_isolate->PrintStack(stderr, i::Isolate::kPrintStackConcise);
}
} // namespace v8
......@@ -16,6 +16,8 @@ class D8Console : public debug::ConsoleDelegate {
explicit D8Console(Isolate* isolate);
private:
void Assert(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) override;
void Log(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) override;
void Error(const debug::ConsoleCallArguments& args,
......@@ -30,6 +32,10 @@ class D8Console : public debug::ConsoleDelegate {
const v8::debug::ConsoleContext&) override;
void TimeEnd(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) override;
void TimeStamp(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) override;
void Trace(const debug::ConsoleCallArguments& args,
const v8::debug::ConsoleContext&) override;
Isolate* isolate_;
std::map<std::string, base::TimeTicks> timers_;
......
......@@ -722,7 +722,8 @@ class Isolate {
void PrintCurrentStackTrace(FILE* out);
void PrintStack(StringStream* accumulator,
PrintStackMode mode = kPrintStackVerbose);
void PrintStack(FILE* out, PrintStackMode mode = kPrintStackVerbose);
V8_EXPORT_PRIVATE void PrintStack(FILE* out,
PrintStackMode mode = kPrintStackVerbose);
Handle<String> StackTraceString();
// Stores a stack trace in a stack-allocated temporary buffer which will
// end up in the minidump for debugging purposes.
......
......@@ -845,9 +845,7 @@ void Logger::CodeDeoptEvent(Code* code, DeoptKind kind, Address pc,
if (!log_->IsEnabled()) return;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
Log::MessageBuilder msg(log_);
int since_epoch = timer_.IsStarted()
? static_cast<int>(timer_.Elapsed().InMicroseconds())
: -1;
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
msg.Append("code-deopt,%d,%d,", since_epoch, code->CodeSize());
msg.AppendAddress(code->instruction_start());
......@@ -893,24 +891,27 @@ void Logger::CurrentTimeEvent() {
void Logger::TimerEvent(Logger::StartEnd se, const char* name) {
if (!log_->IsEnabled()) return;
DCHECK(FLAG_log_internal_timer_events);
Log::MessageBuilder msg(log_);
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
const char* format = (se == START) ? "timer-event-start,\"%s\",%ld"
: "timer-event-end,\"%s\",%ld";
const char* format = (se == START)
? "timer-event-start,\"%s\",%ld"
: (se == END) ? "timer-event-end,\"%s\",%ld"
: "timer-event,\"%s\",%ld";
msg.Append(format, name, since_epoch);
msg.WriteToLogFile();
}
// static
void Logger::EnterExternal(Isolate* isolate) {
DCHECK(FLAG_log_internal_timer_events);
LOG(isolate, TimerEvent(START, TimerEventExternal::name()));
DCHECK(isolate->current_vm_state() == JS);
isolate->set_current_vm_state(EXTERNAL);
}
// static
void Logger::LeaveExternal(Isolate* isolate) {
DCHECK(FLAG_log_internal_timer_events);
LOG(isolate, TimerEvent(END, TimerEventExternal::name()));
DCHECK(isolate->current_vm_state() == EXTERNAL);
isolate->set_current_vm_state(JS);
......@@ -1000,9 +1001,7 @@ void Logger::CallbackEventInternal(const char* prefix, Name* name,
msg.Append("%s,%s,-2,",
kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
kLogEventsNames[CodeEventListener::CALLBACK_TAG]);
int timestamp = timer_.IsStarted()
? static_cast<int>(timer_.Elapsed().InMicroseconds())
: -1;
int timestamp = static_cast<int>(timer_.Elapsed().InMicroseconds());
msg.Append("%d,", timestamp);
msg.AppendAddress(entry_point);
if (name->IsString()) {
......@@ -1048,9 +1047,7 @@ void AppendCodeCreateHeader(Log::MessageBuilder* msg,
msg->Append("%s,%s,%d,",
kLogEventsNames[CodeEventListener::CODE_CREATION_EVENT],
kLogEventsNames[tag], code->kind());
int timestamp = timer->IsStarted()
? static_cast<int>(timer->Elapsed().InMicroseconds())
: -1;
int timestamp = static_cast<int>(timer->Elapsed().InMicroseconds());
msg->Append("%d,", timestamp);
msg->AppendAddress(code->instruction_start());
msg->Append(",%d,", code->instruction_size());
......@@ -1825,7 +1822,7 @@ bool Logger::SetUp(Isolate* isolate) {
is_logging_ = true;
}
if (FLAG_log_internal_timer_events || FLAG_prof_cpp) timer_.Start();
timer_.Start();
if (FLAG_prof_cpp) {
profiler_ = new Profiler(isolate);
......
......@@ -93,7 +93,7 @@ class Ticker;
class Logger : public CodeEventListener {
public:
enum StartEnd { START = 0, END = 1 };
enum StartEnd { START = 0, END = 1, STAMP = 2 };
// Acquires resources for logging if the right flags are set.
bool SetUp(Isolate* isolate);
......@@ -213,7 +213,7 @@ class Logger : public CodeEventListener {
void CurrentTimeEvent();
void TimerEvent(StartEnd se, const char* name);
V8_EXPORT_PRIVATE void TimerEvent(StartEnd se, const char* name);
static void EnterExternal(Isolate* isolate);
static void LeaveExternal(Isolate* isolate);
......
......@@ -39,7 +39,8 @@ function parseState(s) {
function LogProcessor() {
LogReader.call(this, {
'code-creation': {
parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
parsers: [null, parseInt, parseInt, parseInt, parseInt,
null, 'var-args'],
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
......@@ -55,8 +56,10 @@ function LogProcessor() {
LogProcessor.prototype.__proto__ = LogReader.prototype;
LogProcessor.prototype.processCodeCreation = function(
type, kind, start, size, name, maybe_func) {
if (type != "LazyCompile" && type != "Script" && type != "Function") return;
type, kind, timestamp, start, size, name, maybe_func) {
if (type != "LazyCompile" && type != "Script" && type != "Function") {
return;
}
// Scripts will compile into anonymous functions starting at 1:1. Adjust the
// name here so that it matches corrsponding function's name during the heap
// traversal.
......@@ -66,9 +69,9 @@ LogProcessor.prototype.processCodeCreation = function(
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);
this.profile.addFuncCode(type, name, timestamp, start, size, funcAddr, state);
} else {
this.profile.addCode(type, name, start, size);
this.profile.addCode(type, name, timestamp, start, size);
}
};
......@@ -100,6 +103,7 @@ function RunTest() {
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];
......@@ -170,6 +174,7 @@ function RunTest() {
return [equal, comparison];
}
var result = RunTest();
if (typeof result !== "string") {
var out = [];
......
......@@ -63,6 +63,35 @@ namespace {
i::FLAG_logfile = i::Log::kLogToTemporaryFile; \
i::FLAG_logfile_per_isolate = false
static const char* StrNStr(const char* s1, const char* s2, size_t n) {
CHECK_EQ(s1[n], '\0');
return strstr(s1, s2);
}
// Look for a log line which starts with {prefix} and ends with {suffix}.
static const char* FindLogLine(i::Vector<const char>* log, const char* prefix,
const char* suffix) {
const char* start = log->start();
const char* end = start + log->length();
CHECK_EQ(end[0], '\0');
size_t prefixLength = strlen(prefix);
// Loop through the input until we find /{prefix}[^\n]+{suffix}/.
while (start < end) {
const char* prefixResult = StrNStr(start, prefix, (end - start));
if (!prefixResult) return NULL;
const char* suffixResult =
StrNStr(prefixResult, suffix, (end - prefixResult));
if (!suffixResult) return NULL;
// Check that there are no newlines in between the {prefix} and the {suffix}
// results.
const char* newlineResult =
StrNStr(prefixResult, "\n", (end - prefixResult));
if (!newlineResult) return prefixResult;
if (newlineResult > suffixResult) return prefixResult;
start = prefixResult + prefixLength;
}
return NULL;
}
class ScopedLoggerInitializer {
public:
......@@ -84,6 +113,7 @@ class ScopedLoggerInitializer {
if (temp_file_ != NULL) fclose(temp_file_);
i::FLAG_prof = saved_prof_;
i::FLAG_log = saved_log_;
log_.Dispose();
}
v8::Local<v8::Context>& env() { return env_; }
......@@ -92,6 +122,29 @@ class ScopedLoggerInitializer {
Logger* logger() { return logger_; }
v8::Local<v8::String> GetLogString() {
return v8::String::NewFromUtf8(isolate_, log_.start(),
v8::NewStringType::kNormal, log_.length())
.ToLocalChecked();
}
void StopLogging() {
bool exists = false;
log_ = i::ReadFile(StopLoggingGetTempFile(), &exists, true);
CHECK(exists);
}
const char* FindLine(const char* prefix, const char* suffix) {
return FindLogLine(&log_, prefix, suffix);
}
void LogCompiledFunctions() { logger_->LogCompiledFunctions(); }
void StringEvent(const char* name, const char* value) {
logger_->StringEvent(name, value);
}
private:
FILE* StopLoggingGetTempFile() {
temp_file_ = logger_->TearDown();
CHECK(temp_file_);
......@@ -100,7 +153,6 @@ class ScopedLoggerInitializer {
return temp_file_;
}
private:
const bool saved_log_;
const bool saved_prof_;
FILE* temp_file_;
......@@ -109,23 +161,33 @@ class ScopedLoggerInitializer {
v8::HandleScope scope_;
v8::Local<v8::Context> env_;
Logger* logger_;
i::Vector<const char> log_;
DISALLOW_COPY_AND_ASSIGN(ScopedLoggerInitializer);
};
} // namespace
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::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;
TEST(FindLogLine) {
const char* string =
"prefix1, stuff, suffix1\n"
"prefix2, stuff\n, suffix2\n"
"prefix3suffix3\n"
"prefix4 suffix4";
// Make sure the vector contains the terminating \0 character.
i::Vector<const char> log(string, strlen(string));
CHECK(FindLogLine(&log, "prefix1", "suffix1"));
CHECK(FindLogLine(&log, "prefix1", "suffix1"));
CHECK(!FindLogLine(&log, "prefix2", "suffix2"));
CHECK(!FindLogLine(&log, "prefix1", "suffix2"));
CHECK(!FindLogLine(&log, "prefix1", "suffix3"));
CHECK(FindLogLine(&log, "prefix3", "suffix3"));
CHECK(FindLogLine(&log, "prefix4", "suffix4"));
CHECK(!FindLogLine(&log, "prefix4", "suffix4XXXXXXXXXXXX"));
CHECK(!FindLogLine(&log, "prefix4XXXXXXXXXXXXXXXXXXXXXXxxx", "suffix4"));
CHECK(!FindLogLine(&log, "suffix", "suffix5XXXXXXXXXXXXXXXXXXXX"));
}
// BUG(913). Need to implement support for profiling multiple VM threads.
#if 0
......@@ -344,8 +406,7 @@ TEST(LogCallbacks) {
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate);
Logger* logger = initialize_logger.logger();
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
isolate, v8::FunctionTemplate::New(isolate));
......@@ -357,31 +418,25 @@ TEST(LogCallbacks) {
v8::Local<v8::Value>(), signature),
static_cast<v8::PropertyAttribute>(v8::DontDelete));
initialize_logger.env()
logger.env()
->Global()
->Set(initialize_logger.env(), v8_str("Obj"),
obj->GetFunction(initialize_logger.env()).ToLocalChecked())
->Set(logger.env(), v8_str("Obj"),
obj->GetFunction(logger.env()).ToLocalChecked())
.FromJust();
CompileRun("Obj.prototype.method1.toString();");
logger->LogCompiledFunctions();
logger.LogCompiledFunctions();
bool exists = false;
i::Vector<const char> log(
i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
CHECK(exists);
logger.StopLogging();
Address ObjMethod1_entry = reinterpret_cast<Address>(ObjMethod1);
#if USES_FUNCTION_DESCRIPTORS
ObjMethod1_entry = *FUNCTION_ENTRYPOINT_ADDRESS(ObjMethod1_entry);
#endif
i::EmbeddedVector<char, 100> ref_data;
i::SNPrintF(ref_data,
"code-creation,Callback,-2,-1,0x%" V8PRIxPTR ",1,\"method1\"",
i::SNPrintF(ref_data, ",0x%" V8PRIxPTR ",1,\"method1\"",
reinterpret_cast<intptr_t>(ObjMethod1_entry));
CHECK(StrNStr(log.start(), ref_data.start(), log.length()));
log.Dispose();
CHECK(logger.FindLine("code-creation,Callback,-2,", ref_data.start()));
}
isolate->Dispose();
}
......@@ -407,8 +462,7 @@ TEST(LogAccessorCallbacks) {
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate);
Logger* logger = initialize_logger.logger();
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
v8::Local<v8::FunctionTemplate> obj = v8::Local<v8::FunctionTemplate>::New(
isolate, v8::FunctionTemplate::New(isolate));
......@@ -417,51 +471,43 @@ TEST(LogAccessorCallbacks) {
inst->SetAccessor(v8_str("prop1"), Prop1Getter, Prop1Setter);
inst->SetAccessor(v8_str("prop2"), Prop2Getter);
logger->LogAccessorCallbacks();
logger.logger()->LogAccessorCallbacks();
bool exists = false;
i::Vector<const char> log(
i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
CHECK(exists);
logger.StopLogging();
Address Prop1Getter_entry = reinterpret_cast<Address>(Prop1Getter);
#if USES_FUNCTION_DESCRIPTORS
Prop1Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Getter_entry);
#endif
EmbeddedVector<char, 100> prop1_getter_record;
i::SNPrintF(prop1_getter_record,
"code-creation,Callback,-2,-1,0x%" V8PRIxPTR ",1,\"get prop1\"",
i::SNPrintF(prop1_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop1\"",
reinterpret_cast<intptr_t>(Prop1Getter_entry));
CHECK(StrNStr(log.start(), prop1_getter_record.start(), log.length()));
CHECK(logger.FindLine("code-creation,Callback,-2,",
prop1_getter_record.start()));
Address Prop1Setter_entry = reinterpret_cast<Address>(Prop1Setter);
#if USES_FUNCTION_DESCRIPTORS
Prop1Setter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop1Setter_entry);
#endif
EmbeddedVector<char, 100> prop1_setter_record;
i::SNPrintF(prop1_setter_record,
"code-creation,Callback,-2,-1,0x%" V8PRIxPTR ",1,\"set prop1\"",
i::SNPrintF(prop1_setter_record, ",0x%" V8PRIxPTR ",1,\"set prop1\"",
reinterpret_cast<intptr_t>(Prop1Setter_entry));
CHECK(StrNStr(log.start(), prop1_setter_record.start(), log.length()));
CHECK(logger.FindLine("code-creation,Callback,-2,",
prop1_setter_record.start()));
Address Prop2Getter_entry = reinterpret_cast<Address>(Prop2Getter);
#if USES_FUNCTION_DESCRIPTORS
Prop2Getter_entry = *FUNCTION_ENTRYPOINT_ADDRESS(Prop2Getter_entry);
#endif
EmbeddedVector<char, 100> prop2_getter_record;
i::SNPrintF(prop2_getter_record,
"code-creation,Callback,-2,-1,0x%" V8PRIxPTR ",1,\"get prop2\"",
i::SNPrintF(prop2_getter_record, ",0x%" V8PRIxPTR ",1,\"get prop2\"",
reinterpret_cast<intptr_t>(Prop2Getter_entry));
CHECK(StrNStr(log.start(), prop2_getter_record.start(), log.length()));
log.Dispose();
CHECK(logger.FindLine("code-creation,Callback,-2,",
prop2_getter_record.start()));
}
isolate->Dispose();
}
typedef i::NativesCollection<i::TEST> TestSources;
// Test that logging of code create / move events is equivalent to traversal of
// a resulting heap.
TEST(EquivalenceOfLoggingAndTraversal) {
......@@ -477,8 +523,7 @@ TEST(EquivalenceOfLoggingAndTraversal) {
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate);
Logger* logger = initialize_logger.logger();
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
// Compile and run a function that creates other functions.
CompileRun(
......@@ -486,29 +531,26 @@ TEST(EquivalenceOfLoggingAndTraversal) {
" obj.test =\n"
" (function a(j) { return function b() { return j; } })(100);\n"
"})(this);");
logger->StopProfiler();
logger.logger()->StopProfiler();
reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
i::Heap::kMakeHeapIterableMask, i::GarbageCollectionReason::kTesting);
logger->StringEvent("test-logging-done", "");
logger.StringEvent("test-logging-done", "");
// Iterate heap to find compiled functions, will write to log.
logger->LogCompiledFunctions();
logger->StringEvent("test-traversal-done", "");
logger.LogCompiledFunctions();
logger.StringEvent("test-traversal-done", "");
bool exists = false;
i::Vector<const char> log(
i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
CHECK(exists);
v8::Local<v8::String> log_str =
v8::String::NewFromUtf8(isolate, log.start(),
v8::NewStringType::kNormal, log.length())
.ToLocalChecked();
initialize_logger.env()
logger.StopLogging();
v8::Local<v8::String> log_str = logger.GetLogString();
logger.env()
->Global()
->Set(initialize_logger.env(), v8_str("_log"), log_str)
->Set(logger.env(), v8_str("_log"), log_str)
.FromJust();
i::Vector<const char> source = TestSources::GetScriptsSource();
// Load the Test snapshot's sources, see log-eq-of-logging-and-traversal.js
i::Vector<const char> source =
i::NativesCollection<i::TEST>::GetScriptsSource();
v8::Local<v8::String> source_str =
v8::String::NewFromUtf8(isolate, source.start(),
v8::NewStringType::kNormal, source.length())
......@@ -521,15 +563,14 @@ TEST(EquivalenceOfLoggingAndTraversal) {
CHECK(false);
}
v8::Local<v8::Value> result;
if (!script->Run(initialize_logger.env()).ToLocal(&result)) {
if (!script->Run(logger.env()).ToLocal(&result)) {
v8::String::Utf8Value exception(isolate, try_catch.Exception());
printf("run: %s\n", *exception);
CHECK(false);
}
// The result either be a "true" literal or problem description.
// The result either be the "true" literal or problem description.
if (!result->IsTrue()) {
v8::Local<v8::String> s =
result->ToString(initialize_logger.env()).ToLocalChecked();
v8::Local<v8::String> s = result->ToString(logger.env()).ToLocalChecked();
i::ScopedVector<char> data(s->Utf8Length() + 1);
CHECK(data.start());
s->WriteUtf8(data.start());
......@@ -549,17 +590,14 @@ TEST(LogVersion) {
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate);
bool exists = false;
i::Vector<const char> log(
i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
CHECK(exists);
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
logger.StopLogging();
i::EmbeddedVector<char, 100> ref_data;
i::SNPrintF(ref_data, "v8-version,%d,%d,%d,%d,%d", i::Version::GetMajor(),
i::SNPrintF(ref_data, "%d,%d,%d,%d,%d", i::Version::GetMajor(),
i::Version::GetMinor(), i::Version::GetBuild(),
i::Version::GetPatch(), i::Version::IsCandidate());
CHECK(StrNStr(log.start(), ref_data.start(), log.length()));
log.Dispose();
CHECK(logger.FindLine("v8-version,", ref_data.start()));
}
isolate->Dispose();
}
......@@ -584,9 +622,8 @@ TEST(Issue539892) {
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
ScopedLoggerInitializer initialize_logger(saved_log, saved_prof, isolate);
Logger* logger = initialize_logger.logger();
logger->addCodeEventListener(&code_event_logger);
ScopedLoggerInitializer logger(saved_log, saved_prof, isolate);
logger.logger()->addCodeEventListener(&code_event_logger);
// Function with a really large name.
const char* source_text =
......@@ -613,7 +650,7 @@ TEST(Issue539892) {
CompileRun(source_text);
// Must not crash.
logger->LogCompiledFunctions();
logger.LogCompiledFunctions();
}
isolate->Dispose();
}
......@@ -18,7 +18,6 @@ console.timeEnd("a", "b");
console.log("log", "more");
console.warn("warn", { toString: () => 2 });
console.error("error");
console.debug("debug");
console.info("info");
......
default: {NUMBER}
abcd: {NUMBER}
b: 0.000000
a: {NUMBER}
log more
warn 2
debug
info
*%(basename)s:25: Error: exception
console.timeEnd: default, {NUMBER}
console.timeEnd: abcd, {NUMBER}
console.timeEnd: b, {NUMBER}
console.timeEnd: a, {NUMBER}
console.log: log more
console.warn: warn 2
console.debug: debug
console.info: info
console.info: *%(basename)s:24: Error: exception
console.info({ toString: () => {throw new Error("exception");} })
^
Error: exception
at Object.toString (*%(basename)s:25:39)
at Object.toString (*%(basename)s:24:39)
at console.info (<anonymous>)
at *%(basename)s:25:9
at *%(basename)s:24:9
state: 0
state: 0
increment state
current state: 1
increment state
current state: 2
increment state
current state: 3
console.log: state: 0
console.log: state: 0
console.log: increment state
console.log: current state: 1
console.log: increment state
console.log: current state: 2
console.log: increment state
console.log: current state: 3
*%(basename)s:19: Error
setTimeout(function() { throw new Error(); });
^
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
console.assert(true);
console.assert("yes");
assertThrows(() => console.assert(false), Error);
assertThrows(() => console.assert(""), Error);
assertThrows(() => console.assert(0), Error);
let args = ["", {}, [], this, Array, 1, 1.4, true, false];
console.log(...args);
console.error(...args);
console.warn(...args);
console.info(...args);
console.debug(...args);
console.time();
console.timeEnd();
console.time("a");
console.timeEnd("a");
console.timeStamp();
args.forEach(each => console.timeStamp(each));
console.trace();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment