2008-05-14 Alp Toker <alp@nuanti.com>
[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 getNumberOfCalls(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->numberOfCalls());
96 }
97
98 static JSValueRef getChildren(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     const Deque<RefPtr<ProfileNode> >& children = profileNode->children();
107
108     JSObjectRef global = JSContextGetGlobalObject(ctx);
109
110     JSRetainPtr<JSStringRef> arrayString(Adopt, JSStringCreateWithUTF8CString("Array"));
111
112     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, arrayString.get(), exception);
113     if (exception && *exception)
114         return JSValueMakeUndefined(ctx);
115
116     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
117     if (exception && *exception)
118         return JSValueMakeUndefined(ctx);
119
120     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
121     if (exception && *exception)
122         return JSValueMakeUndefined(ctx);
123
124     JSRetainPtr<JSStringRef> pushString(Adopt, JSStringCreateWithUTF8CString("push"));
125     
126     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, pushString.get(), exception);
127     if (exception && *exception)
128         return JSValueMakeUndefined(ctx);
129
130     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
131     if (exception && *exception)
132         return JSValueMakeUndefined(ctx);
133
134     for (Deque<RefPtr<ProfileNode> >::const_iterator it = children.begin(); it != children.end(); ++it) {
135         JSValueRef arg0 = toRef(toJS(toJS(ctx), (*it).get() ));
136         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
137         if (exception && *exception)
138             return JSValueMakeUndefined(ctx);
139     }
140
141     return result;
142 }
143
144 static void finalize(JSObjectRef object)
145 {
146     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(object));
147     ProfileNodeCache().remove(profileNode);
148     profileNode->deref();
149 }
150
151 JSClassRef ProfileNodeClass()
152 {
153     static JSStaticValue staticValues[] = {
154         { "functionName", getFunctionName, 0, kJSPropertyAttributeNone },
155         { "totalTime", getTotalTime, 0, kJSPropertyAttributeNone },
156         { "selfTime", getSelfTime, 0, kJSPropertyAttributeNone },
157         { "numberOfCalls", getNumberOfCalls, 0, kJSPropertyAttributeNone },
158         { "children", getChildren, 0, kJSPropertyAttributeNone },
159         { 0, 0, 0, 0 }
160     };
161
162     static JSClassDefinition classDefinition = {
163         0, kJSClassAttributeNone, "ProfileNode", 0, staticValues, 0,
164         0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
165     };
166
167     static JSClassRef ProfileNodeClass = JSClassCreate(&classDefinition);
168     return ProfileNodeClass;
169 }
170
171 JSValue* toJS(ExecState* exec, ProfileNode* ProfileNode)
172 {
173     if (!ProfileNode)
174         return jsNull();
175
176     JSValue* ProfileNodeWrapper = ProfileNodeCache().get(ProfileNode);
177     if (ProfileNodeWrapper)
178         return ProfileNodeWrapper;
179
180     ProfileNode->ref();
181
182     ProfileNodeWrapper = toJS(JSObjectMake(toRef(exec), ProfileNodeClass(), static_cast<void*>(ProfileNode)));
183     ProfileNodeCache().set(ProfileNode, ProfileNodeWrapper);
184     return ProfileNodeWrapper;
185
186 }
187
188
189 } // namespace WebCore