Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: third_party/WebKit/Source/platform/v8_inspector/V8Console.cpp

Issue 1859293002: [DevTools] Move Console to v8_inspector (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "platform/v8_inspector/V8Console.h"
6
7 #include "platform/inspector_protocol/String16.h"
8 #include "platform/v8_inspector/InspectedContext.h"
9 #include "platform/v8_inspector/V8DebuggerImpl.h"
10 #include "platform/v8_inspector/V8InspectorSessionImpl.h"
11 #include "platform/v8_inspector/V8ProfilerAgentImpl.h"
12 #include "platform/v8_inspector/V8StackTraceImpl.h"
13 #include "platform/v8_inspector/V8StringUtil.h"
14 #include "platform/v8_inspector/public/ConsoleAPITypes.h"
15 #include "platform/v8_inspector/public/ConsoleTypes.h"
16 #include "platform/v8_inspector/public/V8DebuggerClient.h"
17
18 namespace blink {
19
20 namespace {
21
22 v8::Local<v8::Private> inspectedContextPrivateKey(v8::Isolate* isolate)
23 {
24 return v8::Private::ForApi(isolate, toV8StringInternalized(isolate, "V8Conso le#InspectedContext"));
25 }
26
27 class ConsoleHelper {
28 PROTOCOL_DISALLOW_COPY(ConsoleHelper);
29 public:
30 ConsoleHelper(const v8::FunctionCallbackInfo<v8::Value>& info)
31 : m_info(info)
32 , m_isolate(info.GetIsolate())
33 , m_context(info.GetIsolate()->GetCurrentContext())
34 , m_inspectedContext(nullptr)
35 , m_debuggerClient(nullptr)
36 {
37 }
38
39 v8::Local<v8::Object> ensureConsole()
40 {
41 if (m_console.IsEmpty()) {
42 ASSERT(!m_info.Data().IsEmpty());
43 ASSERT(!m_info.Data()->IsUndefined());
44 m_console = m_info.Data().As<v8::Object>();
45 }
46 return m_console;
47 }
48
49 InspectedContext* ensureInspectedContext()
50 {
51 if (m_inspectedContext)
52 return m_inspectedContext;
53 v8::Local<v8::Object> console = ensureConsole();
54
55 v8::Local<v8::Private> key = inspectedContextPrivateKey(m_isolate);
56 v8::Local<v8::Value> inspectedContextValue;
57 if (!console->GetPrivate(m_context, key).ToLocal(&inspectedContextValue) )
58 return nullptr;
59 ASSERT(inspectedContextValue->IsExternal());
60 m_inspectedContext = static_cast<InspectedContext*>(inspectedContextValu e.As<v8::External>()->Value());
61 return m_inspectedContext;
62 }
63
64 V8DebuggerClient* ensureDebuggerClient()
65 {
66 if (m_debuggerClient)
67 return m_debuggerClient;
68 InspectedContext* inspectedContext = ensureInspectedContext();
69 if (!inspectedContext)
70 return nullptr;
71 m_debuggerClient = inspectedContext->debugger()->client();
72 return m_debuggerClient;
73 }
74
75 void addMessage(MessageType type, MessageLevel level, bool allowEmptyArgumen ts, int skipArgumentCount)
76 {
77 if (!allowEmptyArguments && !m_info.Length())
78 return;
79 if (V8DebuggerClient* debuggerClient = ensureDebuggerClient())
80 debuggerClient->reportMessageToConsole(m_context, type, level, Strin g16(), &m_info, skipArgumentCount, -1);
81 }
82
83 void addMessage(MessageType type, MessageLevel level, const String16& messag e)
84 {
85 if (V8DebuggerClient* debuggerClient = ensureDebuggerClient())
86 debuggerClient->reportMessageToConsole(m_context, type, level, messa ge, nullptr, 0 /* skipArgumentsCount */, 1 /* maxStackSize */);
87 }
88
89 void addDeprecationMessage(const char* id, const String16& message)
90 {
91 if (checkAndSetPrivateFlagOnConsole(id, false))
92 return;
93 if (V8DebuggerClient* debuggerClient = ensureDebuggerClient())
94 debuggerClient->reportMessageToConsole(m_context, LogMessageType, Wa rningMessageLevel, message, nullptr, 0 /* skipArgumentsCount */, 0 /* maxStackSi ze */);
95 }
96
97 bool firstArgToBoolean(bool defaultValue)
98 {
99 if (m_info.Length() < 1)
100 return defaultValue;
101 if (m_info[0]->IsBoolean())
102 return m_info[0].As<v8::Boolean>()->Value();
103 return m_info[0]->BooleanValue(m_context).FromMaybe(defaultValue);
104 }
105
106 String16 firstArgToString(const String16& defaultValue)
107 {
108 if (m_info.Length() < 1)
109 return defaultValue;
110 v8::Local<v8::String> titleValue;
111 if (m_info[0]->IsObject()) {
112 if (!m_info[0].As<v8::Object>()->ObjectProtoToString(m_context).ToLo cal(&titleValue))
113 return defaultValue;
114 } else {
115 if (!m_info[0]->ToString(m_context).ToLocal(&titleValue))
116 return defaultValue;
117 }
118 return toProtocolString(titleValue);
119 }
120
121 v8::MaybeLocal<v8::Map> privateMap(const char* name)
122 {
123 v8::Local<v8::Object> console = ensureConsole();
124 v8::Local<v8::Private> privateKey = v8::Private::ForApi(m_isolate, toV8S tringInternalized(m_isolate, name));
125 v8::Local<v8::Value> mapValue;
126 if (!console->GetPrivate(m_context, privateKey).ToLocal(&mapValue))
127 return v8::MaybeLocal<v8::Map>();
128 if (mapValue->IsUndefined()) {
129 v8::Local<v8::Map> map = v8::Map::New(m_isolate);
130 if (!console->SetPrivate(m_context, privateKey, map).FromMaybe(false ))
131 return v8::MaybeLocal<v8::Map>();
132 return map;
133 }
134 return mapValue->IsMap() ? mapValue.As<v8::Map>() : v8::MaybeLocal<v8::M ap>();
135 }
136
137 int64_t getIntFromMap(v8::Local<v8::Map> map, const String16& key, int64_t d efaultValue)
138 {
139 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
140 if (!map->Has(m_context, v8Key).FromMaybe(false))
141 return defaultValue;
142 v8::Local<v8::Value> intValue;
143 if (!map->Get(m_context, v8Key).ToLocal(&intValue))
144 return defaultValue;
145 return intValue.As<v8::Integer>()->Value();
146 }
147
148 void setIntOnMap(v8::Local<v8::Map> map, const String16& key, int64_t value)
149 {
150 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
151 if (!map->Set(m_context, v8Key, v8::Integer::New(m_isolate, value)).ToLo cal(&map))
152 return;
153 }
154
155 double getDoubleFromMap(v8::Local<v8::Map> map, const String16& key, double defaultValue)
156 {
157 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
158 if (!map->Has(m_context, v8Key).FromMaybe(false))
159 return defaultValue;
160 v8::Local<v8::Value> intValue;
161 if (!map->Get(m_context, v8Key).ToLocal(&intValue))
162 return defaultValue;
163 return intValue.As<v8::Number>()->Value();
164 }
165
166 void setDoubleOnMap(v8::Local<v8::Map> map, const String16& key, double valu e)
167 {
168 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
169 if (!map->Set(m_context, v8Key, v8::Number::New(m_isolate, value)).ToLoc al(&map))
170 return;
171 }
172
173 V8ProfilerAgentImpl* profilerAgent()
174 {
175 InspectedContext* inspectedContext = ensureInspectedContext();
176 if (!inspectedContext)
177 return nullptr;
178 V8InspectorSessionImpl* session = inspectedContext->debugger()->sessionF orContextGroup(inspectedContext->contextGroupId());
179 if (session && session->profilerAgentImpl()->enabled())
180 return session->profilerAgentImpl();
181 return nullptr;
182 }
183 private:
184 const v8::FunctionCallbackInfo<v8::Value>& m_info;
185 v8::Isolate* m_isolate;
186 v8::Local<v8::Context> m_context;
187 v8::Local<v8::Object> m_console;
188 InspectedContext* m_inspectedContext;
189 V8DebuggerClient* m_debuggerClient;
190
191 bool checkAndSetPrivateFlagOnConsole(const char* name, bool defaultValue)
192 {
193 v8::Local<v8::Object> console = ensureConsole();
194 v8::Local<v8::Private> key = v8::Private::ForApi(m_isolate, toV8StringIn ternalized(m_isolate, name));
195 v8::Local<v8::Value> flagValue;
196 if (!console->GetPrivate(m_context, key).ToLocal(&flagValue))
197 return defaultValue;
198 ASSERT(flagValue->IsUndefined() || flagValue->IsBoolean());
199 if (flagValue->IsBoolean()) {
200 ASSERT(flagValue.As<v8::Boolean>()->Value());
201 return true;
202 }
203 if (!console->SetPrivate(m_context, key, v8::True(m_isolate)).FromMaybe( false))
204 return defaultValue;
205 return false;
206 }
207 };
208
209 v8::MaybeLocal<v8::Object> createObjectWithClassName(V8DebuggerImpl* debugger, v 8::Local<v8::Context> context, const char* className)
210 {
211 v8::Isolate* isolate = debugger->isolate();
212 v8::Local<v8::FunctionTemplate> functionTemplate;
213 String16 functionTemplateName = String16("V8Console#") + className;
214 if (!debugger->functionTemplate(functionTemplateName).ToLocal(&functionTempl ate)) {
215 functionTemplate = v8::FunctionTemplate::New(isolate);
216 functionTemplate->SetClassName(toV8StringInternalized(isolate, className ));
217 debugger->setFunctionTemplate(functionTemplateName, functionTemplate);
218 }
219 v8::Local<v8::Function> constructor;
220 if (!functionTemplate->GetFunction(context).ToLocal(&constructor))
221 return v8::MaybeLocal<v8::Object>();
222 return constructor->NewInstance(context, 0, nullptr);
223 }
224
225 void createBoundFunctionProperty(v8::Local<v8::Context> context, v8::Local<v8::O bject> obj, v8::Local<v8::Object> prototype, const char* name, v8::FunctionCallb ack callback)
226 {
227 v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate( ), name);
228 v8::Local<v8::Function> func;
229 if (!v8::Function::New(context, callback, obj).ToLocal(&func))
230 return;
231 func->SetName(funcName);
232 if (!prototype->Set(context, funcName, func).FromMaybe(false))
233 return;
234 }
235
236 } // namespace
237
238 void V8Console::debugCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
239 {
240 ConsoleHelper(info).addMessage(LogMessageType, DebugMessageLevel, false, 0);
241 }
242
243 void V8Console::errorCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
244 {
245 ConsoleHelper(info).addMessage(LogMessageType, ErrorMessageLevel, false, 0);
246 }
247
248 void V8Console::infoCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
249 {
250 ConsoleHelper(info).addMessage(LogMessageType, InfoMessageLevel, false, 0);
251 }
252
253 void V8Console::logCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
254 {
255 ConsoleHelper(info).addMessage(LogMessageType, LogMessageLevel, false, 0);
256 }
257
258 void V8Console::warnCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
259 {
260 ConsoleHelper(info).addMessage(LogMessageType, WarningMessageLevel, false, 0 );
261 }
262
263 void V8Console::dirCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
264 {
265 ConsoleHelper(info).addMessage(DirMessageType, LogMessageLevel, false, 0);
266 }
267
268 void V8Console::dirxmlCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
269 {
270 ConsoleHelper(info).addMessage(DirXMLMessageType, LogMessageLevel, false, 0) ;
271 }
272
273 void V8Console::tableCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
274 {
275 ConsoleHelper(info).addMessage(TableMessageType, LogMessageLevel, false, 0);
276 }
277
278 void V8Console::traceCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
279 {
280 ConsoleHelper(info).addMessage(TraceMessageType, LogMessageLevel, true, 0);
281 }
282
283 void V8Console::groupCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
284 {
285 ConsoleHelper(info).addMessage(StartGroupMessageType, LogMessageLevel, true, 0);
286 }
287
288 void V8Console::groupCollapsedCallback(const v8::FunctionCallbackInfo<v8::Value> & info)
289 {
290 ConsoleHelper(info).addMessage(StartGroupCollapsedMessageType, LogMessageLev el, true, 0);
291 }
292
293 void V8Console::groupEndCallback(const v8::FunctionCallbackInfo<v8::Value>& info )
294 {
295 ConsoleHelper(info).addMessage(EndGroupMessageType, LogMessageLevel, true, 0 );
296 }
297
298 void V8Console::clearCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
299 {
300 ConsoleHelper(info).addMessage(ClearMessageType, LogMessageLevel, true, 0);
301 }
302
303 void V8Console::countCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
304 {
305 ConsoleHelper helper(info);
306
307 String16 title = helper.firstArgToString(String16());
308 String16 identifier;
309 if (title.isEmpty()) {
310 OwnPtr<V8StackTraceImpl> stackTrace = V8StackTraceImpl::capture(nullptr, 1);
311 if (stackTrace)
312 identifier = stackTrace->topSourceURL() + ":" + String16::number(sta ckTrace->topLineNumber());
313 } else {
314 identifier = title + "@";
315 }
316
317 v8::Local<v8::Map> countMap;
318 if (!helper.privateMap("V8Console#countMap").ToLocal(&countMap))
319 return;
320 int64_t count = helper.getIntFromMap(countMap, identifier, 0) + 1;
321 helper.setIntOnMap(countMap, identifier, count);
322 helper.addMessage(CountMessageType, DebugMessageLevel, title + ": " + String 16::number(count));
323 }
324
325 void V8Console::assertCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
326 {
327 ConsoleHelper helper(info);
328 if (helper.firstArgToBoolean(false))
329 return;
330 helper.addMessage(AssertMessageType, ErrorMessageLevel, true, 1);
331 }
332
333 void V8Console::markTimelineCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
334 {
335 ConsoleHelper(info).addDeprecationMessage("V8Console#markTimelineDeprecated" , "'console.markTimeline' is deprecated. Please use 'console.timeStamp' instead. ");
336 timeStampCallback(info);
337 }
338
339 void V8Console::profileCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
340 {
341 ConsoleHelper helper(info);
342 if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
343 profilerAgent->consoleProfile(helper.firstArgToString(String16()));
344 }
345
346 void V8Console::profileEndCallback(const v8::FunctionCallbackInfo<v8::Value>& in fo)
347 {
348 ConsoleHelper helper(info);
349 if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
350 profilerAgent->consoleProfileEnd(helper.firstArgToString(String16()));
351 }
352
353 static void timeFunction(const v8::FunctionCallbackInfo<v8::Value>& info, bool t imelinePrefix)
354 {
355 ConsoleHelper helper(info);
356 if (V8DebuggerClient* client = helper.ensureDebuggerClient()) {
357 String16 protocolTitle = helper.firstArgToString(String16());
358 if (timelinePrefix)
359 protocolTitle = "Timeline '" + protocolTitle + "'";
360 client->consoleTime(protocolTitle);
361
362 if (info.Length() < 1)
363 return;
364 v8::Local<v8::Map> timeMap;
365 if (!helper.privateMap("V8Console#timeMap").ToLocal(&timeMap))
366 return;
367 helper.setDoubleOnMap(timeMap, protocolTitle, client->currentTimeMS());
368 }
369 }
370
371 static void timeEndFunction(const v8::FunctionCallbackInfo<v8::Value>& info, boo l timelinePrefix)
372 {
373 ConsoleHelper helper(info);
374 if (V8DebuggerClient* client = helper.ensureDebuggerClient()) {
375 String16 protocolTitle = helper.firstArgToString(String16());
376 if (timelinePrefix)
377 protocolTitle = "Timeline '" + protocolTitle + "'";
378 client->consoleTimeEnd(protocolTitle);
379
380 if (info.Length() < 1)
381 return;
382 v8::Local<v8::Map> timeMap;
383 if (!helper.privateMap("V8Console#timeMap").ToLocal(&timeMap))
384 return;
385 double elapsed = client->currentTimeMS() - helper.getDoubleFromMap(timeM ap, protocolTitle, 0.0);
386 String16 message = protocolTitle + ": " + String16::fromDoubleFixedPreci sion(elapsed, 3) + "ms";
387 helper.addMessage(TimeEndMessageType, DebugMessageLevel, message);
388 }
389 }
390
391 void V8Console::timelineCallback(const v8::FunctionCallbackInfo<v8::Value>& info )
392 {
393 ConsoleHelper(info).addDeprecationMessage("V8Console#timeline", "'console.ti meline' is deprecated. Please use 'console.time' instead.");
394 timeFunction(info, true);
395 }
396
397 void V8Console::timelineEndCallback(const v8::FunctionCallbackInfo<v8::Value>& i nfo)
398 {
399 ConsoleHelper(info).addDeprecationMessage("V8Console#timelineEnd", "'console .timelineEnd' is deprecated. Please use 'console.timeEnd' instead.");
400 timeEndFunction(info, true);
401 }
402
403 void V8Console::timeCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
404 {
405 timeFunction(info, false);
406 }
407
408 void V8Console::timeEndCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
409 {
410 timeEndFunction(info, false);
411 }
412
413 void V8Console::timeStampCallback(const v8::FunctionCallbackInfo<v8::Value>& inf o)
414 {
415 ConsoleHelper helper(info);
416 if (V8DebuggerClient* client = helper.ensureDebuggerClient())
417 client->consoleTimeStamp(helper.firstArgToString(String16()));
418 }
419
420 void V8Console::memoryGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
421 {
422 if (V8DebuggerClient* client = ConsoleHelper(info).ensureDebuggerClient()) {
423 v8::Local<v8::Value> memoryValue;
424 if (!client->memoryInfo(info.GetIsolate(), info.GetIsolate()->GetCurrent Context(), info.Holder()).ToLocal(&memoryValue))
425 return;
426 info.GetReturnValue().Set(memoryValue);
427 }
428 }
429
430 void V8Console::memorySetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
431 {
432 // We can't make the attribute readonly as it breaks existing code that reli es on being able to assign to console.memory in strict mode. Instead, the setter just ignores the passed value. http://crbug.com/468611
433 }
434
435 v8::MaybeLocal<v8::Object> V8Console::create(v8::Local<v8::Context> context, Ins pectedContext* inspectedContext, bool hasMemoryAttribute)
436 {
437 v8::Isolate* isolate = context->GetIsolate();
438 v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kDoNotRunM icrotasks);
439
440 v8::Local<v8::Object> console;
441 if (!createObjectWithClassName(inspectedContext->debugger(), context, "Conso le").ToLocal(&console))
442 return v8::MaybeLocal<v8::Object>();
443
444 v8::Local<v8::Object> prototype;
445 if (!createObjectWithClassName(inspectedContext->debugger(), context, "Conso lePrototype").ToLocal(&prototype))
446 return v8::MaybeLocal<v8::Object>();
447
448 createBoundFunctionProperty(context, console, prototype, "debug", V8Console: :debugCallback);
449 createBoundFunctionProperty(context, console, prototype, "error", V8Console: :errorCallback);
450 createBoundFunctionProperty(context, console, prototype, "info", V8Console:: infoCallback);
451 createBoundFunctionProperty(context, console, prototype, "log", V8Console::l ogCallback);
452 createBoundFunctionProperty(context, console, prototype, "warn", V8Console:: warnCallback);
453 createBoundFunctionProperty(context, console, prototype, "dir", V8Console::d irCallback);
454 createBoundFunctionProperty(context, console, prototype, "dirxml", V8Console ::dirxmlCallback);
455 createBoundFunctionProperty(context, console, prototype, "table", V8Console: :tableCallback);
456 createBoundFunctionProperty(context, console, prototype, "trace", V8Console: :traceCallback);
457 createBoundFunctionProperty(context, console, prototype, "group", V8Console: :groupCallback);
458 createBoundFunctionProperty(context, console, prototype, "groupCollapsed", V 8Console::groupCollapsedCallback);
459 createBoundFunctionProperty(context, console, prototype, "groupEnd", V8Conso le::groupEndCallback);
460 createBoundFunctionProperty(context, console, prototype, "clear", V8Console: :clearCallback);
461 createBoundFunctionProperty(context, console, prototype, "count", V8Console: :countCallback);
462 createBoundFunctionProperty(context, console, prototype, "assert", V8Console ::assertCallback);
463 createBoundFunctionProperty(context, console, prototype, "markTimeline", V8C onsole::markTimelineCallback);
464 createBoundFunctionProperty(context, console, prototype, "profile", V8Consol e::profileCallback);
465 createBoundFunctionProperty(context, console, prototype, "profileEnd", V8Con sole::profileEndCallback);
466 createBoundFunctionProperty(context, console, prototype, "timeline", V8Conso le::timelineCallback);
467 createBoundFunctionProperty(context, console, prototype, "timelineEnd", V8Co nsole::timelineEndCallback);
468 createBoundFunctionProperty(context, console, prototype, "time", V8Console:: timeCallback);
469 createBoundFunctionProperty(context, console, prototype, "timeEnd", V8Consol e::timeEndCallback);
470 createBoundFunctionProperty(context, console, prototype, "timeStamp", V8Cons ole::timeStampCallback);
471
472 if (!console->SetPrototype(context, prototype).FromMaybe(false))
473 return v8::MaybeLocal<v8::Object>();
474
475 if (hasMemoryAttribute)
476 console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(isolate, V8Console::memoryGetterCallback, console), v8::Functi on::New(isolate, V8Console::memorySetterCallback), static_cast<v8::PropertyAttri bute>(v8::None), v8::DEFAULT);
477
478 console->SetPrivate(context, inspectedContextPrivateKey(isolate), v8::Extern al::New(isolate, inspectedContext));
479 return console;
480 }
481
482 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698