2010-10-13 Yury Semikhatsky <yurys@chromium.org>
[WebKit-https.git] / WebCore / bindings / v8 / ScriptCallStack.cpp
1 /*
2  * Copyright (C) 2008, 2009 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "ScriptCallStack.h"
33
34 #include "InspectorValues.h"
35 #include "ScriptController.h"
36 #include "ScriptDebugServer.h"
37 #include "ScriptScope.h"
38 #include "V8Binding.h"
39
40 #include <v8-debug.h>
41
42 namespace WebCore {
43
44 static void getFrameLocation(v8::Handle<v8::StackFrame> frame, String* sourceName, int* sourceLineNumber, String* functionName)
45 {
46     ASSERT(!frame.IsEmpty());
47     v8::Local<v8::String> sourceNameValue(frame->GetScriptNameOrSourceURL());
48     v8::Local<v8::String> functionNameValue(frame->GetFunctionName());
49     *sourceName = sourceNameValue.IsEmpty() ? "" : toWebCoreString(sourceNameValue);
50     *functionName = functionNameValue.IsEmpty() ? "" : toWebCoreString(functionNameValue);
51     *sourceLineNumber = frame->GetLineNumber();
52 }
53
54 static void getTopFrameLocation(v8::Handle<v8::StackTrace> stackTrace, String* sourceName, int* sourceLineNumber, String* functionName)
55 {
56     if (stackTrace->GetFrameCount() <= 0) {
57         // Successfully grabbed stack trace, but there are no frames. It may happen in case of a syntax error for example.
58         // Fallback to setting lineNumber to 0, and source and function name to "undefined".
59         *sourceName = "undefined";
60         *sourceLineNumber = 0;
61         *functionName = "undefined";
62     } else {
63         v8::Handle<v8::StackFrame> frame = stackTrace->GetFrame(0);
64         getFrameLocation(frame, sourceName, sourceLineNumber, functionName);
65     }
66 }
67
68 static PassOwnPtr<ScriptCallFrame> toScriptCallFrame(v8::Handle<v8::StackFrame> frame)
69 {
70     String sourceName;
71     int sourceLineNumber;
72     String functionName;
73     getFrameLocation(frame, &sourceName, &sourceLineNumber, &functionName);
74     return new ScriptCallFrame(functionName, sourceName, sourceLineNumber);
75 }
76
77 static void toScriptCallFramesVector(v8::Local<v8::Context> context, v8::Handle<v8::StackTrace> stackTrace, Vector<OwnPtr<ScriptCallFrame> >& scriptCallFrames)
78 {
79     v8::Context::Scope contextScope(context);
80     int frameCount = stackTrace->GetFrameCount();
81     for (int i = 0; i < frameCount; i++) {
82         v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i);
83         scriptCallFrames.append(toScriptCallFrame(stackFrame));
84     }
85 }
86
87 const int ScriptCallStack::maxCallStackSizeToCapture = 200;
88 const v8::StackTrace::StackTraceOptions ScriptCallStack::stackTraceOptions = static_cast<v8::StackTrace::StackTraceOptions>(
89      v8::StackTrace::kLineNumber
90     | v8::StackTrace::kColumnOffset
91     | v8::StackTrace::kScriptNameOrSourceURL
92     | v8::StackTrace::kFunctionName);
93
94
95 PassOwnPtr<ScriptCallStack> ScriptCallStack::create(const v8::Arguments& arguments, unsigned skipArgumentCount, int framCountLimit)
96 {
97     v8::HandleScope scope;
98     v8::Local<v8::Context> context = v8::Context::GetCurrent();
99     v8::Context::Scope contextScope(context);
100     v8::Handle<v8::StackTrace> stackTrace(v8::StackTrace::CurrentStackTrace(framCountLimit, ScriptCallStack::stackTraceOptions));
101
102     if (stackTrace.IsEmpty())
103         return 0;
104
105     String sourceName;
106     int sourceLineNumber;
107     String functionName;
108     getTopFrameLocation(stackTrace, &sourceName, &sourceLineNumber, &functionName);
109
110     Vector<OwnPtr<ScriptCallFrame> > scriptCallFrames;
111     if (framCountLimit > 1)
112         toScriptCallFramesVector(context, stackTrace, scriptCallFrames);
113
114     return new ScriptCallStack(ScriptState::forContext(context), new ScriptCallFrame(functionName, sourceName, sourceLineNumber, arguments, skipArgumentCount), scriptCallFrames);
115 }
116
117 PassOwnPtr<ScriptCallStack> ScriptCallStack::create(ScriptState* state, v8::Handle<v8::StackTrace> stackTrace)
118 {
119     v8::HandleScope scope;
120     Vector<OwnPtr<ScriptCallFrame> > scriptCallFrames;
121     toScriptCallFramesVector(state->context(), stackTrace, scriptCallFrames);
122
123     String sourceName;
124     int sourceLineNumber;
125     String functionName;
126     getTopFrameLocation(stackTrace, &sourceName, &sourceLineNumber, &functionName);
127
128     return new ScriptCallStack(state, new ScriptCallFrame(functionName, sourceName, sourceLineNumber), scriptCallFrames);
129 }
130
131 ScriptCallStack::ScriptCallStack(ScriptState* scriptState, PassOwnPtr<ScriptCallFrame> topFrame, Vector<OwnPtr<ScriptCallFrame> >& scriptCallFrames)
132     : m_topFrame(topFrame)
133     , m_scriptState(scriptState)
134 {
135     m_scriptCallFrames.swap(scriptCallFrames);
136 }
137
138 ScriptCallStack::~ScriptCallStack()
139 {
140 }
141
142 const ScriptCallFrame& ScriptCallStack::at(unsigned index)
143 {
144     if (!index && m_topFrame)
145         return *m_topFrame;
146     return *m_scriptCallFrames.at(index);
147 }
148
149 unsigned ScriptCallStack::size()
150 {
151     if (m_scriptCallFrames.isEmpty())
152         return 1;
153     return m_scriptCallFrames.size();
154 }
155
156
157 bool ScriptCallStack::stackTrace(int frameLimit, const RefPtr<InspectorArray>& stackTrace)
158 {
159 #if ENABLE(INSPECTOR)
160     if (!v8::Context::InContext())
161         return false;
162     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
163     if (context.IsEmpty())
164         return false;
165     v8::HandleScope scope;
166     v8::Context::Scope contextScope(context);
167     v8::Handle<v8::StackTrace> trace(v8::StackTrace::CurrentStackTrace(frameLimit));
168     int frameCount = trace->GetFrameCount();
169     if (trace.IsEmpty() || !frameCount)
170         return false;
171     for (int i = 0; i < frameCount; ++i) {
172         v8::Handle<v8::StackFrame> frame = trace->GetFrame(i);
173         RefPtr<InspectorObject> frameObject = InspectorObject::create();
174         v8::Local<v8::String> scriptName = frame->GetScriptName();
175         frameObject->setString("scriptName", scriptName.IsEmpty() ? "" : toWebCoreString(scriptName));
176         v8::Local<v8::String> functionName = frame->GetFunctionName();
177         frameObject->setString("functionName", functionName.IsEmpty() ? "" : toWebCoreString(functionName));
178         frameObject->setNumber("lineNumber", frame->GetLineNumber());
179         frameObject->setNumber("column", frame->GetColumn());
180         stackTrace->pushObject(frameObject);
181     }
182     return true;
183 #else
184     return false;
185 #endif
186 }
187
188 } // namespace WebCore