1/*
2 * Copyright (C) 2014 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 "ConsolePrototype.h"
28
29#include "ConsoleClient.h"
30#include "Error.h"
31#include "ExceptionHelpers.h"
32#include "JSCInlines.h"
33#include "JSConsole.h"
34#include "ScriptArguments.h"
35#include "ScriptCallStackFactory.h"
36
37namespace JSC {
38
39const ClassInfo ConsolePrototype::s_info = { "ConsolePrototype", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ConsolePrototype) };
40
41static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState*);
42static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState*);
43static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState*);
44static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState*);
45static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState*);
46static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState*);
47static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState*);
48static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState*);
49static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState*);
50static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState*);
51static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState*);
52static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState*);
53static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(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*);
60
61void ConsolePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
62{
63    Base::finishCreation(vm);
64    ASSERT(inherits(info()));
65    vm.prototypeMap.addPrototype(this);
66
67    // For legacy reasons, console properties are enumerable, writable, deleteable,
68    // and all have a length of 0. This may change if Console is standardized.
69
70    JSC_NATIVE_FUNCTION("debug", consoleProtoFuncDebug, None, 0);
71    JSC_NATIVE_FUNCTION("error", consoleProtoFuncError, None, 0);
72    JSC_NATIVE_FUNCTION("log", consoleProtoFuncLog, None, 0);
73    JSC_NATIVE_FUNCTION("info", consoleProtoFuncLog, None, 0); // "info" is an alias of "log".
74    JSC_NATIVE_FUNCTION("warn", consoleProtoFuncWarn, None, 0);
75
76    JSC_NATIVE_FUNCTION("clear", consoleProtoFuncClear, None, 0);
77    JSC_NATIVE_FUNCTION("dir", consoleProtoFuncDir, None, 0);
78    JSC_NATIVE_FUNCTION("dirxml", consoleProtoFuncDirXML, None, 0);
79    JSC_NATIVE_FUNCTION("table", consoleProtoFuncTable, None, 0);
80    JSC_NATIVE_FUNCTION("trace", consoleProtoFuncTrace, None, 0);
81    JSC_NATIVE_FUNCTION("assert", consoleProtoFuncAssert, None, 0);
82    JSC_NATIVE_FUNCTION("count", consoleProtoFuncCount, None, 0);
83    JSC_NATIVE_FUNCTION("profile", consoleProtoFuncProfile, None, 0);
84    JSC_NATIVE_FUNCTION("profileEnd", consoleProtoFuncProfileEnd, None, 0);
85    JSC_NATIVE_FUNCTION("time", consoleProtoFuncTime, None, 0);
86    JSC_NATIVE_FUNCTION("timeEnd", consoleProtoFuncTimeEnd, None, 0);
87    JSC_NATIVE_FUNCTION("timeStamp", consoleProtoFuncTimeStamp, None, 0);
88    JSC_NATIVE_FUNCTION("group", consoleProtoFuncGroup, None, 0);
89    JSC_NATIVE_FUNCTION("groupCollapsed", consoleProtoFuncGroupCollapsed, None, 0);
90    JSC_NATIVE_FUNCTION("groupEnd", consoleProtoFuncGroupEnd, None, 0);
91}
92
93static String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
94{
95    if (value.isUndefinedOrNull())
96        return String();
97    return value.toString(exec)->value(exec);
98}
99
100static EncodedJSValue consoleLogWithLevel(ExecState* exec, MessageLevel level)
101{
102    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
103    if (!castedThis)
104        return throwVMTypeError(exec);
105    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
106    ConsoleClient* client = castedThis->globalObject()->consoleClient();
107    if (!client)
108        return JSValue::encode(jsUndefined());
109
110    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
111    client->logWithLevel(exec, arguments.release(), level);
112    return JSValue::encode(jsUndefined());
113}
114
115static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDebug(ExecState* exec)
116{
117    return consoleLogWithLevel(exec, MessageLevel::Debug);
118}
119
120static EncodedJSValue JSC_HOST_CALL consoleProtoFuncError(ExecState* exec)
121{
122    return consoleLogWithLevel(exec, MessageLevel::Error);
123}
124
125static EncodedJSValue JSC_HOST_CALL consoleProtoFuncLog(ExecState* exec)
126{
127    return consoleLogWithLevel(exec, MessageLevel::Log);
128}
129
130static EncodedJSValue JSC_HOST_CALL consoleProtoFuncWarn(ExecState* exec)
131{
132    return consoleLogWithLevel(exec, MessageLevel::Warning);
133}
134
135static EncodedJSValue JSC_HOST_CALL consoleProtoFuncClear(ExecState* exec)
136{
137    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
138    if (!castedThis)
139        return throwVMTypeError(exec);
140    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
141    ConsoleClient* client = castedThis->globalObject()->consoleClient();
142    if (!client)
143        return JSValue::encode(jsUndefined());
144
145    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
146    client->clear(exec, arguments.release());
147    return JSValue::encode(jsUndefined());
148}
149
150static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDir(ExecState* exec)
151{
152    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
153    if (!castedThis)
154        return throwVMTypeError(exec);
155    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
156    ConsoleClient* client = castedThis->globalObject()->consoleClient();
157    if (!client)
158        return JSValue::encode(jsUndefined());
159
160    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
161    client->dir(exec, arguments.release());
162    return JSValue::encode(jsUndefined());
163}
164
165static EncodedJSValue JSC_HOST_CALL consoleProtoFuncDirXML(ExecState* exec)
166{
167    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
168    if (!castedThis)
169        return throwVMTypeError(exec);
170    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
171    ConsoleClient* client = castedThis->globalObject()->consoleClient();
172    if (!client)
173        return JSValue::encode(jsUndefined());
174
175    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
176    client->dirXML(exec, arguments.release());
177    return JSValue::encode(jsUndefined());
178}
179
180static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTable(ExecState* exec)
181{
182    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
183    if (!castedThis)
184        return throwVMTypeError(exec);
185    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
186    ConsoleClient* client = castedThis->globalObject()->consoleClient();
187    if (!client)
188        return JSValue::encode(jsUndefined());
189
190    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
191    client->table(exec, arguments.release());
192    return JSValue::encode(jsUndefined());
193}
194
195static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTrace(ExecState* exec)
196{
197    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
198    if (!castedThis)
199        return throwVMTypeError(exec);
200    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
201    ConsoleClient* client = castedThis->globalObject()->consoleClient();
202    if (!client)
203        return JSValue::encode(jsUndefined());
204
205    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
206    client->trace(exec, arguments.release());
207    return JSValue::encode(jsUndefined());
208}
209
210static EncodedJSValue JSC_HOST_CALL consoleProtoFuncAssert(ExecState* exec)
211{
212    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
213    if (!castedThis)
214        return throwVMTypeError(exec);
215    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
216    ConsoleClient* client = castedThis->globalObject()->consoleClient();
217    if (!client)
218        return JSValue::encode(jsUndefined());
219
220    bool condition(exec->argument(0).toBoolean(exec));
221    if (exec->hadException())
222        return JSValue::encode(jsUndefined());
223
224    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 1));
225    client->assertCondition(exec, arguments.release(), condition);
226    return JSValue::encode(jsUndefined());
227}
228
229static EncodedJSValue JSC_HOST_CALL consoleProtoFuncCount(ExecState* exec)
230{
231    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
232    if (!castedThis)
233        return throwVMTypeError(exec);
234    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
235    ConsoleClient* client = castedThis->globalObject()->consoleClient();
236    if (!client)
237        return JSValue::encode(jsUndefined());
238
239    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
240    client->count(exec, arguments.release());
241    return JSValue::encode(jsUndefined());
242}
243
244static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfile(ExecState* exec)
245{
246    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
247    if (!castedThis)
248        return throwVMTypeError(exec);
249    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
250    ConsoleClient* client = castedThis->globalObject()->consoleClient();
251    if (!client)
252        return JSValue::encode(jsUndefined());
253
254    size_t argsCount = exec->argumentCount();
255    if (argsCount <= 0) {
256        client->profile(exec, String());
257        return JSValue::encode(jsUndefined());
258    }
259
260    const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
261    if (exec->hadException())
262        return JSValue::encode(jsUndefined());
263
264    client->profile(exec, title);
265    return JSValue::encode(jsUndefined());
266}
267
268static EncodedJSValue JSC_HOST_CALL consoleProtoFuncProfileEnd(ExecState* exec)
269{
270    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
271    if (!castedThis)
272        return throwVMTypeError(exec);
273    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
274    ConsoleClient* client = castedThis->globalObject()->consoleClient();
275    if (!client)
276        return JSValue::encode(jsUndefined());
277
278    size_t argsCount = exec->argumentCount();
279    if (argsCount <= 0) {
280        client->profileEnd(exec, String());
281        return JSValue::encode(jsUndefined());
282    }
283
284    const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
285    if (exec->hadException())
286        return JSValue::encode(jsUndefined());
287
288    client->profileEnd(exec, title);
289    return JSValue::encode(jsUndefined());
290}
291
292static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTime(ExecState* exec)
293{
294    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
295    if (!castedThis)
296        return throwVMTypeError(exec);
297    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
298    ConsoleClient* client = castedThis->globalObject()->consoleClient();
299    if (!client)
300        return JSValue::encode(jsUndefined());
301
302    if (exec->argumentCount() < 1)
303        return throwVMError(exec, createNotEnoughArgumentsError(exec));
304
305    const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
306    if (exec->hadException())
307        return JSValue::encode(jsUndefined());
308
309    client->time(exec, title);
310    return JSValue::encode(jsUndefined());
311}
312
313static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeEnd(ExecState* exec)
314{
315    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
316    if (!castedThis)
317        return throwVMTypeError(exec);
318    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
319    ConsoleClient* client = castedThis->globalObject()->consoleClient();
320    if (!client)
321        return JSValue::encode(jsUndefined());
322
323    if (exec->argumentCount() < 1)
324        return throwVMError(exec, createNotEnoughArgumentsError(exec));
325
326    const String& title(valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)));
327    if (exec->hadException())
328        return JSValue::encode(jsUndefined());
329
330    client->timeEnd(exec, title);
331    return JSValue::encode(jsUndefined());
332}
333
334static EncodedJSValue JSC_HOST_CALL consoleProtoFuncTimeStamp(ExecState* exec)
335{
336    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
337    if (!castedThis)
338        return throwVMTypeError(exec);
339    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
340    ConsoleClient* client = castedThis->globalObject()->consoleClient();
341    if (!client)
342        return JSValue::encode(jsUndefined());
343
344    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
345    client->timeStamp(exec, arguments.release());
346    return JSValue::encode(jsUndefined());
347}
348
349static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroup(ExecState* exec)
350{
351    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
352    if (!castedThis)
353        return throwVMTypeError(exec);
354    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
355    ConsoleClient* client = castedThis->globalObject()->consoleClient();
356    if (!client)
357        return JSValue::encode(jsUndefined());
358
359    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
360    client->group(exec, arguments.release());
361    return JSValue::encode(jsUndefined());
362}
363
364static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState* exec)
365{
366    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
367    if (!castedThis)
368        return throwVMTypeError(exec);
369    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
370    ConsoleClient* client = castedThis->globalObject()->consoleClient();
371    if (!client)
372        return JSValue::encode(jsUndefined());
373
374    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
375    client->groupCollapsed(exec, arguments.release());
376    return JSValue::encode(jsUndefined());
377}
378
379static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState* exec)
380{
381    JSConsole* castedThis = jsDynamicCast<JSConsole*>(exec->thisValue());
382    if (!castedThis)
383        return throwVMTypeError(exec);
384    ASSERT_GC_OBJECT_INHERITS(castedThis, JSConsole::info());
385    ConsoleClient* client = castedThis->globalObject()->consoleClient();
386    if (!client)
387        return JSValue::encode(jsUndefined());
388
389    RefPtr<Inspector::ScriptArguments> arguments(Inspector::createScriptArguments(exec, 0));
390    client->groupEnd(exec, arguments.release());
391    return JSValue::encode(jsUndefined());
392}
393
394}
395