1/*
2 * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ConsoleObject.h"
28
29#include "ConsoleClient.h"
30#include "Error.h"
31#include "JSCInlines.h"
32#include "ScriptArguments.h"
33#include "ScriptCallStackFactory.h"
34
35namespace JSC {
36
37STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ConsoleObject);
38
39static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState*);
40static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState*);
41static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState*);
42static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState*);
43static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState*);
44static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState*);
45static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState*);
46static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState*);
47static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState*);
48static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState*);
49static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState*);
50static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState*);
51static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState*);
52static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState*);
53static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTakeHeapSnapshot(ExecState*);
54static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState*);
55static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState*);
56static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState*);
57static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState*);
58static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState*);
59static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState*);
60static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecord(ExecState*);
61static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecordEnd(ExecState*);
62static EncodedJSValue JSC_HOST_CALL consoleProtoFuncScreenshot(ExecState*);
63
64const ClassInfo ConsoleObject::s_info = { "Console", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ConsoleObject) };
65
66ConsoleObject::ConsoleObject(VM& vm, Structure* structure)
67 : JSNonFinalObject(vm, structure)
68{
69}
70
71void ConsoleObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
72{
73 Base::finishCreation(vm);
74 ASSERT(inherits(vm, info()));
75
76 // For legacy reasons, console properties are enumerable, writable, deleteable,
77 // and all have a length of 0. This may change if Console is standardized.
78
79 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("debug", consoleProtoFuncDebug, static_cast<unsigned>(PropertyAttribute::None), 0);
80 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("error", consoleProtoFuncError, static_cast<unsigned>(PropertyAttribute::None), 0);
81 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("log", consoleProtoFuncLog, static_cast<unsigned>(PropertyAttribute::None), 0);
82 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("info", consoleProtoFuncInfo, static_cast<unsigned>(PropertyAttribute::None), 0);
83 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("warn", consoleProtoFuncWarn, static_cast<unsigned>(PropertyAttribute::None), 0);
84
85 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, consoleProtoFuncClear, static_cast<unsigned>(PropertyAttribute::None), 0);
86 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("dir", consoleProtoFuncDir, static_cast<unsigned>(PropertyAttribute::None), 0);
87 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("dirxml", consoleProtoFuncDirXML, static_cast<unsigned>(PropertyAttribute::None), 0);
88 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("table", consoleProtoFuncTable, static_cast<unsigned>(PropertyAttribute::None), 0);
89 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("trace", consoleProtoFuncTrace, static_cast<unsigned>(PropertyAttribute::None), 0);
90 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("assert", consoleProtoFuncAssert, static_cast<unsigned>(PropertyAttribute::None), 0);
91 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->count, consoleProtoFuncCount, static_cast<unsigned>(PropertyAttribute::None), 0);
92 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("profile", consoleProtoFuncProfile, static_cast<unsigned>(PropertyAttribute::None), 0);
93 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("profileEnd", consoleProtoFuncProfileEnd, static_cast<unsigned>(PropertyAttribute::None), 0);
94 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("time", consoleProtoFuncTime, static_cast<unsigned>(PropertyAttribute::None), 0);
95 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("timeEnd", consoleProtoFuncTimeEnd, static_cast<unsigned>(PropertyAttribute::None), 0);
96 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("timeStamp", consoleProtoFuncTimeStamp, static_cast<unsigned>(PropertyAttribute::None), 0);
97 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("takeHeapSnapshot", consoleProtoFuncTakeHeapSnapshot, static_cast<unsigned>(PropertyAttribute::None), 0);
98 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("group", consoleProtoFuncGroup, static_cast<unsigned>(PropertyAttribute::None), 0);
99 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("groupCollapsed", consoleProtoFuncGroupCollapsed, static_cast<unsigned>(PropertyAttribute::None), 0);
100 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("groupEnd", consoleProtoFuncGroupEnd, static_cast<unsigned>(PropertyAttribute::None), 0);
101 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("record", consoleProtoFuncRecord, static_cast<unsigned>(PropertyAttribute::None), 0);
102 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("recordEnd", consoleProtoFuncRecordEnd, static_cast<unsigned>(PropertyAttribute::None), 0);
103 JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("screenshot", consoleProtoFuncScreenshot, static_cast<unsigned>(PropertyAttribute::None), 0);
104}
105
106static String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
107{
108 if (value.isUndefinedOrNull())
109 return String();
110 return value.toWTFString(exec);
111}
112
113static EncodedJSValue consoleLogWithLevel(ExecState* exec, MessageLevel level)
114{
115 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
116 if (!client)
117 return JSValue::encode(jsUndefined());
118
119 client->logWithLevel(exec, Inspector::createScriptArguments(exec, 0), level);
120 return JSValue::encode(jsUndefined());
121}
122
123static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState* exec)
124{
125 return consoleLogWithLevel(exec, MessageLevel::Debug);
126}
127
128static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState* exec)
129{
130 return consoleLogWithLevel(exec, MessageLevel::Error);
131}
132
133static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState* exec)
134{
135 return consoleLogWithLevel(exec, MessageLevel::Log);
136}
137
138static EncodedJSValue JSC_HOST_CALL consoleProtoFuncInfo(ExecState* exec)
139{
140 return consoleLogWithLevel(exec, MessageLevel::Info);
141}
142
143static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState* exec)
144{
145 return consoleLogWithLevel(exec, MessageLevel::Warning);
146}
147
148static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState* exec)
149{
150 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
151 if (!client)
152 return JSValue::encode(jsUndefined());
153
154 client->clear(exec);
155 return JSValue::encode(jsUndefined());
156}
157
158static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState* exec)
159{
160 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
161 if (!client)
162 return JSValue::encode(jsUndefined());
163
164 client->dir(exec, Inspector::createScriptArguments(exec, 0));
165 return JSValue::encode(jsUndefined());
166}
167
168static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState* exec)
169{
170 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
171 if (!client)
172 return JSValue::encode(jsUndefined());
173
174 client->dirXML(exec, Inspector::createScriptArguments(exec, 0));
175 return JSValue::encode(jsUndefined());
176}
177
178static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState* exec)
179{
180 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
181 if (!client)
182 return JSValue::encode(jsUndefined());
183
184 client->table(exec, Inspector::createScriptArguments(exec, 0));
185 return JSValue::encode(jsUndefined());
186}
187
188static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState* exec)
189{
190 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
191 if (!client)
192 return JSValue::encode(jsUndefined());
193
194 client->trace(exec, Inspector::createScriptArguments(exec, 0));
195 return JSValue::encode(jsUndefined());
196}
197
198static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState* exec)
199{
200 VM& vm = exec->vm();
201 auto scope = DECLARE_THROW_SCOPE(vm);
202 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
203 if (!client)
204 return JSValue::encode(jsUndefined());
205
206 bool condition = exec->argument(0).toBoolean(exec);
207 RETURN_IF_EXCEPTION(scope, encodedJSValue());
208
209 if (condition)
210 return JSValue::encode(jsUndefined());
211
212 client->assertion(exec, Inspector::createScriptArguments(exec, 1));
213 return JSValue::encode(jsUndefined());
214}
215
216static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState* exec)
217{
218 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
219 if (!client)
220 return JSValue::encode(jsUndefined());
221
222 client->count(exec, Inspector::createScriptArguments(exec, 0));
223 return JSValue::encode(jsUndefined());
224}
225
226static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState* exec)
227{
228 VM& vm = exec->vm();
229 auto scope = DECLARE_THROW_SCOPE(vm);
230 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
231 if (!client)
232 return JSValue::encode(jsUndefined());
233
234 size_t argsCount = exec->argumentCount();
235 if (!argsCount) {
236 client->profile(exec, String());
237 return JSValue::encode(jsUndefined());
238 }
239
240 const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
241 RETURN_IF_EXCEPTION(scope, encodedJSValue());
242
243 client->profile(exec, title);
244 return JSValue::encode(jsUndefined());
245}
246
247static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState* exec)
248{
249 VM& vm = exec->vm();
250 auto scope = DECLARE_THROW_SCOPE(vm);
251 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
252 if (!client)
253 return JSValue::encode(jsUndefined());
254
255 size_t argsCount = exec->argumentCount();
256 if (!argsCount) {
257 client->profileEnd(exec, String());
258 return JSValue::encode(jsUndefined());
259 }
260
261 const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
262 RETURN_IF_EXCEPTION(scope, encodedJSValue());
263
264 client->profileEnd(exec, title);
265 return JSValue::encode(jsUndefined());
266}
267
268static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTakeHeapSnapshot(ExecState* exec)
269{
270 VM& vm = exec->vm();
271 auto scope = DECLARE_THROW_SCOPE(vm);
272 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
273 if (!client)
274 return JSValue::encode(jsUndefined());
275
276 size_t argsCount = exec->argumentCount();
277 if (!argsCount) {
278 client->takeHeapSnapshot(exec, String());
279 return JSValue::encode(jsUndefined());
280 }
281
282 const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
283 RETURN_IF_EXCEPTION(scope, encodedJSValue());
284
285 client->takeHeapSnapshot(exec, title);
286 return JSValue::encode(jsUndefined());
287}
288
289static String valueOrDefaultLabelString(ExecState* exec, JSValue value)
290{
291 if (value.isUndefined())
292 return "default"_s;
293 return value.toWTFString(exec);
294}
295
296static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState* exec)
297{
298 VM& vm = exec->vm();
299 auto scope = DECLARE_THROW_SCOPE(vm);
300 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
301 if (!client)
302 return JSValue::encode(jsUndefined());
303
304 String title;
305 if (exec->argumentCount() < 1)
306 title = "default"_s;
307 else {
308 title = valueOrDefaultLabelString(exec, exec->argument(0));
309 RETURN_IF_EXCEPTION(scope, encodedJSValue());
310 }
311
312 client->time(exec, title);
313 return JSValue::encode(jsUndefined());
314}
315
316static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState* exec)
317{
318 VM& vm = exec->vm();
319 auto scope = DECLARE_THROW_SCOPE(vm);
320 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
321 if (!client)
322 return JSValue::encode(jsUndefined());
323
324 String title;
325 if (exec->argumentCount() < 1)
326 title = "default"_s;
327 else {
328 title = valueOrDefaultLabelString(exec, exec->argument(0));
329 RETURN_IF_EXCEPTION(scope, encodedJSValue());
330 }
331
332 client->timeEnd(exec, title);
333 return JSValue::encode(jsUndefined());
334}
335
336static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState* exec)
337{
338 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
339 if (!client)
340 return JSValue::encode(jsUndefined());
341
342 client->timeStamp(exec, Inspector::createScriptArguments(exec, 0));
343 return JSValue::encode(jsUndefined());
344}
345
346static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState* exec)
347{
348 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
349 if (!client)
350 return JSValue::encode(jsUndefined());
351
352 client->group(exec, Inspector::createScriptArguments(exec, 0));
353 return JSValue::encode(jsUndefined());
354}
355
356static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState* exec)
357{
358 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
359 if (!client)
360 return JSValue::encode(jsUndefined());
361
362 client->groupCollapsed(exec, Inspector::createScriptArguments(exec, 0));
363 return JSValue::encode(jsUndefined());
364}
365
366static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState* exec)
367{
368 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
369 if (!client)
370 return JSValue::encode(jsUndefined());
371
372 client->groupEnd(exec, Inspector::createScriptArguments(exec, 0));
373 return JSValue::encode(jsUndefined());
374}
375
376static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecord(ExecState* exec)
377{
378 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
379 if (!client)
380 return JSValue::encode(jsUndefined());
381
382 client->record(exec, Inspector::createScriptArguments(exec, 0));
383 return JSValue::encode(jsUndefined());
384}
385
386static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecordEnd(ExecState* exec)
387{
388 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
389 if (!client)
390 return JSValue::encode(jsUndefined());
391
392 client->recordEnd(exec, Inspector::createScriptArguments(exec, 0));
393 return JSValue::encode(jsUndefined());
394}
395
396static EncodedJSValue JSC_HOST_CALL consoleProtoFuncScreenshot(ExecState* exec)
397{
398 ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient();
399 if (!client)
400 return JSValue::encode(jsUndefined());
401
402 client->screenshot(exec, Inspector::createScriptArguments(exec, 0));
403 return JSValue::encode(jsUndefined());
404}
405
406} // namespace JSC
407