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