14#include "src/inspector/protocol/Protocol.h"
31 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Log;
33 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Debug;
35 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Info;
37 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Error;
39 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Warning;
41 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Clear;
43 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Dir;
45 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Dirxml;
47 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Table;
49 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Trace;
51 return protocol::Runtime::ConsoleAPICalled::TypeEnum::StartGroup;
53 return protocol::Runtime::ConsoleAPICalled::TypeEnum::StartGroupCollapsed;
55 return protocol::Runtime::ConsoleAPICalled::TypeEnum::EndGroup;
57 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Assert;
59 return protocol::Runtime::ConsoleAPICalled::TypeEnum::TimeEnd;
61 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Count;
63 return protocol::Runtime::ConsoleAPICalled::TypeEnum::Log;
66const char kGlobalConsoleMessageHandleLabel[] =
"DevTools console";
67const unsigned maxConsoleMessageCount = 1000;
68const int maxConsoleMessageV8Size = 10 * 1024 * 1024;
69const unsigned maxArrayItemsLimit = 10000;
70const unsigned maxStackDepthLimit = 32;
72class V8ValueStringBuilder {
76 V8ValueStringBuilder builder(context);
77 if (!builder.append(value))
return String16();
78 return builder.toString();
84 IgnoreUndefined = 1 << 1,
95 if (value.IsEmpty())
return true;
96 if ((ignoreOptions & IgnoreNull) && value->IsNull())
return true;
97 if ((ignoreOptions & IgnoreUndefined) && value->IsUndefined())
return true;
98 if (value->IsBigIntObject()) {
100 }
else if (value->IsBooleanObject()) {
103 }
else if (value->IsNumberObject()) {
106 }
else if (value->IsStringObject()) {
108 }
else if (value->IsSymbolObject()) {
111 if (value->IsString())
return append(value.As<
v8::String>());
112 if (value->IsBigInt())
return append(value.As<
v8::BigInt>());
113 if (value->IsSymbol())
return append(value.As<
v8::Symbol>());
114 if (value->IsArray())
return append(value.As<
v8::Array>());
115 if (value->IsProxy()) {
119 if (value->IsObject() && !value->IsDate() && !value->IsFunction() &&
120 !value->IsNativeError() && !value->IsRegExp()) {
123 if (object->ObjectProtoToString(m_context).ToLocal(&stringValue))
124 return append(stringValue);
127 if (!value->ToString(m_context).ToLocal(&stringValue))
return false;
128 return append(stringValue);
132 for (
const auto& it : m_visitedArrays) {
133 if (it == array)
return true;
135 uint32_t length = array->Length();
136 if (length > m_arrayLimit)
return false;
145 if (!array->Get(m_context,
i).ToLocal(&value))
continue;
146 if (!append(value, IgnoreNull | IgnoreUndefined)) {
157 bool result = append(symbol->Description(m_isolate), IgnoreUndefined);
164 if (!bigint->ToString(m_context).ToLocal(&bigint_string))
return false;
165 bool result = append(bigint_string);
173 if (!
string.IsEmpty()) {
179 String16 toString() {
197 m_timestamp(timestamp),
205 m_revokedExceptionId(0) {}
210 unsigned columnNumber,
211 std::unique_ptr<V8StackTraceImpl> stackTrace,
213 const char* dataURIPrefix =
"data:";
214 if (url.
substring(0, strlen(dataURIPrefix)) == dataURIPrefix) {
226 protocol::Console::Frontend* frontend)
const {
228 String16 level = protocol::Console::ConsoleMessage::LevelEnum::Log;
231 level = protocol::Console::ConsoleMessage::LevelEnum::Debug;
234 level = protocol::Console::ConsoleMessage::LevelEnum::Error;
236 level = protocol::Console::ConsoleMessage::LevelEnum::Warning;
238 level = protocol::Console::ConsoleMessage::LevelEnum::Info;
239 std::unique_ptr<protocol::Console::ConsoleMessage>
result =
240 protocol::Console::ConsoleMessage::create()
241 .setSource(protocol::Console::ConsoleMessage::SourceEnum::ConsoleApi)
248 frontend->messageAdded(std::move(
result));
251std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>>
253 bool generatePreview)
const {
257 if (
m_arguments.empty() || !contextId)
return nullptr;
259 inspector->
getContext(contextGroupId, contextId);
260 if (!inspectedContext)
return nullptr;
267 std::make_unique<protocol::Array<protocol::Runtime::RemoteObject>>();
275 if (secondArgument->IsArray()) {
277 }
else if (secondArgument->IsString()) {
280 if (array->Set(context, 0, secondArgument).IsJust()) {
285 std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =
287 inspectedContext = inspector->
getContext(contextGroupId, contextId);
288 if (!inspectedContext)
return nullptr;
290 args->emplace_back(std::move(wrapped));
296 std::unique_ptr<protocol::Runtime::RemoteObject> wrapped =
299 inspectedContext = inspector->
getContext(contextGroupId, contextId);
300 if (!inspectedContext)
return nullptr;
305 args->emplace_back(std::move(wrapped));
313 bool generatePreview)
const {
320 std::unique_ptr<protocol::Runtime::RemoteObject> exception =
323 std::unique_ptr<protocol::Runtime::ExceptionDetails> exceptionDetails =
324 protocol::Runtime::ExceptionDetails::create()
334 exceptionDetails->setStackTrace(
338 if (exception) exceptionDetails->setException(std::move(exception));
339 std::unique_ptr<protocol::DictionaryValue> data =
341 if (data) exceptionDetails->setExceptionMetaData(std::move(data));
342 frontend->exceptionThrown(
m_timestamp, std::move(exceptionDetails));
350 std::unique_ptr<protocol::Array<protocol::Runtime::RemoteObject>>
355 std::make_unique<protocol::Array<protocol::Runtime::RemoteObject>>();
357 std::unique_ptr<protocol::Runtime::RemoteObject> messageArg =
358 protocol::Runtime::RemoteObject::create()
359 .setType(protocol::Runtime::RemoteObject::TypeEnum::String)
361 messageArg->setValue(protocol::StringValue::create(
m_message));
362 arguments->emplace_back(std::move(messageArg));
365 std::optional<String16> consoleContext;
367 std::unique_ptr<protocol::Runtime::StackTrace> stackTrace;
383 frontend->consoleAPICalled(
385 m_timestamp, std::move(stackTrace), std::move(consoleContext));
391std::unique_ptr<protocol::DictionaryValue>
401 if (!maybe_exception.
ToLocal(&exception))
return nullptr;
406std::unique_ptr<protocol::Runtime::RemoteObject>
408 bool generatePreview)
const {
413 if (!inspectedContext)
return nullptr;
433 std::unique_ptr<V8StackTraceImpl> stackTrace) {
436 std::unique_ptr<V8ConsoleMessage> message(
438 if (stackTrace && !stackTrace->isEmpty()) {
439 message->m_url =
toString16(stackTrace->topSourceURL());
440 message->m_lineNumber = stackTrace->topLineNumber();
441 message->m_columnNumber = stackTrace->topColumnNumber();
443 message->m_stackTrace = std::move(stackTrace);
444 message->m_consoleContext = consoleContext;
445 message->m_type =
type;
446 message->m_contextId = contextId;
448 std::unique_ptr<v8::Global<v8::Value>> argument(
450 argument->AnnotateStrongRetainer(kGlobalConsoleMessageHandleLabel);
451 message->m_arguments.push_back(std::move(argument));
457 message->m_message +=
String16(
" ");
461 message->m_message += V8ValueStringBuilder::toString(arg, v8Context);
483 message->m_columnNumber, message->m_stackTrace.get());
492 unsigned lineNumber,
unsigned columnNumber,
493 std::unique_ptr<V8StackTraceImpl> stackTrace,
int scriptId,
496 std::unique_ptr<V8ConsoleMessage> consoleMessage(
498 consoleMessage->setLocation(url, lineNumber, columnNumber,
499 std::move(stackTrace), scriptId);
500 consoleMessage->m_exceptionId = exceptionId;
501 consoleMessage->m_detailedMessage = detailedMessage;
502 if (contextId && !exception.IsEmpty()) {
503 consoleMessage->m_contextId = contextId;
504 consoleMessage->m_arguments.push_back(
507 consoleMessage->m_v8Size +=
510 return consoleMessage;
515 double timestamp,
const String16& messageText,
516 unsigned revokedExceptionId) {
519 message->m_revokedExceptionId = revokedExceptionId;
537 :
m_inspector(inspector), m_contextGroupId(contextGroupId) {}
562 std::unique_ptr<V8ConsoleMessage> message) {
567 TraceV8ConsoleMessageEvent(message->origin(), message->type());
578 if (
m_messages.size() == maxConsoleMessageCount) {
582 while (
m_estimatedSize + message->estimatedSize() > maxConsoleMessageV8Size &&
599 for (
auto& data :
m_data) {
600 data.second.m_counters.clear();
601 data.second.m_reportedDeprecationMessages.clear();
607 std::set<String16>& reportedDeprecationMessages =
608 m_data[contextId].m_reportedDeprecationMessages;
609 auto it = reportedDeprecationMessages.find(
method);
610 if (it != reportedDeprecationMessages.end())
return false;
611 reportedDeprecationMessages.insert(it,
method);
622 std::map<LabelKey, int>& counters =
m_data[contextId].m_counters;
624 if (it == counters.end())
return false;
639 int consoleContextId,
641 auto& timers =
m_data[contextId].m_timers;
642 auto it = timers.find(std::make_pair(consoleContextId,
label));
643 if (it == timers.end())
return std::nullopt;
648 int consoleContextId,
650 auto& timers =
m_data[contextId].m_timers;
651 auto it = timers.find(std::make_pair(consoleContextId,
label));
652 if (it == timers.end())
return std::nullopt;
665 auto it =
m_data.find(contextId);
static Local< Array > New(Isolate *isolate, int length=0)
static V8_INLINE Local< Boolean > New(Isolate *isolate, bool value)
V8_INLINE Local< S > As() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
static Local< Number > New(Isolate *isolate, double value)
v8::Local< v8::Context > context() const
v8::Isolate * isolate() const
String16 substring(size_t pos, size_t len=UINT_MAX) const
static String16 fromInteger(int)
void messageAdded(V8ConsoleMessage *)
bool countReset(int contextId, int consoleContextId, const String16 &id)
bool time(int contextId, int consoleContextId, const String16 &label)
bool shouldReportDeprecationMessage(int contextId, const String16 &method)
int count(int contextId, int consoleContextId, const String16 &id)
void contextDestroyed(int contextId)
void addMessage(std::unique_ptr< V8ConsoleMessage >)
std::optional< double > timeLog(int contextId, int consoleContextId, const String16 &label)
V8ConsoleMessageStorage(V8InspectorImpl *, int contextGroupId)
std::map< int, PerContextData > m_data
std::optional< double > timeEnd(int contextId, int consoleContextId, const String16 &label)
std::deque< std::unique_ptr< V8ConsoleMessage > > m_messages
V8InspectorImpl * m_inspector
~V8ConsoleMessageStorage()
std::pair< int, String16 > LabelKey
static std::unique_ptr< V8ConsoleMessage > createForConsoleAPI(v8::Local< v8::Context > v8Context, int contextId, int groupId, V8InspectorImpl *inspector, double timestamp, ConsoleAPIType, v8::MemorySpan< const v8::Local< v8::Value > > arguments, const String16 &consoleContext, std::unique_ptr< V8StackTraceImpl >)
void contextDestroyed(int contextId)
V8MessageOrigin origin() const
void reportToFrontend(protocol::Console::Frontend *) const
std::unique_ptr< V8StackTraceImpl > m_stackTrace
std::unique_ptr< protocol::DictionaryValue > getAssociatedExceptionData(V8InspectorImpl *inspector, V8InspectorSessionImpl *session) const
static std::unique_ptr< V8ConsoleMessage > createForRevokedException(double timestamp, const String16 &message, unsigned revokedExceptionId)
ConsoleAPIType type() const
std::vector< std::unique_ptr< v8::Global< v8::Value > > > Arguments
static std::unique_ptr< V8ConsoleMessage > createForException(double timestamp, const String16 &detailedMessage, const String16 &url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr< V8StackTraceImpl >, int scriptId, v8::Isolate *, const String16 &message, int contextId, v8::Local< v8::Value > exception, unsigned exceptionId)
std::unique_ptr< protocol::Runtime::RemoteObject > wrapException(V8InspectorSessionImpl *, bool generatePreview) const
unsigned m_revokedExceptionId
std::unique_ptr< protocol::Array< protocol::Runtime::RemoteObject > > wrapArguments(V8InspectorSessionImpl *, bool generatePreview) const
String16 m_consoleContext
String16 m_detailedMessage
void setLocation(const String16 &url, unsigned lineNumber, unsigned columnNumber, std::unique_ptr< V8StackTraceImpl >, int scriptId)
V8ConsoleMessage(V8MessageOrigin, double timestamp, const String16 &message)
virtual double currentTimeMS()
virtual void consoleAPIMessage(int contextGroupId, v8::Isolate::MessageErrorLevel level, const StringView &message, const StringView &url, unsigned lineNumber, unsigned columnNumber, V8StackTrace *)
std::unique_ptr< protocol::DictionaryValue > getAssociatedExceptionDataForProtocol(v8::Local< v8::Value > exception)
v8::Isolate * isolate() const
InspectedContext * getContext(int groupId, int contextId) const
bool hasConsoleMessageStorage(int contextGroupId)
V8InspectorClient * client()
void forEachSession(int contextGroupId, const std::function< void(V8InspectorSessionImpl *)> &callback)
std::unique_ptr< protocol::Runtime::RemoteObject > wrapObject(v8::Local< v8::Context >, v8::Local< v8::Value >, const String16 &groupName, bool generatePreview)
void releaseObjectGroup(const String16 &objectGroup)
V8InspectorImpl * inspector() const
V8ConsoleAgentImpl * consoleAgent()
std::unique_ptr< protocol::Runtime::RemoteObject > wrapTable(v8::Local< v8::Context >, v8::Local< v8::Object > table, v8::MaybeLocal< v8::Array > columns)
V8RuntimeAgentImpl * runtimeAgent()
int contextGroupId() const
void messageAdded(V8ConsoleMessage *)
base::Vector< const DirectHandle< Object > > args
ZoneVector< RpoNumber > & result
int EstimatedValueSize(Isolate *v8_isolate, Local< Value > value)
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
StringView toStringView(const String16 &string)
String16 toString16(const StringView &string)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
#define TRACE_EVENT_INSTANT0(category_group, name, scope)
#define TRACE_EVENT_SCOPE_THREAD
v8::LocalVector< v8::Array > m_visitedArrays
v8::Local< v8::Context > m_context
String16Builder m_builder
V8InspectorImpl * m_inspector
std::unique_ptr< ValueMirror > value