OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "platform/v8_inspector/V8Console.h" | |
6 | |
7 #include "platform/inspector_protocol/String16.h" | |
8 #include "platform/v8_inspector/V8StackTraceImpl.h" | |
9 #include "platform/v8_inspector/V8StringUtil.h" | |
10 #include "platform/v8_inspector/public/ConsoleAPITypes.h" | |
11 #include "platform/v8_inspector/public/ConsoleTypes.h" | |
12 #include "platform/v8_inspector/public/V8DebuggerClient.h" | |
13 | |
14 namespace blink { | |
15 | |
16 namespace { | |
17 | |
18 v8::MaybeLocal<v8::Object> consoleObjectFromInfo(const v8::FunctionCallbackInfo< v8::Value>& info) | |
19 { | |
20 if (info.Data().IsEmpty() || !info.Data()->IsObject()) | |
21 return v8::MaybeLocal<v8::Object>(); | |
22 return info.Data().As<v8::Object>(); | |
23 } | |
24 | |
25 v8::Local<v8::Private> clientPrivateKey(v8::Isolate* isolate) | |
26 { | |
27 return v8::Private::ForApi(isolate, toV8StringInternalized(isolate, "V8Conso le#V8DebuggerClient")); | |
28 } | |
29 | |
30 V8DebuggerClient* clientFromConsoleObject(v8::Isolate* isolate, v8::Local<v8::Ob ject> console) | |
31 { | |
32 v8::Local<v8::Value> value; | |
33 if (!console->GetPrivate(isolate->GetCurrentContext(), clientPrivateKey(isol ate)).ToLocal(&value)) | |
34 return nullptr; | |
35 if (!value->IsExternal()) | |
dgozman
2016/04/08 18:18:46
ASSERT
kozy
2016/04/08 23:56:51
Done.
| |
36 return nullptr; | |
37 V8DebuggerClient* client = static_cast<V8DebuggerClient*>(value.As<v8::Exter nal>()->Value()); | |
38 return client; | |
39 } | |
40 | |
41 void internalAddMessage(MessageType type, MessageLevel level, const v8::Function CallbackInfo<v8::Value>& info, bool allowEmptyArguments, int firstArg) | |
dgozman
2016/04/08 18:18:46
skipArgumentCount
kozy
2016/04/08 23:56:51
Done.
| |
42 { | |
43 if (!allowEmptyArguments && !info.Length()) | |
44 return; | |
45 v8::Local<v8::Object> consoleObject; | |
46 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
47 return; | |
48 v8::Isolate* isolate = info.GetIsolate(); | |
49 V8DebuggerClient* client = clientFromConsoleObject(isolate, consoleObject); | |
50 if (!client) | |
51 return; | |
52 client->reportMessageToConsole(isolate->GetCurrentContext(), type, level, in fo, firstArg); | |
53 } | |
54 | |
55 bool createBoundFunctionProperty(v8::Local<v8::Context> context, v8::Local<v8::O bject> obj, const char* name, v8::FunctionCallback callback) | |
56 { | |
57 v8::Local<v8::String> funcName = toV8StringInternalized(context->GetIsolate( ), name); | |
58 v8::Local<v8::Function> func; | |
59 if (!v8::Function::New(context, callback, obj).ToLocal(&func)) | |
60 return false; | |
61 func->SetName(funcName); | |
62 return obj->CreateDataProperty(context, funcName, func).FromMaybe(false); | |
dgozman
2016/04/08 18:18:46
ASSERT
kozy
2016/04/08 23:56:51
Done.
| |
63 } | |
64 | |
65 v8::MaybeLocal<v8::Map> privateMapFromConsoleObject(v8::Isolate* isolate, v8::Lo cal<v8::Object> console, const char* name) | |
66 { | |
67 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
68 | |
69 v8::Local<v8::Private> privateKey = v8::Private::ForApi(isolate, toV8StringI nternalized(isolate, name)); | |
70 v8::Local<v8::Value> mapValue; | |
71 if (!console->GetPrivate(context, privateKey).ToLocal(&mapValue)) | |
72 return v8::MaybeLocal<v8::Map>(); | |
73 if (mapValue->IsUndefined()) { | |
74 v8::Local<v8::Map> map = v8::Map::New(isolate); | |
75 if (!console->SetPrivate(context, privateKey, map).FromMaybe(false)) | |
76 return v8::MaybeLocal<v8::Map>(); | |
77 return map; | |
78 } | |
79 return mapValue->IsMap() ? mapValue.As<v8::Map>() : v8::MaybeLocal<v8::Map>( ); | |
80 } | |
81 | |
82 } // namespace | |
83 | |
84 void V8Console::debugCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
85 { | |
86 internalAddMessage(LogMessageType, DebugMessageLevel, info, false, 0); | |
87 } | |
88 | |
89 void V8Console::errorCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
90 { | |
91 internalAddMessage(LogMessageType, ErrorMessageLevel, info, false, 0); | |
92 } | |
93 | |
94 void V8Console::infoCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
95 { | |
96 internalAddMessage(LogMessageType, InfoMessageLevel, info, false, 0); | |
97 } | |
98 | |
99 void V8Console::logCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
100 { | |
101 internalAddMessage(LogMessageType, LogMessageLevel, info, false, 0); | |
102 } | |
103 | |
104 void V8Console::warnCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
105 { | |
106 internalAddMessage(LogMessageType, WarningMessageLevel, info, false, 0); | |
107 } | |
108 | |
109 void V8Console::dirCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
110 { | |
111 internalAddMessage(DirMessageType, LogMessageLevel, info, false, 0); | |
112 } | |
113 | |
114 void V8Console::dirxmlCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
115 { | |
116 internalAddMessage(DirXMLMessageType, LogMessageLevel, info, false, 0); | |
117 } | |
118 | |
119 void V8Console::tableCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
120 { | |
121 internalAddMessage(TableMessageType, LogMessageLevel, info, false, 0); | |
122 } | |
123 | |
124 void V8Console::traceCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
125 { | |
126 internalAddMessage(TraceMessageType, LogMessageLevel, info, true, 0); | |
127 } | |
128 | |
129 void V8Console::groupCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
130 { | |
131 internalAddMessage(StartGroupMessageType, LogMessageLevel, info, true, 0); | |
132 } | |
133 | |
134 void V8Console::groupCollapsedCallback(const v8::FunctionCallbackInfo<v8::Value> & info) | |
135 { | |
136 internalAddMessage(StartGroupCollapsedMessageType, LogMessageLevel, info, tr ue, 0); | |
137 } | |
138 | |
139 void V8Console::groupEndCallback(const v8::FunctionCallbackInfo<v8::Value>& info ) | |
140 { | |
141 internalAddMessage(EndGroupMessageType, LogMessageLevel, info, true, 0); | |
142 } | |
143 | |
144 void V8Console::clearCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
145 { | |
146 internalAddMessage(ClearMessageType, LogMessageLevel, info, true, 0); | |
147 } | |
148 | |
149 void V8Console::countCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
150 { | |
151 v8::Isolate* isolate = info.GetIsolate(); | |
152 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
153 | |
154 v8::Local<v8::Object> consoleObject; | |
155 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
156 return; | |
157 V8DebuggerClient* client = clientFromConsoleObject(isolate, consoleObject); | |
158 if (!client) | |
159 return; | |
160 | |
161 // Follow Firebug's behavior of counting with null and undefined title in | |
162 // the same bucket as no argument | |
163 String16 title; | |
164 if (info.Length() > 0 && (!info[0]->IsNull() || !info[0]->IsUndefined())) { | |
165 v8::Local<v8::String> titleValue; | |
166 if (info[0]->IsObject()) { | |
167 if (!info[0].As<v8::Object>()->ObjectProtoToString(context).ToLocal( &titleValue)) | |
168 return; | |
169 } else { | |
170 if (!info[0]->ToString(context).ToLocal(&titleValue)) | |
171 return; | |
172 } | |
173 title = toProtocolString(titleValue); | |
174 } | |
175 | |
176 String16 identifier; | |
177 if (title.isEmpty()) { | |
178 OwnPtr<V8StackTraceImpl> stackTrace = V8StackTraceImpl::capture(nullptr, 1); | |
179 if (stackTrace) | |
180 identifier = stackTrace->topSourceURL() + ":" + String16::number(sta ckTrace->topLineNumber()); | |
181 } else { | |
182 identifier = title + "@"; | |
183 } | |
184 | |
185 v8::Local<v8::Map> countMap; | |
186 if (!privateMapFromConsoleObject(info.GetIsolate(), consoleObject, "V8Consol e#countMap").ToLocal(&countMap)) | |
187 return; | |
188 | |
189 v8::Local<v8::String> key = toV8String(isolate, identifier); | |
190 int64_t count = 0; | |
191 if (countMap->Has(context, key).FromMaybe(false)) { | |
192 v8::Local<v8::Value> countValue; | |
193 if (!countMap->Get(context, key).ToLocal(&countValue)) | |
194 return; | |
195 count = countValue.As<v8::Integer>()->Value(); | |
196 } | |
197 ++count; | |
198 if (!countMap->Set(context, key, v8::Integer::New(isolate, count)).ToLocal(& countMap)) | |
199 return; | |
200 String16 message = title + ": " + String16::number(count); | |
201 client->reportMessageToConsole(context, CountMessageType, DebugMessageLevel, message); | |
202 } | |
203 | |
204 void V8Console::assertCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
205 { | |
206 bool condition = false; | |
207 if (info.Length() > 0) { | |
208 if (info[0]->IsBoolean()) | |
209 condition = info[0].As<v8::Boolean>()->Value(); | |
210 else | |
211 condition = info[0]->BooleanValue(info.GetIsolate()->GetCurrentConte xt()).FromMaybe(false); | |
212 } | |
213 if (condition) | |
214 return; | |
215 internalAddMessage(AssertMessageType, ErrorMessageLevel, info, true, 1); | |
216 } | |
217 | |
218 void V8Console::markTimelineCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
219 { | |
220 if (!info.Data()->IsObject()) | |
221 return; | |
222 v8::Local<v8::Object> consoleObject = info.Data().As<v8::Object>(); | |
223 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
224 if (!client) | |
225 return; | |
226 client->reportMessageToConsole(info.GetIsolate()->GetCurrentContext(), LogMe ssageType, WarningMessageLevel, "console.markTimeline method was removed."); | |
227 } | |
228 | |
229 void V8Console::profileCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
230 { | |
231 v8::Local<v8::Object> consoleObject; | |
232 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
233 return; | |
234 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
235 if (!client) | |
236 return; | |
237 String16 title = info.Length() > 0 ? toProtocolStringWithTypeCheck(info[0]) : String16(); | |
238 client->profile(info.GetIsolate()->GetCurrentContext(), title); | |
239 } | |
240 | |
241 void V8Console::profileEndCallback(const v8::FunctionCallbackInfo<v8::Value>& in fo) | |
242 { | |
243 v8::Local<v8::Object> consoleObject; | |
244 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
245 return; | |
246 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
247 if (!client) | |
248 return; | |
249 String16 title = info.Length() > 0 ? toProtocolStringWithTypeCheck(info[0]) : String16(); | |
250 client->profileEnd(info.GetIsolate()->GetCurrentContext(), title); | |
251 } | |
252 | |
253 void V8Console::timelineCallback(const v8::FunctionCallbackInfo<v8::Value>& info ) | |
254 { | |
255 v8::Local<v8::Object> consoleObject; | |
256 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
257 return; | |
258 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
259 if (!client) | |
260 return; | |
261 client->reportMessageToConsole(info.GetIsolate()->GetCurrentContext(), LogMe ssageType, WarningMessageLevel, "console.timeline method was removed. Please use console.time imstead."); | |
262 } | |
263 | |
264 void V8Console::timelineEndCallback(const v8::FunctionCallbackInfo<v8::Value>& i nfo) | |
265 { | |
266 v8::Local<v8::Object> consoleObject; | |
267 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
268 return; | |
269 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
270 if (!client) | |
271 return; | |
272 client->reportMessageToConsole(info.GetIsolate()->GetCurrentContext(), LogMe ssageType, WarningMessageLevel, "console.timelineEnd method was removed. Please use console.timeEnd imstead."); | |
273 } | |
274 | |
275 void V8Console::timeCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
276 { | |
277 v8::Isolate* isolate = info.GetIsolate(); | |
278 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
279 v8::Local<v8::Object> consoleObject; | |
280 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
281 return; | |
282 V8DebuggerClient* client = clientFromConsoleObject(isolate, consoleObject); | |
283 if (!client) | |
284 return; | |
285 v8::Local<v8::Map> timeMap; | |
286 if (!privateMapFromConsoleObject(isolate, consoleObject, "V8Console#timeMap" ).ToLocal(&timeMap)) | |
287 return; | |
288 v8::Local<v8::String> title; | |
289 if (!info[0]->ToString(context).ToLocal(&title)) | |
290 return; | |
291 if (!timeMap->Set(context, title, v8::Number::New(isolate, client->currentTi meMS())).ToLocal(&timeMap)) | |
292 return; | |
293 } | |
294 | |
295 void V8Console::timeEndCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
296 { | |
297 v8::Isolate* isolate = info.GetIsolate(); | |
298 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
299 v8::Local<v8::Object> consoleObject; | |
300 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
301 return; | |
302 V8DebuggerClient* client = clientFromConsoleObject(isolate, consoleObject); | |
303 if (!client) | |
304 return; | |
305 v8::Local<v8::Map> timeMap; | |
306 if (!privateMapFromConsoleObject(isolate, consoleObject, "V8Console#timeMap" ).ToLocal(&timeMap)) | |
307 return; | |
308 v8::Local<v8::String> title; | |
309 if (!info[0]->ToString(context).ToLocal(&title)) | |
310 return; | |
311 v8::Local<v8::Value> timeValue; | |
312 if (!timeMap->Get(context, title).ToLocal(&timeValue) || !timeValue->IsNumbe r()) | |
313 return; | |
314 double elapsed = client->currentTimeMS() - timeValue.As<v8::Number>()->Value (); | |
315 String16 message = toProtocolString(title) + ": " + String16::fromDouble(ela psed, 3) + "ms"; | |
316 client->reportMessageToConsole(info.GetIsolate()->GetCurrentContext(), TimeE ndMessageType, DebugMessageLevel, message); | |
317 } | |
318 | |
319 void V8Console::timeStampCallback(const v8::FunctionCallbackInfo<v8::Value>& inf o) | |
320 { | |
321 v8::Local<v8::Object> consoleObject; | |
322 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
323 return; | |
324 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
325 if (!client) | |
326 return; | |
327 String16 title = info.Length() > 0 ? toProtocolStringWithTypeCheck(info[0]) : String16(); | |
328 client->timeStamp(info.GetIsolate(), title); | |
329 } | |
330 | |
331 void V8Console::memoryGetterCallback(const v8::FunctionCallbackInfo<v8::Value>& info) | |
332 { | |
333 v8::Local<v8::Object> consoleObject; | |
334 if (!consoleObjectFromInfo(info).ToLocal(&consoleObject)) | |
335 return; | |
336 V8DebuggerClient* client = clientFromConsoleObject(info.GetIsolate(), consol eObject); | |
337 if (!client) | |
338 return; | |
339 v8::Local<v8::Value> memoryValue; | |
340 if (!client->memoryInfo(info.GetIsolate(), info.GetIsolate()->GetCurrentCont ext(), info.Holder()).ToLocal(&memoryValue)) | |
341 return; | |
342 info.GetReturnValue().Set(memoryValue); | |
343 } | |
344 | |
345 v8::Local<v8::Object> V8Console::create(v8::Local<v8::Context> context, V8Debugg erClient* client) | |
346 { | |
347 v8::Isolate* isolate = context->GetIsolate(); | |
348 v8::Local<v8::Object> console = v8::Object::New(isolate); | |
349 createBoundFunctionProperty(context, console, "debug", V8Console::debugCallb ack); | |
350 createBoundFunctionProperty(context, console, "error", V8Console::errorCallb ack); | |
351 createBoundFunctionProperty(context, console, "info", V8Console::infoCallbac k); | |
352 createBoundFunctionProperty(context, console, "log", V8Console::logCallback) ; | |
353 createBoundFunctionProperty(context, console, "warn", V8Console::warnCallbac k); | |
354 createBoundFunctionProperty(context, console, "dir", V8Console::dirCallback) ; | |
355 createBoundFunctionProperty(context, console, "dirxml", V8Console::dirxmlCal lback); | |
356 createBoundFunctionProperty(context, console, "table", V8Console::tableCallb ack); | |
357 createBoundFunctionProperty(context, console, "trace", V8Console::traceCallb ack); | |
358 createBoundFunctionProperty(context, console, "group", V8Console::groupCallb ack); | |
359 createBoundFunctionProperty(context, console, "groupCollapsed", V8Console::g roupCollapsedCallback); | |
360 createBoundFunctionProperty(context, console, "groupEnd", V8Console::groupEn dCallback); | |
361 createBoundFunctionProperty(context, console, "clear", V8Console::clearCallb ack); | |
362 createBoundFunctionProperty(context, console, "count", V8Console::countCallb ack); | |
363 createBoundFunctionProperty(context, console, "assert", V8Console::assertCal lback); | |
364 createBoundFunctionProperty(context, console, "markTimeline", V8Console::mar kTimelineCallback); | |
365 createBoundFunctionProperty(context, console, "profile", V8Console::profileC allback); | |
366 createBoundFunctionProperty(context, console, "profileEnd", V8Console::profi leEndCallback); | |
367 createBoundFunctionProperty(context, console, "timeline", V8Console::timelin eCallback); | |
368 createBoundFunctionProperty(context, console, "timelineEnd", V8Console::time lineEndCallback); | |
369 createBoundFunctionProperty(context, console, "time", V8Console::timeCallbac k); | |
370 createBoundFunctionProperty(context, console, "timeEnd", V8Console::timeEndC allback); | |
371 createBoundFunctionProperty(context, console, "timeStamp", V8Console::timeSt ampCallback); | |
372 if (client->hasMemoryOnConsole(context)) | |
373 console->SetAccessorProperty(toV8StringInternalized(isolate, "memory"), v8::Function::New(isolate, V8Console::memoryGetterCallback, console), v8::Local< v8::Function>(), static_cast<v8::PropertyAttribute>(v8::None), v8::DEFAULT); | |
374 | |
375 console->SetPrivate(context, clientPrivateKey(isolate), v8::External::New(is olate, client)); | |
376 return console; | |
377 } | |
378 | |
379 } // namespace blink | |
OLD | NEW |