Expose the ProfileNode sorting functions on JavaScriptProfileNode.
[WebKit-https.git] / WebCore / page / JavaScriptProfileNode.cpp
1 /*
2  * Copyright (C) 2008 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 "JavaScriptProfileNode.h"
28
29 #include "kjs_binding.h"
30 #include <profiler/ProfileNode.h>
31 #include <JavaScriptCore/APICast.h>
32 #include <JavaScriptCore/JSObjectRef.h>
33 #include <JavaScriptCore/JSContextRef.h>
34 #include <JavaScriptCore/JSRetainPtr.h>
35 #include <JavaScriptCore/JSStringRef.h>
36 #include <kjs/value.h>
37
38 using namespace KJS;
39
40 namespace WebCore {
41
42 // Cache
43
44 typedef HashMap<ProfileNode*, JSValue*> ProfileNodeMap;
45
46 static ProfileNodeMap& ProfileNodeCache()
47
48     static ProfileNodeMap staticProfileNodes;
49     return staticProfileNodes;
50 }
51
52 // Static Values
53
54 static JSClassRef ProfileNodeClass();
55
56 static JSValueRef getFunctionName(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
57 {
58     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
59         return JSValueMakeUndefined(ctx);
60
61     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
62     return JSValueMakeString(ctx, JSStringCreateWithCharacters(profileNode->functionName().data(), profileNode->functionName().size()));
63 }
64
65 static JSValueRef getTotalTime(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
66 {
67     KJS::JSLock lock;
68
69     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
70         return JSValueMakeUndefined(ctx);
71
72     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
73     return JSValueMakeNumber(ctx, profileNode->totalTime());
74 }
75
76 static JSValueRef getSelfTime(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
77 {
78     KJS::JSLock lock;
79
80     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
81         return JSValueMakeUndefined(ctx);
82
83     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
84     return JSValueMakeNumber(ctx, profileNode->selfTime());
85 }
86
87 static JSValueRef getTotalPercent(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
88 {
89     KJS::JSLock lock;
90
91     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
92         return JSValueMakeUndefined(ctx);
93
94     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
95     return JSValueMakeNumber(ctx, profileNode->totalPercent());
96 }
97
98 static JSValueRef getSelfPercent(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
99 {
100     KJS::JSLock lock;
101
102     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
103         return JSValueMakeUndefined(ctx);
104
105     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
106     return JSValueMakeNumber(ctx, profileNode->selfPercent());
107 }
108
109 static JSValueRef getNumberOfCalls(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
110 {
111     KJS::JSLock lock;
112
113     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
114         return JSValueMakeUndefined(ctx);
115
116     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
117     return JSValueMakeNumber(ctx, profileNode->numberOfCalls());
118 }
119
120 static JSValueRef getChildren(JSContextRef ctx, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
121 {
122     KJS::JSLock lock;
123
124     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
125         return JSValueMakeUndefined(ctx);
126
127     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
128     const Vector<RefPtr<ProfileNode> >& children = profileNode->children();
129
130     JSObjectRef global = JSContextGetGlobalObject(ctx);
131
132     JSRetainPtr<JSStringRef> arrayString(Adopt, JSStringCreateWithUTF8CString("Array"));
133
134     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, arrayString.get(), exception);
135     if (exception && *exception)
136         return JSValueMakeUndefined(ctx);
137
138     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
139     if (exception && *exception)
140         return JSValueMakeUndefined(ctx);
141
142     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
143     if (exception && *exception)
144         return JSValueMakeUndefined(ctx);
145
146     JSRetainPtr<JSStringRef> pushString(Adopt, JSStringCreateWithUTF8CString("push"));
147     
148     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, pushString.get(), exception);
149     if (exception && *exception)
150         return JSValueMakeUndefined(ctx);
151
152     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
153     if (exception && *exception)
154         return JSValueMakeUndefined(ctx);
155
156     for (Vector<RefPtr<ProfileNode> >::const_iterator it = children.begin(); it != children.end(); ++it) {
157         JSValueRef arg0 = toRef(toJS(toJS(ctx), (*it).get() ));
158         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
159         if (exception && *exception)
160             return JSValueMakeUndefined(ctx);
161     }
162
163     return result;
164 }
165
166 static JSValueRef sortTotalTimeDescending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
167 {
168     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
169         return JSValueMakeUndefined(ctx);
170
171     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
172     profileNode->sortTotalTimeDescending();
173
174     return JSValueMakeUndefined(ctx);
175 }
176
177 static JSValueRef sortTotalTimeAscending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
178 {
179     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
180         return JSValueMakeUndefined(ctx);
181
182     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
183     profileNode->sortTotalTimeAscending();
184
185     return JSValueMakeUndefined(ctx);
186 }
187
188 static JSValueRef sortSelfTimeDescending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
189 {
190     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
191         return JSValueMakeUndefined(ctx);
192
193     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
194     profileNode->sortSelfTimeDescending();
195
196     return JSValueMakeUndefined(ctx);
197 }
198
199 static JSValueRef sortSelfTimeAscending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
200 {
201     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
202         return JSValueMakeUndefined(ctx);
203
204     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
205     profileNode->sortSelfTimeAscending();
206
207     return JSValueMakeUndefined(ctx);
208 }
209
210 static JSValueRef sortCallsDescending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
211 {
212     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
213         return JSValueMakeUndefined(ctx);
214
215     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
216     profileNode->sortCallsDescending();
217
218     return JSValueMakeUndefined(ctx);
219 }
220
221 static JSValueRef sortCallsAscending(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
222 {
223     if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass()))
224         return JSValueMakeUndefined(ctx);
225
226     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject));
227     profileNode->sortCallsAscending();
228
229     return JSValueMakeUndefined(ctx);
230 }
231
232 static void finalize(JSObjectRef object)
233 {
234     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(object));
235     ProfileNodeCache().remove(profileNode);
236     profileNode->deref();
237 }
238
239 JSClassRef ProfileNodeClass()
240 {
241     static JSStaticValue staticValues[] = {
242         { "functionName", getFunctionName, 0, kJSPropertyAttributeNone },
243         { "totalTime", getTotalTime, 0, kJSPropertyAttributeNone },
244         { "selfTime", getSelfTime, 0, kJSPropertyAttributeNone },
245         { "totalPercent", getTotalPercent, 0, kJSPropertyAttributeNone },
246         { "selfPercent", getSelfPercent, 0, kJSPropertyAttributeNone },
247         { "numberOfCalls", getNumberOfCalls, 0, kJSPropertyAttributeNone },
248         { "children", getChildren, 0, kJSPropertyAttributeNone },
249         { 0, 0, 0, 0 }
250     };
251
252     static JSStaticFunction staticFunctions[] = {
253         { "sortTotalTimeDescending", sortTotalTimeDescending, kJSPropertyAttributeNone },
254         { "sortTotalTimeAscending", sortTotalTimeAscending, kJSPropertyAttributeNone },
255         { "sortSelfTimeDescending", sortSelfTimeDescending, kJSPropertyAttributeNone },
256         { "sortSelfTimeAscending", sortSelfTimeAscending, kJSPropertyAttributeNone },
257         { "sortCallsDescending", sortCallsDescending, kJSPropertyAttributeNone },
258         { "sortCallsAscending", sortCallsAscending, kJSPropertyAttributeNone },
259         { 0, 0, 0 }
260     };
261
262     static JSClassDefinition classDefinition = {
263         0, kJSClassAttributeNone, "ProfileNode", 0, staticValues, staticFunctions,
264         0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
265     };
266
267     static JSClassRef ProfileNodeClass = JSClassCreate(&classDefinition);
268     return ProfileNodeClass;
269 }
270
271 JSValue* toJS(ExecState* exec, ProfileNode* ProfileNode)
272 {
273     if (!ProfileNode)
274         return jsNull();
275
276     JSValue* ProfileNodeWrapper = ProfileNodeCache().get(ProfileNode);
277     if (ProfileNodeWrapper)
278         return ProfileNodeWrapper;
279
280     ProfileNode->ref();
281
282     ProfileNodeWrapper = toJS(JSObjectMake(toRef(exec), ProfileNodeClass(), static_cast<void*>(ProfileNode)));
283     ProfileNodeCache().set(ProfileNode, ProfileNodeWrapper);
284     return ProfileNodeWrapper;
285 }
286
287
288 } // namespace WebCore