JavaScriptCore:
[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 void finalize(JSObjectRef object)
167 {
168     ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(object));
169     ProfileNodeCache().remove(profileNode);
170     profileNode->deref();
171 }
172
173 JSClassRef ProfileNodeClass()
174 {
175     static JSStaticValue staticValues[] = {
176         { "functionName", getFunctionName, 0, kJSPropertyAttributeNone },
177         { "totalTime", getTotalTime, 0, kJSPropertyAttributeNone },
178         { "selfTime", getSelfTime, 0, kJSPropertyAttributeNone },
179         { "totalPercent", getTotalPercent, 0, kJSPropertyAttributeNone },
180         { "selfPercent", getSelfPercent, 0, kJSPropertyAttributeNone },
181         { "numberOfCalls", getNumberOfCalls, 0, kJSPropertyAttributeNone },
182         { "children", getChildren, 0, kJSPropertyAttributeNone },
183         { 0, 0, 0, 0 }
184     };
185
186     static JSClassDefinition classDefinition = {
187         0, kJSClassAttributeNone, "ProfileNode", 0, staticValues, 0,
188         0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0
189     };
190
191     static JSClassRef ProfileNodeClass = JSClassCreate(&classDefinition);
192     return ProfileNodeClass;
193 }
194
195 JSValue* toJS(ExecState* exec, ProfileNode* ProfileNode)
196 {
197     if (!ProfileNode)
198         return jsNull();
199
200     JSValue* ProfileNodeWrapper = ProfileNodeCache().get(ProfileNode);
201     if (ProfileNodeWrapper)
202         return ProfileNodeWrapper;
203
204     ProfileNode->ref();
205
206     ProfileNodeWrapper = toJS(JSObjectMake(toRef(exec), ProfileNodeClass(), static_cast<void*>(ProfileNode)));
207     ProfileNodeCache().set(ProfileNode, ProfileNodeWrapper);
208     return ProfileNodeWrapper;
209 }
210
211
212 } // namespace WebCore