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

Side by Side Diff: src/inspector/V8Console.cpp

Issue 2292573002: [inspector] Initial import of v8_inspector. (Closed)
Patch Set: format the code, disable cpplint Created 4 years, 3 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
« no previous file with comments | « src/inspector/V8Console.h ('k') | src/inspector/V8ConsoleAgentImpl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project 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 "src/inspector/V8Console.h"
6
7 #include "src/inspector/InjectedScript.h"
8 #include "src/inspector/InspectedContext.h"
9 #include "src/inspector/StringUtil.h"
10 #include "src/inspector/V8Compat.h"
11 #include "src/inspector/V8ConsoleMessage.h"
12 #include "src/inspector/V8DebuggerAgentImpl.h"
13 #include "src/inspector/V8InspectorImpl.h"
14 #include "src/inspector/V8InspectorSessionImpl.h"
15 #include "src/inspector/V8ProfilerAgentImpl.h"
16 #include "src/inspector/V8RuntimeAgentImpl.h"
17 #include "src/inspector/V8StackTraceImpl.h"
18 #include "src/inspector/V8ValueCopier.h"
19 #include "src/inspector/public/V8InspectorClient.h"
20
21 namespace v8_inspector {
22
23 namespace {
24
25 v8::Local<v8::Private> inspectedContextPrivateKey(v8::Isolate* isolate) {
26 return v8::Private::ForApi(
27 isolate, toV8StringInternalized(isolate, "V8Console#InspectedContext"));
28 }
29
30 class ConsoleHelper {
31 V8_INSPECTOR_DISALLOW_COPY(ConsoleHelper);
32
33 public:
34 ConsoleHelper(const v8::FunctionCallbackInfo<v8::Value>& info)
35 : m_info(info),
36 m_isolate(info.GetIsolate()),
37 m_context(info.GetIsolate()->GetCurrentContext()),
38 m_inspectedContext(nullptr),
39 m_inspectorClient(nullptr) {}
40
41 v8::Local<v8::Object> ensureConsole() {
42 if (m_console.IsEmpty()) {
43 DCHECK(!m_info.Data().IsEmpty());
44 DCHECK(!m_info.Data()->IsUndefined());
45 m_console = m_info.Data().As<v8::Object>();
46 }
47 return m_console;
48 }
49
50 InspectedContext* ensureInspectedContext() {
51 if (m_inspectedContext) return m_inspectedContext;
52 v8::Local<v8::Object> console = ensureConsole();
53
54 v8::Local<v8::Private> key = inspectedContextPrivateKey(m_isolate);
55 v8::Local<v8::Value> inspectedContextValue;
56 if (!console->GetPrivate(m_context, key).ToLocal(&inspectedContextValue))
57 return nullptr;
58 DCHECK(inspectedContextValue->IsExternal());
59 m_inspectedContext = static_cast<InspectedContext*>(
60 inspectedContextValue.As<v8::External>()->Value());
61 return m_inspectedContext;
62 }
63
64 V8InspectorClient* ensureDebuggerClient() {
65 if (m_inspectorClient) return m_inspectorClient;
66 InspectedContext* inspectedContext = ensureInspectedContext();
67 if (!inspectedContext) return nullptr;
68 m_inspectorClient = inspectedContext->inspector()->client();
69 return m_inspectorClient;
70 }
71
72 void reportCall(ConsoleAPIType type) {
73 if (!m_info.Length()) return;
74 std::vector<v8::Local<v8::Value>> arguments;
75 for (int i = 0; i < m_info.Length(); ++i) arguments.push_back(m_info[i]);
76 reportCall(type, arguments);
77 }
78
79 void reportCallWithDefaultArgument(ConsoleAPIType type,
80 const String16& message) {
81 std::vector<v8::Local<v8::Value>> arguments;
82 for (int i = 0; i < m_info.Length(); ++i) arguments.push_back(m_info[i]);
83 if (!m_info.Length()) arguments.push_back(toV8String(m_isolate, message));
84 reportCall(type, arguments);
85 }
86
87 void reportCallWithArgument(ConsoleAPIType type, const String16& message) {
88 std::vector<v8::Local<v8::Value>> arguments(1,
89 toV8String(m_isolate, message));
90 reportCall(type, arguments);
91 }
92
93 void reportCall(ConsoleAPIType type,
94 const std::vector<v8::Local<v8::Value>>& arguments) {
95 InspectedContext* inspectedContext = ensureInspectedContext();
96 if (!inspectedContext) return;
97 V8InspectorImpl* inspector = inspectedContext->inspector();
98 std::unique_ptr<V8ConsoleMessage> message =
99 V8ConsoleMessage::createForConsoleAPI(
100 inspector->client()->currentTimeMS(), type, arguments,
101 inspector->debugger()->captureStackTrace(false), inspectedContext);
102 inspector->ensureConsoleMessageStorage(inspectedContext->contextGroupId())
103 ->addMessage(std::move(message));
104 }
105
106 void reportDeprecatedCall(const char* id, const String16& message) {
107 if (checkAndSetPrivateFlagOnConsole(id, false)) return;
108 std::vector<v8::Local<v8::Value>> arguments(1,
109 toV8String(m_isolate, message));
110 reportCall(ConsoleAPIType::kWarning, arguments);
111 }
112
113 bool firstArgToBoolean(bool defaultValue) {
114 if (m_info.Length() < 1) return defaultValue;
115 if (m_info[0]->IsBoolean()) return m_info[0].As<v8::Boolean>()->Value();
116 return m_info[0]->BooleanValue(m_context).FromMaybe(defaultValue);
117 }
118
119 String16 firstArgToString(const String16& defaultValue) {
120 if (m_info.Length() < 1) return defaultValue;
121 v8::Local<v8::String> titleValue;
122 if (m_info[0]->IsObject()) {
123 if (!m_info[0].As<v8::Object>()->ObjectProtoToString(m_context).ToLocal(
124 &titleValue))
125 return defaultValue;
126 } else {
127 if (!m_info[0]->ToString(m_context).ToLocal(&titleValue))
128 return defaultValue;
129 }
130 return toProtocolString(titleValue);
131 }
132
133 v8::MaybeLocal<v8::Object> firstArgAsObject() {
134 if (m_info.Length() < 1 || !m_info[0]->IsObject())
135 return v8::MaybeLocal<v8::Object>();
136 return m_info[0].As<v8::Object>();
137 }
138
139 v8::MaybeLocal<v8::Function> firstArgAsFunction() {
140 if (m_info.Length() < 1 || !m_info[0]->IsFunction())
141 return v8::MaybeLocal<v8::Function>();
142 return m_info[0].As<v8::Function>();
143 }
144
145 v8::MaybeLocal<v8::Map> privateMap(const char* name) {
146 v8::Local<v8::Object> console = ensureConsole();
147 v8::Local<v8::Private> privateKey =
148 v8::Private::ForApi(m_isolate, toV8StringInternalized(m_isolate, name));
149 v8::Local<v8::Value> mapValue;
150 if (!console->GetPrivate(m_context, privateKey).ToLocal(&mapValue))
151 return v8::MaybeLocal<v8::Map>();
152 if (mapValue->IsUndefined()) {
153 v8::Local<v8::Map> map = v8::Map::New(m_isolate);
154 if (!console->SetPrivate(m_context, privateKey, map).FromMaybe(false))
155 return v8::MaybeLocal<v8::Map>();
156 return map;
157 }
158 return mapValue->IsMap() ? mapValue.As<v8::Map>()
159 : v8::MaybeLocal<v8::Map>();
160 }
161
162 int64_t getIntFromMap(v8::Local<v8::Map> map, const String16& key,
163 int64_t defaultValue) {
164 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
165 if (!map->Has(m_context, v8Key).FromMaybe(false)) return defaultValue;
166 v8::Local<v8::Value> intValue;
167 if (!map->Get(m_context, v8Key).ToLocal(&intValue)) return defaultValue;
168 return intValue.As<v8::Integer>()->Value();
169 }
170
171 void setIntOnMap(v8::Local<v8::Map> map, const String16& key, int64_t value) {
172 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
173 if (!map->Set(m_context, v8Key, v8::Integer::New(m_isolate, value))
174 .ToLocal(&map))
175 return;
176 }
177
178 double getDoubleFromMap(v8::Local<v8::Map> map, const String16& key,
179 double defaultValue) {
180 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
181 if (!map->Has(m_context, v8Key).FromMaybe(false)) return defaultValue;
182 v8::Local<v8::Value> intValue;
183 if (!map->Get(m_context, v8Key).ToLocal(&intValue)) return defaultValue;
184 return intValue.As<v8::Number>()->Value();
185 }
186
187 void setDoubleOnMap(v8::Local<v8::Map> map, const String16& key,
188 double value) {
189 v8::Local<v8::String> v8Key = toV8String(m_isolate, key);
190 if (!map->Set(m_context, v8Key, v8::Number::New(m_isolate, value))
191 .ToLocal(&map))
192 return;
193 }
194
195 V8ProfilerAgentImpl* profilerAgent() {
196 if (V8InspectorSessionImpl* session = currentSession()) {
197 if (session && session->profilerAgent()->enabled())
198 return session->profilerAgent();
199 }
200 return nullptr;
201 }
202
203 V8DebuggerAgentImpl* debuggerAgent() {
204 if (V8InspectorSessionImpl* session = currentSession()) {
205 if (session && session->debuggerAgent()->enabled())
206 return session->debuggerAgent();
207 }
208 return nullptr;
209 }
210
211 V8InspectorSessionImpl* currentSession() {
212 InspectedContext* inspectedContext = ensureInspectedContext();
213 if (!inspectedContext) return nullptr;
214 return inspectedContext->inspector()->sessionForContextGroup(
215 inspectedContext->contextGroupId());
216 }
217
218 private:
219 const v8::FunctionCallbackInfo<v8::Value>& m_info;
220 v8::Isolate* m_isolate;
221 v8::Local<v8::Context> m_context;
222 v8::Local<v8::Object> m_console;
223 InspectedContext* m_inspectedContext;
224 V8InspectorClient* m_inspectorClient;
225
226 bool checkAndSetPrivateFlagOnConsole(const char* name, bool defaultValue) {
227 v8::Local<v8::Object> console = ensureConsole();
228 v8::Local<v8::Private> key =
229 v8::Private::ForApi(m_isolate, toV8StringInternalized(m_isolate, name));
230 v8::Local<v8::Value> flagValue;
231 if (!console->GetPrivate(m_context, key).ToLocal(&flagValue))
232 return defaultValue;
233 DCHECK(flagValue->IsUndefined() || flagValue->IsBoolean());
234 if (flagValue->IsBoolean()) {
235 DCHECK(flagValue.As<v8::Boolean>()->Value());
236 return true;
237 }
238 if (!console->SetPrivate(m_context, key, v8::True(m_isolate))
239 .FromMaybe(false))
240 return defaultValue;
241 return false;
242 }
243 };
244
245 void returnDataCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
246 info.GetReturnValue().Set(info.Data());
247 }
248
249 void createBoundFunctionProperty(v8::Local<v8::Context> context,
250 v8::Local<v8::Object> console,
251 const char* name,
252 v8::FunctionCallback callback,
253 const char* description = nullptr) {
254 v8::Local<v8::String> funcName =
255 toV8StringInternalized(context->GetIsolate(), name);
256 v8::Local<v8::Function> func;
257 if (!V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, callback, console, 0)
258 .ToLocal(&func))
259 return;
260 func->SetName(funcName);
261 if (description) {
262 v8::Local<v8::String> returnValue =
263 toV8String(context->GetIsolate(), description);
264 v8::Local<v8::Function> toStringFunction;
265 if (V8_FUNCTION_NEW_REMOVE_PROTOTYPE(context, returnDataCallback,
266 returnValue, 0)
267 .ToLocal(&toStringFunction))
268 createDataProperty(context, func, toV8StringInternalized(
269 context->GetIsolate(), "toString"),
270 toStringFunction);
271 }
272 createDataProperty(context, console, funcName, func);
273 }
274
275 } // namespace
276
277 void V8Console::debugCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
278 ConsoleHelper(info).reportCall(ConsoleAPIType::kDebug);
279 }
280
281 void V8Console::errorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
282 ConsoleHelper(info).reportCall(ConsoleAPIType::kError);
283 }
284
285 void V8Console::infoCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
286 ConsoleHelper(info).reportCall(ConsoleAPIType::kInfo);
287 }
288
289 void V8Console::logCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
290 ConsoleHelper(info).reportCall(ConsoleAPIType::kLog);
291 }
292
293 void V8Console::warnCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
294 ConsoleHelper(info).reportCall(ConsoleAPIType::kWarning);
295 }
296
297 void V8Console::dirCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
298 ConsoleHelper(info).reportCall(ConsoleAPIType::kDir);
299 }
300
301 void V8Console::dirxmlCallback(
302 const v8::FunctionCallbackInfo<v8::Value>& info) {
303 ConsoleHelper(info).reportCall(ConsoleAPIType::kDirXML);
304 }
305
306 void V8Console::tableCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
307 ConsoleHelper(info).reportCall(ConsoleAPIType::kTable);
308 }
309
310 void V8Console::traceCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
311 ConsoleHelper(info).reportCallWithDefaultArgument(ConsoleAPIType::kTrace,
312 String16("console.trace"));
313 }
314
315 void V8Console::groupCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
316 ConsoleHelper(info).reportCallWithDefaultArgument(ConsoleAPIType::kStartGroup,
317 String16("console.group"));
318 }
319
320 void V8Console::groupCollapsedCallback(
321 const v8::FunctionCallbackInfo<v8::Value>& info) {
322 ConsoleHelper(info).reportCallWithDefaultArgument(
323 ConsoleAPIType::kStartGroupCollapsed, String16("console.groupCollapsed"));
324 }
325
326 void V8Console::groupEndCallback(
327 const v8::FunctionCallbackInfo<v8::Value>& info) {
328 ConsoleHelper(info).reportCallWithDefaultArgument(
329 ConsoleAPIType::kEndGroup, String16("console.groupEnd"));
330 }
331
332 void V8Console::clearCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
333 ConsoleHelper(info).reportCallWithDefaultArgument(ConsoleAPIType::kClear,
334 String16("console.clear"));
335 }
336
337 void V8Console::countCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
338 ConsoleHelper helper(info);
339
340 String16 title = helper.firstArgToString(String16());
341 String16 identifier;
342 if (title.isEmpty()) {
343 std::unique_ptr<V8StackTraceImpl> stackTrace =
344 V8StackTraceImpl::capture(nullptr, 0, 1);
345 if (stackTrace)
346 identifier = toString16(stackTrace->topSourceURL()) + ":" +
347 String16::fromInteger(stackTrace->topLineNumber());
348 } else {
349 identifier = title + "@";
350 }
351
352 v8::Local<v8::Map> countMap;
353 if (!helper.privateMap("V8Console#countMap").ToLocal(&countMap)) return;
354 int64_t count = helper.getIntFromMap(countMap, identifier, 0) + 1;
355 helper.setIntOnMap(countMap, identifier, count);
356 helper.reportCallWithArgument(ConsoleAPIType::kCount,
357 title + ": " + String16::fromInteger(count));
358 }
359
360 void V8Console::assertCallback(
361 const v8::FunctionCallbackInfo<v8::Value>& info) {
362 ConsoleHelper helper(info);
363 if (helper.firstArgToBoolean(false)) return;
364
365 std::vector<v8::Local<v8::Value>> arguments;
366 for (int i = 1; i < info.Length(); ++i) arguments.push_back(info[i]);
367 if (info.Length() < 2)
368 arguments.push_back(
369 toV8String(info.GetIsolate(), String16("console.assert")));
370 helper.reportCall(ConsoleAPIType::kAssert, arguments);
371
372 if (V8DebuggerAgentImpl* debuggerAgent = helper.debuggerAgent())
373 debuggerAgent->breakProgramOnException(
374 protocol::Debugger::Paused::ReasonEnum::Assert, nullptr);
375 }
376
377 void V8Console::markTimelineCallback(
378 const v8::FunctionCallbackInfo<v8::Value>& info) {
379 ConsoleHelper(info).reportDeprecatedCall("V8Console#markTimelineDeprecated",
380 "'console.markTimeline' is "
381 "deprecated. Please use "
382 "'console.timeStamp' instead.");
383 timeStampCallback(info);
384 }
385
386 void V8Console::profileCallback(
387 const v8::FunctionCallbackInfo<v8::Value>& info) {
388 ConsoleHelper helper(info);
389 if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
390 profilerAgent->consoleProfile(helper.firstArgToString(String16()));
391 }
392
393 void V8Console::profileEndCallback(
394 const v8::FunctionCallbackInfo<v8::Value>& info) {
395 ConsoleHelper helper(info);
396 if (V8ProfilerAgentImpl* profilerAgent = helper.profilerAgent())
397 profilerAgent->consoleProfileEnd(helper.firstArgToString(String16()));
398 }
399
400 static void timeFunction(const v8::FunctionCallbackInfo<v8::Value>& info,
401 bool timelinePrefix) {
402 ConsoleHelper helper(info);
403 if (V8InspectorClient* client = helper.ensureDebuggerClient()) {
404 String16 protocolTitle = helper.firstArgToString("default");
405 if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'";
406 client->consoleTime(toStringView(protocolTitle));
407
408 v8::Local<v8::Map> timeMap;
409 if (!helper.privateMap("V8Console#timeMap").ToLocal(&timeMap)) return;
410 helper.setDoubleOnMap(timeMap, protocolTitle, client->currentTimeMS());
411 }
412 }
413
414 static void timeEndFunction(const v8::FunctionCallbackInfo<v8::Value>& info,
415 bool timelinePrefix) {
416 ConsoleHelper helper(info);
417 if (V8InspectorClient* client = helper.ensureDebuggerClient()) {
418 String16 protocolTitle = helper.firstArgToString("default");
419 if (timelinePrefix) protocolTitle = "Timeline '" + protocolTitle + "'";
420 client->consoleTimeEnd(toStringView(protocolTitle));
421
422 v8::Local<v8::Map> timeMap;
423 if (!helper.privateMap("V8Console#timeMap").ToLocal(&timeMap)) return;
424 double elapsed = client->currentTimeMS() -
425 helper.getDoubleFromMap(timeMap, protocolTitle, 0.0);
426 String16 message =
427 protocolTitle + ": " + String16::fromDoublePrecision3(elapsed) + "ms";
428 helper.reportCallWithArgument(ConsoleAPIType::kTimeEnd, message);
429 }
430 }
431
432 void V8Console::timelineCallback(
433 const v8::FunctionCallbackInfo<v8::Value>& info) {
434 ConsoleHelper(info).reportDeprecatedCall(
435 "V8Console#timeline",
436 "'console.timeline' is deprecated. Please use 'console.time' instead.");
437 timeFunction(info, true);
438 }
439
440 void V8Console::timelineEndCallback(
441 const v8::FunctionCallbackInfo<v8::Value>& info) {
442 ConsoleHelper(info).reportDeprecatedCall("V8Console#timelineEnd",
443 "'console.timelineEnd' is "
444 "deprecated. Please use "
445 "'console.timeEnd' instead.");
446 timeEndFunction(info, true);
447 }
448
449 void V8Console::timeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
450 timeFunction(info, false);
451 }
452
453 void V8Console::timeEndCallback(
454 const v8::FunctionCallbackInfo<v8::Value>& info) {
455 timeEndFunction(info, false);
456 }
457
458 void V8Console::timeStampCallback(
459 const v8::FunctionCallbackInfo<v8::Value>& info) {
460 ConsoleHelper helper(info);
461 if (V8InspectorClient* client = helper.ensureDebuggerClient()) {
462 String16 title = helper.firstArgToString(String16());
463 client->consoleTimeStamp(toStringView(title));
464 }
465 }
466
467 void V8Console::memoryGetterCallback(
468 const v8::FunctionCallbackInfo<v8::Value>& info) {
469 if (V8InspectorClient* client = ConsoleHelper(info).ensureDebuggerClient()) {
470 v8::Local<v8::Value> memoryValue;
471 if (!client
472 ->memoryInfo(info.GetIsolate(),
473 info.GetIsolate()->GetCurrentContext())
474 .ToLocal(&memoryValue))
475 return;
476 info.GetReturnValue().Set(memoryValue);
477 }
478 }
479
480 void V8Console::memorySetterCallback(
481 const v8::FunctionCallbackInfo<v8::Value>& info) {
482 // We can't make the attribute readonly as it breaks existing code that relies
483 // on being able to assign to console.memory in strict mode. Instead, the
484 // setter just ignores the passed value. http://crbug.com/468611
485 }
486
487 void V8Console::keysCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
488 v8::Isolate* isolate = info.GetIsolate();
489 info.GetReturnValue().Set(v8::Array::New(isolate));
490
491 ConsoleHelper helper(info);
492 v8::Local<v8::Object> obj;
493 if (!helper.firstArgAsObject().ToLocal(&obj)) return;
494 v8::Local<v8::Array> names;
495 if (!obj->GetOwnPropertyNames(isolate->GetCurrentContext()).ToLocal(&names))
496 return;
497 info.GetReturnValue().Set(names);
498 }
499
500 void V8Console::valuesCallback(
501 const v8::FunctionCallbackInfo<v8::Value>& info) {
502 v8::Isolate* isolate = info.GetIsolate();
503 info.GetReturnValue().Set(v8::Array::New(isolate));
504
505 ConsoleHelper helper(info);
506 v8::Local<v8::Object> obj;
507 if (!helper.firstArgAsObject().ToLocal(&obj)) return;
508 v8::Local<v8::Array> names;
509 v8::Local<v8::Context> context = isolate->GetCurrentContext();
510 if (!obj->GetOwnPropertyNames(context).ToLocal(&names)) return;
511 v8::Local<v8::Array> values = v8::Array::New(isolate, names->Length());
512 for (size_t i = 0; i < names->Length(); ++i) {
513 v8::Local<v8::Value> key;
514 if (!names->Get(context, i).ToLocal(&key)) continue;
515 v8::Local<v8::Value> value;
516 if (!obj->Get(context, key).ToLocal(&value)) continue;
517 createDataProperty(context, values, i, value);
518 }
519 info.GetReturnValue().Set(values);
520 }
521
522 static void setFunctionBreakpoint(ConsoleHelper& helper,
523 v8::Local<v8::Function> function,
524 V8DebuggerAgentImpl::BreakpointSource source,
525 const String16& condition, bool enable) {
526 V8DebuggerAgentImpl* debuggerAgent = helper.debuggerAgent();
527 if (!debuggerAgent) return;
528 String16 scriptId = String16::fromInteger(function->ScriptId());
529 int lineNumber = function->GetScriptLineNumber();
530 int columnNumber = function->GetScriptColumnNumber();
531 if (lineNumber == v8::Function::kLineOffsetNotFound ||
532 columnNumber == v8::Function::kLineOffsetNotFound)
533 return;
534 if (enable)
535 debuggerAgent->setBreakpointAt(scriptId, lineNumber, columnNumber, source,
536 condition);
537 else
538 debuggerAgent->removeBreakpointAt(scriptId, lineNumber, columnNumber,
539 source);
540 }
541
542 void V8Console::debugFunctionCallback(
543 const v8::FunctionCallbackInfo<v8::Value>& info) {
544 ConsoleHelper helper(info);
545 v8::Local<v8::Function> function;
546 if (!helper.firstArgAsFunction().ToLocal(&function)) return;
547 setFunctionBreakpoint(helper, function,
548 V8DebuggerAgentImpl::DebugCommandBreakpointSource,
549 String16(), true);
550 }
551
552 void V8Console::undebugFunctionCallback(
553 const v8::FunctionCallbackInfo<v8::Value>& info) {
554 ConsoleHelper helper(info);
555 v8::Local<v8::Function> function;
556 if (!helper.firstArgAsFunction().ToLocal(&function)) return;
557 setFunctionBreakpoint(helper, function,
558 V8DebuggerAgentImpl::DebugCommandBreakpointSource,
559 String16(), false);
560 }
561
562 void V8Console::monitorFunctionCallback(
563 const v8::FunctionCallbackInfo<v8::Value>& info) {
564 ConsoleHelper helper(info);
565 v8::Local<v8::Function> function;
566 if (!helper.firstArgAsFunction().ToLocal(&function)) return;
567 v8::Local<v8::Value> name = function->GetName();
568 if (!name->IsString() || !v8::Local<v8::String>::Cast(name)->Length())
569 name = function->GetInferredName();
570 String16 functionName = toProtocolStringWithTypeCheck(name);
571 String16Builder builder;
572 builder.append("console.log(\"function ");
573 if (functionName.isEmpty())
574 builder.append("(anonymous function)");
575 else
576 builder.append(functionName);
577 builder.append(
578 " called\" + (arguments.length > 0 ? \" with arguments: \" + "
579 "Array.prototype.join.call(arguments, \", \") : \"\")) && false");
580 setFunctionBreakpoint(helper, function,
581 V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
582 builder.toString(), true);
583 }
584
585 void V8Console::unmonitorFunctionCallback(
586 const v8::FunctionCallbackInfo<v8::Value>& info) {
587 ConsoleHelper helper(info);
588 v8::Local<v8::Function> function;
589 if (!helper.firstArgAsFunction().ToLocal(&function)) return;
590 setFunctionBreakpoint(helper, function,
591 V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
592 String16(), false);
593 }
594
595 void V8Console::lastEvaluationResultCallback(
596 const v8::FunctionCallbackInfo<v8::Value>& info) {
597 ConsoleHelper helper(info);
598 InspectedContext* context = helper.ensureInspectedContext();
599 if (!context) return;
600 if (InjectedScript* injectedScript = context->getInjectedScript())
601 info.GetReturnValue().Set(injectedScript->lastEvaluationResult());
602 }
603
604 static void inspectImpl(const v8::FunctionCallbackInfo<v8::Value>& info,
605 bool copyToClipboard) {
606 if (info.Length() < 1) return;
607 if (!copyToClipboard) info.GetReturnValue().Set(info[0]);
608
609 ConsoleHelper helper(info);
610 InspectedContext* context = helper.ensureInspectedContext();
611 if (!context) return;
612 InjectedScript* injectedScript = context->getInjectedScript();
613 if (!injectedScript) return;
614 ErrorString errorString;
615 std::unique_ptr<protocol::Runtime::RemoteObject> wrappedObject =
616 injectedScript->wrapObject(&errorString, info[0], "",
617 false /** forceValueType */,
618 false /** generatePreview */);
619 if (!wrappedObject || !errorString.isEmpty()) return;
620
621 std::unique_ptr<protocol::DictionaryValue> hints =
622 protocol::DictionaryValue::create();
623 if (copyToClipboard) hints->setBoolean("copyToClipboard", true);
624 if (V8InspectorSessionImpl* session = helper.currentSession())
625 session->runtimeAgent()->inspect(std::move(wrappedObject),
626 std::move(hints));
627 }
628
629 void V8Console::inspectCallback(
630 const v8::FunctionCallbackInfo<v8::Value>& info) {
631 inspectImpl(info, false);
632 }
633
634 void V8Console::copyCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
635 inspectImpl(info, true);
636 }
637
638 void V8Console::inspectedObject(const v8::FunctionCallbackInfo<v8::Value>& info,
639 unsigned num) {
640 DCHECK(num < V8InspectorSessionImpl::kInspectedObjectBufferSize);
641 ConsoleHelper helper(info);
642 if (V8InspectorSessionImpl* session = helper.currentSession()) {
643 V8InspectorSession::Inspectable* object = session->inspectedObject(num);
644 v8::Isolate* isolate = info.GetIsolate();
645 if (object)
646 info.GetReturnValue().Set(object->get(isolate->GetCurrentContext()));
647 else
648 info.GetReturnValue().Set(v8::Undefined(isolate));
649 }
650 }
651
652 v8::Local<v8::Object> V8Console::createConsole(
653 InspectedContext* inspectedContext, bool hasMemoryAttribute) {
654 v8::Local<v8::Context> context = inspectedContext->context();
655 v8::Context::Scope contextScope(context);
656 v8::Isolate* isolate = context->GetIsolate();
657 v8::MicrotasksScope microtasksScope(isolate,
658 v8::MicrotasksScope::kDoNotRunMicrotasks);
659
660 v8::Local<v8::Object> console = v8::Object::New(isolate);
661 bool success =
662 console->SetPrototype(context, v8::Object::New(isolate)).FromMaybe(false);
663 DCHECK(success);
664
665 createBoundFunctionProperty(context, console, "debug",
666 V8Console::debugCallback);
667 createBoundFunctionProperty(context, console, "error",
668 V8Console::errorCallback);
669 createBoundFunctionProperty(context, console, "info",
670 V8Console::infoCallback);
671 createBoundFunctionProperty(context, console, "log", V8Console::logCallback);
672 createBoundFunctionProperty(context, console, "warn",
673 V8Console::warnCallback);
674 createBoundFunctionProperty(context, console, "dir", V8Console::dirCallback);
675 createBoundFunctionProperty(context, console, "dirxml",
676 V8Console::dirxmlCallback);
677 createBoundFunctionProperty(context, console, "table",
678 V8Console::tableCallback);
679 createBoundFunctionProperty(context, console, "trace",
680 V8Console::traceCallback);
681 createBoundFunctionProperty(context, console, "group",
682 V8Console::groupCallback);
683 createBoundFunctionProperty(context, console, "groupCollapsed",
684 V8Console::groupCollapsedCallback);
685 createBoundFunctionProperty(context, console, "groupEnd",
686 V8Console::groupEndCallback);
687 createBoundFunctionProperty(context, console, "clear",
688 V8Console::clearCallback);
689 createBoundFunctionProperty(context, console, "count",
690 V8Console::countCallback);
691 createBoundFunctionProperty(context, console, "assert",
692 V8Console::assertCallback);
693 createBoundFunctionProperty(context, console, "markTimeline",
694 V8Console::markTimelineCallback);
695 createBoundFunctionProperty(context, console, "profile",
696 V8Console::profileCallback);
697 createBoundFunctionProperty(context, console, "profileEnd",
698 V8Console::profileEndCallback);
699 createBoundFunctionProperty(context, console, "timeline",
700 V8Console::timelineCallback);
701 createBoundFunctionProperty(context, console, "timelineEnd",
702 V8Console::timelineEndCallback);
703 createBoundFunctionProperty(context, console, "time",
704 V8Console::timeCallback);
705 createBoundFunctionProperty(context, console, "timeEnd",
706 V8Console::timeEndCallback);
707 createBoundFunctionProperty(context, console, "timeStamp",
708 V8Console::timeStampCallback);
709
710 if (hasMemoryAttribute)
711 console->SetAccessorProperty(
712 toV8StringInternalized(isolate, "memory"),
713 V8_FUNCTION_NEW_REMOVE_PROTOTYPE(
714 context, V8Console::memoryGetterCallback, console, 0)
715 .ToLocalChecked(),
716 V8_FUNCTION_NEW_REMOVE_PROTOTYPE(
717 context, V8Console::memorySetterCallback, v8::Local<v8::Value>(), 0)
718 .ToLocalChecked(),
719 static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT);
720
721 console->SetPrivate(context, inspectedContextPrivateKey(isolate),
722 v8::External::New(isolate, inspectedContext));
723 return console;
724 }
725
726 void V8Console::clearInspectedContextIfNeeded(v8::Local<v8::Context> context,
727 v8::Local<v8::Object> console) {
728 v8::Isolate* isolate = context->GetIsolate();
729 console->SetPrivate(context, inspectedContextPrivateKey(isolate),
730 v8::External::New(isolate, nullptr));
731 }
732
733 v8::Local<v8::Object> V8Console::createCommandLineAPI(
734 InspectedContext* inspectedContext) {
735 v8::Local<v8::Context> context = inspectedContext->context();
736 v8::Isolate* isolate = context->GetIsolate();
737 v8::MicrotasksScope microtasksScope(isolate,
738 v8::MicrotasksScope::kDoNotRunMicrotasks);
739
740 v8::Local<v8::Object> commandLineAPI = v8::Object::New(isolate);
741 bool success =
742 commandLineAPI->SetPrototype(context, v8::Null(isolate)).FromMaybe(false);
743 DCHECK(success);
744
745 createBoundFunctionProperty(context, commandLineAPI, "dir",
746 V8Console::dirCallback,
747 "function dir(value) { [Command Line API] }");
748 createBoundFunctionProperty(context, commandLineAPI, "dirxml",
749 V8Console::dirxmlCallback,
750 "function dirxml(value) { [Command Line API] }");
751 createBoundFunctionProperty(context, commandLineAPI, "profile",
752 V8Console::profileCallback,
753 "function profile(title) { [Command Line API] }");
754 createBoundFunctionProperty(
755 context, commandLineAPI, "profileEnd", V8Console::profileEndCallback,
756 "function profileEnd(title) { [Command Line API] }");
757 createBoundFunctionProperty(context, commandLineAPI, "clear",
758 V8Console::clearCallback,
759 "function clear() { [Command Line API] }");
760 createBoundFunctionProperty(
761 context, commandLineAPI, "table", V8Console::tableCallback,
762 "function table(data, [columns]) { [Command Line API] }");
763
764 createBoundFunctionProperty(context, commandLineAPI, "keys",
765 V8Console::keysCallback,
766 "function keys(object) { [Command Line API] }");
767 createBoundFunctionProperty(context, commandLineAPI, "values",
768 V8Console::valuesCallback,
769 "function values(object) { [Command Line API] }");
770 createBoundFunctionProperty(
771 context, commandLineAPI, "debug", V8Console::debugFunctionCallback,
772 "function debug(function) { [Command Line API] }");
773 createBoundFunctionProperty(
774 context, commandLineAPI, "undebug", V8Console::undebugFunctionCallback,
775 "function undebug(function) { [Command Line API] }");
776 createBoundFunctionProperty(
777 context, commandLineAPI, "monitor", V8Console::monitorFunctionCallback,
778 "function monitor(function) { [Command Line API] }");
779 createBoundFunctionProperty(
780 context, commandLineAPI, "unmonitor",
781 V8Console::unmonitorFunctionCallback,
782 "function unmonitor(function) { [Command Line API] }");
783 createBoundFunctionProperty(
784 context, commandLineAPI, "inspect", V8Console::inspectCallback,
785 "function inspect(object) { [Command Line API] }");
786 createBoundFunctionProperty(context, commandLineAPI, "copy",
787 V8Console::copyCallback,
788 "function copy(value) { [Command Line API] }");
789 createBoundFunctionProperty(context, commandLineAPI, "$_",
790 V8Console::lastEvaluationResultCallback);
791 createBoundFunctionProperty(context, commandLineAPI, "$0",
792 V8Console::inspectedObject0);
793 createBoundFunctionProperty(context, commandLineAPI, "$1",
794 V8Console::inspectedObject1);
795 createBoundFunctionProperty(context, commandLineAPI, "$2",
796 V8Console::inspectedObject2);
797 createBoundFunctionProperty(context, commandLineAPI, "$3",
798 V8Console::inspectedObject3);
799 createBoundFunctionProperty(context, commandLineAPI, "$4",
800 V8Console::inspectedObject4);
801
802 inspectedContext->inspector()->client()->installAdditionalCommandLineAPI(
803 context, commandLineAPI);
804
805 commandLineAPI->SetPrivate(context, inspectedContextPrivateKey(isolate),
806 v8::External::New(isolate, inspectedContext));
807 return commandLineAPI;
808 }
809
810 static bool isCommandLineAPIGetter(const String16& name) {
811 if (name.length() != 2) return false;
812 // $0 ... $4, $_
813 return name[0] == '$' &&
814 ((name[1] >= '0' && name[1] <= '4') || name[1] == '_');
815 }
816
817 void V8Console::CommandLineAPIScope::accessorGetterCallback(
818 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
819 CommandLineAPIScope* scope = static_cast<CommandLineAPIScope*>(
820 info.Data().As<v8::External>()->Value());
821 DCHECK(scope);
822
823 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
824 if (scope->m_cleanup) {
825 bool removed = info.Holder()->Delete(context, name).FromMaybe(false);
826 DCHECK(removed);
827 return;
828 }
829 v8::Local<v8::Object> commandLineAPI = scope->m_commandLineAPI;
830
831 v8::Local<v8::Value> value;
832 if (!commandLineAPI->Get(context, name).ToLocal(&value)) return;
833 if (isCommandLineAPIGetter(toProtocolStringWithTypeCheck(name))) {
834 DCHECK(value->IsFunction());
835 v8::MicrotasksScope microtasks(info.GetIsolate(),
836 v8::MicrotasksScope::kDoNotRunMicrotasks);
837 if (value.As<v8::Function>()
838 ->Call(context, commandLineAPI, 0, nullptr)
839 .ToLocal(&value))
840 info.GetReturnValue().Set(value);
841 } else {
842 info.GetReturnValue().Set(value);
843 }
844 }
845
846 void V8Console::CommandLineAPIScope::accessorSetterCallback(
847 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
848 const v8::PropertyCallbackInfo<void>& info) {
849 CommandLineAPIScope* scope = static_cast<CommandLineAPIScope*>(
850 info.Data().As<v8::External>()->Value());
851 v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
852 if (!info.Holder()->Delete(context, name).FromMaybe(false)) return;
853 if (!info.Holder()->CreateDataProperty(context, name, value).FromMaybe(false))
854 return;
855 bool removed =
856 scope->m_installedMethods->Delete(context, name).FromMaybe(false);
857 DCHECK(removed);
858 }
859
860 V8Console::CommandLineAPIScope::CommandLineAPIScope(
861 v8::Local<v8::Context> context, v8::Local<v8::Object> commandLineAPI,
862 v8::Local<v8::Object> global)
863 : m_context(context),
864 m_commandLineAPI(commandLineAPI),
865 m_global(global),
866 m_installedMethods(v8::Set::New(context->GetIsolate())),
867 m_cleanup(false) {
868 v8::Local<v8::Array> names;
869 if (!m_commandLineAPI->GetOwnPropertyNames(context).ToLocal(&names)) return;
870 v8::Local<v8::External> externalThis =
871 v8::External::New(context->GetIsolate(), this);
872 for (size_t i = 0; i < names->Length(); ++i) {
873 v8::Local<v8::Value> name;
874 if (!names->Get(context, i).ToLocal(&name) || !name->IsName()) continue;
875 if (m_global->Has(context, name).FromMaybe(true)) continue;
876 if (!m_installedMethods->Add(context, name).ToLocal(&m_installedMethods))
877 continue;
878 if (!m_global
879 ->SetAccessor(context, v8::Local<v8::Name>::Cast(name),
880 CommandLineAPIScope::accessorGetterCallback,
881 CommandLineAPIScope::accessorSetterCallback,
882 externalThis, v8::DEFAULT, v8::DontEnum)
883 .FromMaybe(false)) {
884 bool removed = m_installedMethods->Delete(context, name).FromMaybe(false);
885 DCHECK(removed);
886 continue;
887 }
888 }
889 }
890
891 V8Console::CommandLineAPIScope::~CommandLineAPIScope() {
892 m_cleanup = true;
893 v8::Local<v8::Array> names = m_installedMethods->AsArray();
894 for (size_t i = 0; i < names->Length(); ++i) {
895 v8::Local<v8::Value> name;
896 if (!names->Get(m_context, i).ToLocal(&name) || !name->IsName()) continue;
897 if (name->IsString()) {
898 v8::Local<v8::Value> descriptor;
899 bool success = m_global
900 ->GetOwnPropertyDescriptor(
901 m_context, v8::Local<v8::String>::Cast(name))
902 .ToLocal(&descriptor);
903 DCHECK(success);
904 }
905 }
906 }
907
908 } // namespace v8_inspector
OLDNEW
« no previous file with comments | « src/inspector/V8Console.h ('k') | src/inspector/V8ConsoleAgentImpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698