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

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

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