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

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

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

Powered by Google App Engine
This is Rietveld 408576698