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 "Exception.h"
38 #include "JSCJSValue.h"
39 #include "JSCInlines.h"
40 #include "ScriptArguments.h"
41 #include "ScriptCallFrame.h"
42 #include "ScriptCallStack.h"
43 #include "ScriptValue.h"
44 #include "StackVisitor.h"
45 #include <wtf/RefCountedArray.h>
46 #include <wtf/text/WTFString.h>
52 class CreateScriptCallStackFunctor
{
54 CreateScriptCallStackFunctor(bool needToSkipAFrame
, Vector
<ScriptCallFrame
>& frames
, size_t remainingCapacity
)
55 : m_needToSkipAFrame(needToSkipAFrame
)
57 , m_remainingCapacityForFrameCapture(remainingCapacity
)
61 StackVisitor::Status
operator()(StackVisitor
& visitor
)
63 if (m_needToSkipAFrame
) {
64 m_needToSkipAFrame
= false;
65 return StackVisitor::Continue
;
68 if (m_remainingCapacityForFrameCapture
) {
71 visitor
->computeLineAndColumn(line
, column
);
72 m_frames
.append(ScriptCallFrame(visitor
->functionName(), visitor
->sourceURL(), line
, column
));
74 m_remainingCapacityForFrameCapture
--;
75 return StackVisitor::Continue
;
78 return StackVisitor::Done
;
82 bool m_needToSkipAFrame
;
83 Vector
<ScriptCallFrame
>& m_frames
;
84 size_t m_remainingCapacityForFrameCapture
;
87 Ref
<ScriptCallStack
> createScriptCallStack(JSC::ExecState
* exec
, size_t maxStackSize
)
90 return ScriptCallStack::create();
92 Vector
<ScriptCallFrame
> frames
;
94 CallFrame
* frame
= exec
->vm().topCallFrame
;
95 CreateScriptCallStackFunctor
functor(false, frames
, maxStackSize
);
96 frame
->iterate(functor
);
98 return ScriptCallStack::create(frames
);
101 Ref
<ScriptCallStack
> createScriptCallStackForConsole(JSC::ExecState
* exec
, size_t maxStackSize
)
104 return ScriptCallStack::create();
106 Vector
<ScriptCallFrame
> frames
;
108 CallFrame
* frame
= exec
->vm().topCallFrame
;
109 CreateScriptCallStackFunctor
functor(true, frames
, maxStackSize
);
110 frame
->iterate(functor
);
112 if (frames
.isEmpty()) {
113 CreateScriptCallStackFunctor
functor(false, frames
, maxStackSize
);
114 frame
->iterate(functor
);
117 return ScriptCallStack::create(frames
);
120 static void extractSourceInformationFromException(JSC::ExecState
* exec
, JSObject
* exceptionObject
, int* lineNumber
, int* columnNumber
, String
* sourceURL
)
122 // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not need to evaluate JavaScript handling exceptions
123 JSValue lineValue
= exceptionObject
->getDirect(exec
->vm(), Identifier::fromString(exec
, "line"));
124 *lineNumber
= lineValue
&& lineValue
.isNumber() ? int(lineValue
.toNumber(exec
)) : 0;
125 JSValue columnValue
= exceptionObject
->getDirect(exec
->vm(), Identifier::fromString(exec
, "column"));
126 *columnNumber
= columnValue
&& columnValue
.isNumber() ? int(columnValue
.toNumber(exec
)) : 0;
127 JSValue sourceURLValue
= exceptionObject
->getDirect(exec
->vm(), Identifier::fromString(exec
, "sourceURL"));
128 *sourceURL
= sourceURLValue
&& sourceURLValue
.isString() ? sourceURLValue
.toString(exec
)->value(exec
) : ASCIILiteral("undefined");
129 exec
->clearException();
132 Ref
<ScriptCallStack
> createScriptCallStackFromException(JSC::ExecState
* exec
, JSC::Exception
* exception
, size_t maxStackSize
)
134 Vector
<ScriptCallFrame
> frames
;
135 RefCountedArray
<StackFrame
> stackTrace
= exception
->stack();
136 for (size_t i
= 0; i
< stackTrace
.size() && i
< maxStackSize
; i
++) {
139 stackTrace
[i
].computeLineAndColumn(line
, column
);
140 String functionName
= stackTrace
[i
].friendlyFunctionName(exec
);
141 frames
.append(ScriptCallFrame(functionName
, stackTrace
[i
].friendlySourceURL(), line
, column
));
144 // Fallback to getting at least the line and sourceURL from the exception object if it has values and the exceptionStack doesn't.
145 if (exception
->value().isObject()) {
146 JSObject
* exceptionObject
= exception
->value().toObject(exec
);
149 String exceptionSourceURL
;
150 if (!frames
.size()) {
151 extractSourceInformationFromException(exec
, exceptionObject
, &lineNumber
, &columnNumber
, &exceptionSourceURL
);
152 frames
.append(ScriptCallFrame(String(), exceptionSourceURL
, lineNumber
, columnNumber
));
154 if (stackTrace
[0].sourceURL
.isEmpty()) {
155 const ScriptCallFrame
& firstCallFrame
= frames
.first();
156 extractSourceInformationFromException(exec
, exceptionObject
, &lineNumber
, &columnNumber
, &exceptionSourceURL
);
157 frames
[0] = ScriptCallFrame(firstCallFrame
.functionName(), exceptionSourceURL
, lineNumber
, columnNumber
);
162 return ScriptCallStack::create(frames
);
165 Ref
<ScriptArguments
> createScriptArguments(JSC::ExecState
* exec
, unsigned skipArgumentCount
)
167 Vector
<Deprecated::ScriptValue
> arguments
;
168 size_t argumentCount
= exec
->argumentCount();
169 for (size_t i
= skipArgumentCount
; i
< argumentCount
; ++i
)
170 arguments
.append(Deprecated::ScriptValue(exec
->vm(), exec
->uncheckedArgument(i
)));
171 return ScriptArguments::create(exec
, arguments
);
174 } // namespace Inspector