2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 * Copyright (c) 2010 Google Inc. All rights reserved.
4 * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "ScriptCallStackFactory.h"
36 #include "CallFrame.h"
37 #include "JSCJSValue.h"
38 #include "JSCInlines.h"
39 #include "ScriptArguments.h"
40 #include "ScriptCallFrame.h"
41 #include "ScriptCallStack.h"
42 #include "ScriptValue.h"
43 #include "StackVisitor.h"
44 #include <wtf/RefCountedArray.h>
45 #include <wtf/text/WTFString.h>
51 class CreateScriptCallStackFunctor
{
53 CreateScriptCallStackFunctor(bool needToSkipAFrame
, Vector
<ScriptCallFrame
>& frames
, size_t remainingCapacity
)
54 : m_needToSkipAFrame(needToSkipAFrame
)
56 , m_remainingCapacityForFrameCapture(remainingCapacity
)
60 StackVisitor::Status
operator()(StackVisitor
& visitor
)
62 if (m_needToSkipAFrame
) {
63 m_needToSkipAFrame
= false;
64 return StackVisitor::Continue
;
67 if (m_remainingCapacityForFrameCapture
) {
70 visitor
->computeLineAndColumn(line
, column
);
71 m_frames
.append(ScriptCallFrame(visitor
->functionName(), visitor
->sourceURL(), line
, column
));
73 m_remainingCapacityForFrameCapture
--;
74 return StackVisitor::Continue
;
77 return StackVisitor::Done
;
81 bool m_needToSkipAFrame
;
82 Vector
<ScriptCallFrame
>& m_frames
;
83 size_t m_remainingCapacityForFrameCapture
;
86 PassRefPtr
<ScriptCallStack
> createScriptCallStack(JSC::ExecState
* exec
, size_t maxStackSize
)
89 return ScriptCallStack::create();
91 Vector
<ScriptCallFrame
> frames
;
93 CallFrame
* frame
= exec
->vm().topCallFrame
;
94 CreateScriptCallStackFunctor
functor(false, frames
, maxStackSize
);
95 frame
->iterate(functor
);
97 return ScriptCallStack::create(frames
);
100 PassRefPtr
<ScriptCallStack
> createScriptCallStackForConsole(JSC::ExecState
* exec
, size_t maxStackSize
)
103 return ScriptCallStack::create();
105 Vector
<ScriptCallFrame
> frames
;
107 CallFrame
* frame
= exec
->vm().topCallFrame
;
108 CreateScriptCallStackFunctor
functor(true, frames
, maxStackSize
);
109 frame
->iterate(functor
);
111 if (frames
.isEmpty()) {
112 CreateScriptCallStackFunctor
functor(false, frames
, maxStackSize
);
113 frame
->iterate(functor
);
116 return ScriptCallStack::create(frames
);
119 static void extractSourceInformationFromException(JSC::ExecState
* exec
, JSObject
* exceptionObject
, int* lineNumber
, int* columnNumber
, String
* sourceURL
)
121 // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not need to evaluate JavaScript handling exceptions
122 JSValue lineValue
= exceptionObject
->getDirect(exec
->vm(), Identifier(exec
, "line"));
123 *lineNumber
= lineValue
&& lineValue
.isNumber() ? int(lineValue
.toNumber(exec
)) : 0;
124 JSValue columnValue
= exceptionObject
->getDirect(exec
->vm(), Identifier(exec
, "column"));
125 *columnNumber
= columnValue
&& columnValue
.isNumber() ? int(columnValue
.toNumber(exec
)) : 0;
126 JSValue sourceURLValue
= exceptionObject
->getDirect(exec
->vm(), Identifier(exec
, "sourceURL"));
127 *sourceURL
= sourceURLValue
&& sourceURLValue
.isString() ? sourceURLValue
.toString(exec
)->value(exec
) : String("undefined");
128 exec
->clearException();
131 PassRefPtr
<ScriptCallStack
> createScriptCallStackFromException(JSC::ExecState
* exec
, JSC::JSValue
& exception
, size_t maxStackSize
)
133 Vector
<ScriptCallFrame
> frames
;
134 RefCountedArray
<StackFrame
> stackTrace
= exec
->vm().exceptionStack();
135 for (size_t i
= 0; i
< stackTrace
.size() && i
< maxStackSize
; i
++) {
138 stackTrace
[i
].computeLineAndColumn(line
, column
);
139 String functionName
= stackTrace
[i
].friendlyFunctionName(exec
);
140 frames
.append(ScriptCallFrame(functionName
, stackTrace
[i
].friendlySourceURL(), line
, column
));
143 // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't.
144 JSObject
* exceptionObject
= exception
.toObject(exec
);
145 if (exception
.isObject()) {
148 String exceptionSourceURL
;
149 if (!frames
.size()) {
150 extractSourceInformationFromException(exec
, exceptionObject
, &lineNumber
, &columnNumber
, &exceptionSourceURL
);
151 frames
.append(ScriptCallFrame(String(), exceptionSourceURL
, lineNumber
, columnNumber
));
153 if (stackTrace
[0].sourceURL
.isEmpty()) {
154 const ScriptCallFrame
& firstCallFrame
= frames
.first();
155 extractSourceInformationFromException(exec
, exceptionObject
, &lineNumber
, &columnNumber
, &exceptionSourceURL
);
156 frames
[0] = ScriptCallFrame(firstCallFrame
.functionName(), exceptionSourceURL
, lineNumber
, columnNumber
);
161 return ScriptCallStack::create(frames
);
164 PassRefPtr
<ScriptArguments
> createScriptArguments(JSC::ExecState
* exec
, unsigned skipArgumentCount
)
166 Vector
<Deprecated::ScriptValue
> arguments
;
167 size_t argumentCount
= exec
->argumentCount();
168 for (size_t i
= skipArgumentCount
; i
< argumentCount
; ++i
)
169 arguments
.append(Deprecated::ScriptValue(exec
->vm(), exec
->uncheckedArgument(i
)));
170 return ScriptArguments::create(exec
, arguments
);
173 } // namespace Inspector