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) && USE(JSC) 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 50 static ProfileNodeMap& profileNodeCache() 51 { 52 DEFINE_STATIC_LOCAL(ProfileNodeMap, staticProfileNodes, ()); 53 return staticProfileNodes; 54 } 55 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 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 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 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 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 107 static JSValueRef getNumberOfCalls(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->numberOfCalls()); 116 } 117 118 static JSValueRef getChildren(JSContextRef ctx, JSObjectRef thisObject, JSStringRef, JSValueRef* exception) 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 const Vector<RefPtr<ProfileNode> >& children = profileNode->children(); 127 128 JSObjectRef global = JSContextGetGlobalObject(ctx); 129 130 JSRetainPtr<JSStringRef> arrayString(Adopt, JSStringCreateWithUTF8CString("Array")); 131 132 JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, arrayString.get(), exception); 133 if (exception && *exception) 134 return JSValueMakeUndefined(ctx); 135 136 JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception); 137 if (exception && *exception) 138 return JSValueMakeUndefined(ctx); 139 140 JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception); 141 if (exception && *exception) 142 return JSValueMakeUndefined(ctx); 143 144 JSRetainPtr<JSStringRef> pushString(Adopt, JSStringCreateWithUTF8CString("push")); 145 146 JSValueRef pushProperty = JSObjectGetProperty(ctx, result, pushString.get(), exception); 147 if (exception && *exception) 148 return JSValueMakeUndefined(ctx); 149 150 JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception); 151 if (exception && *exception) 152 return JSValueMakeUndefined(ctx); 153 154 ExecState* exec = toJS(ctx); 155 for (Vector<RefPtr<ProfileNode> >::const_iterator it = children.begin(); it != children.end(); ++it) { 156 JSValueRef arg0 = toRef(exec, toJS(exec, (*it).get() )); 157 JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception); 158 if (exception && *exception) 159 return JSValueMakeUndefined(ctx); 160 } 161 162 return result; 163 } 164 165 static JSValueRef getVisible(JSContextRef ctx, JSObjectRef thisObject, JSStringRef, JSValueRef*) 166 { 167 JSC::JSLock lock(SilenceAssertionsOnly); 168 169 if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass())) 170 return JSValueMakeUndefined(ctx); 171 172 ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject)); 173 return JSValueMakeBoolean(ctx, profileNode->visible()); 174 } 175 176 static JSValueRef getCallUID(JSContextRef ctx, JSObjectRef thisObject, JSStringRef, JSValueRef*) 177 { 178 JSC::JSLock lock(SilenceAssertionsOnly); 179 180 if (!JSValueIsObjectOfClass(ctx, thisObject, ProfileNodeClass())) 181 return JSValueMakeUndefined(ctx); 182 183 ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(thisObject)); 184 return JSValueMakeNumber(ctx, profileNode->callIdentifier().hash()); 185 } 186 187 static void finalize(JSObjectRef object) 188 { 189 ProfileNode* profileNode = static_cast<ProfileNode*>(JSObjectGetPrivate(object)); 190 profileNodeCache().remove(profileNode); 191 profileNode->deref(); 192 } 193 194 JSClassRef ProfileNodeClass() 195 { 196 static JSStaticValue staticValues[] = { 197 { "functionName", getFunctionName, 0, kJSPropertyAttributeNone }, 198 { "url", getURL, 0, kJSPropertyAttributeNone }, 199 { "lineNumber", getLineNumber, 0, kJSPropertyAttributeNone }, 200 { "totalTime", getTotalTime, 0, kJSPropertyAttributeNone }, 201 { "selfTime", getSelfTime, 0, kJSPropertyAttributeNone }, 202 { "numberOfCalls", getNumberOfCalls, 0, kJSPropertyAttributeNone }, 203 { "children", getChildren, 0, kJSPropertyAttributeNone }, 204 { "visible", getVisible, 0, kJSPropertyAttributeNone }, 205 { "callUID", getCallUID, 0, kJSPropertyAttributeNone }, 206 { 0, 0, 0, 0 } 207 }; 208 209 static JSClassDefinition classDefinition = { 210 0, kJSClassAttributeNone, "ProfileNode", 0, staticValues, 0, 211 0, finalize, 0, 0, 0, 0, 0, 0, 0, 0, 0 212 }; 213 214 static JSClassRef profileNodeClass = JSClassCreate(&classDefinition); 215 return profileNodeClass; 216 } 217 218 JSValue toJS(ExecState* exec, ProfileNode* profileNode) 219 { 220 if (!profileNode) 221 return jsNull(); 222 223 JSObject* profileNodeWrapper = profileNodeCache().get(profileNode); 224 if (profileNodeWrapper) 225 return profileNodeWrapper; 226 227 profileNode->ref(); 228 229 profileNodeWrapper = toJS(JSObjectMake(toRef(exec), ProfileNodeClass(), static_cast<void*>(profileNode))); 230 profileNodeCache().set(profileNode, profileNodeWrapper); 231 return profileNodeWrapper; 232 } 233 234 } // namespace WebCore 235 236 #endif // ENABLE(JAVASCRIPT_DEBUGGER) 237