]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/ErrorInstance.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / ErrorInstance.cpp
CommitLineData
b37bf2e1 1/*
9dae56ea
A
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
b37bf2e1
A
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
9dae56ea
A
21#include "config.h"
22#include "ErrorInstance.h"
b37bf2e1 23
93a37866 24#include "JSScope.h"
81345200 25#include "JSCInlines.h"
ed1e77d3
A
26#include "JSGlobalObjectFunctions.h"
27#include <wtf/Vector.h>
93a37866 28
9dae56ea 29namespace JSC {
b37bf2e1 30
81345200 31STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(ErrorInstance);
b37bf2e1 32
ed1e77d3 33const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, CREATE_METHOD_TABLE(ErrorInstance) };
14957cd0 34
93a37866
A
35ErrorInstance::ErrorInstance(VM& vm, Structure* structure)
36 : JSNonFinalObject(vm, structure)
14957cd0 37{
9dae56ea 38}
b37bf2e1 39
ed1e77d3
A
40static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
41{
42 ErrorInstance::SourceAppender appender = exception->sourceAppender();
43 exception->clearSourceAppender();
44 RuntimeType type = exception->runtimeTypeForCause();
45 exception->clearRuntimeTypeForCause();
46
47 if (!callFrame->codeBlock()->hasExpressionInfo())
48 return;
49
50 int startOffset = 0;
51 int endOffset = 0;
52 int divotPoint = 0;
53 unsigned line = 0;
54 unsigned column = 0;
55
56 CodeBlock* codeBlock = callFrame->codeBlock();
57 codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column);
58
59 int expressionStart = divotPoint - startOffset;
60 int expressionStop = divotPoint + endOffset;
61
62 const String& sourceString = codeBlock->source()->source();
63 if (!expressionStop || expressionStart > static_cast<int>(sourceString.length()))
64 return;
65
66 VM* vm = &callFrame->vm();
67 JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message);
68 if (!jsMessage || !jsMessage.isString())
69 return;
70
71 String message = asString(jsMessage)->value(callFrame);
72 if (expressionStart < expressionStop)
73 message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop) , type, ErrorInstance::FoundExactSource);
74 else {
75 // No range information, so give a few characters of context.
76 const StringImpl* data = sourceString.impl();
77 int dataLength = sourceString.length();
78 int start = expressionStart;
79 int stop = expressionStart;
80 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
81 // Then strip whitespace.
82 while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')
83 start--;
84 while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start]))
85 start++;
86 while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')
87 stop++;
88 while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1]))
89 stop--;
90 message = appender(message, codeBlock->source()->getRange(start, stop), type, ErrorInstance::FoundApproximateSource);
91 }
92 exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
93
94}
95
96class FindFirstCallerFrameWithCodeblockFunctor {
97public:
98 FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
99 : m_startCallFrame(startCallFrame)
100 , m_foundCallFrame(nullptr)
101 , m_foundStartCallFrame(false)
102 , m_index(0)
103 { }
104
105 StackVisitor::Status operator()(StackVisitor& visitor)
106 {
107 if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
108 m_foundStartCallFrame = true;
109
110 if (m_foundStartCallFrame) {
111 if (visitor->callFrame()->codeBlock()) {
112 m_foundCallFrame = visitor->callFrame();
113 return StackVisitor::Done;
114 }
115 m_index++;
116 }
117
118 return StackVisitor::Continue;
119 }
120
121 CallFrame* foundCallFrame() const { return m_foundCallFrame; }
122 unsigned index() const { return m_index; }
123
124private:
125 CallFrame* m_startCallFrame;
126 CallFrame* m_foundCallFrame;
127 bool m_foundStartCallFrame;
128 unsigned m_index;
129};
130
131static bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset)
132{
133 Vector<StackFrame> stackTrace = Vector<StackFrame>();
134
135 if (exec && stackTrace.isEmpty())
136 vm.interpreter->getStackTrace(stackTrace);
137
138 if (!stackTrace.isEmpty()) {
139
140 ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
141
142 StackFrame* stackFrame;
143 for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
144 stackFrame = &stackTrace.at(i);
145 if (stackFrame->bytecodeOffset)
146 break;
147 }
148
149 if (bytecodeOffset) {
150 FindFirstCallerFrameWithCodeblockFunctor functor(exec);
151 vm.topCallFrame->iterate(functor);
152 callFrame = functor.foundCallFrame();
153 unsigned stackIndex = functor.index();
154 bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
155 }
156
157 unsigned line;
158 unsigned column;
159 stackFrame->computeLineAndColumn(line, column);
160 obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete);
161 obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete);
162
163 if (!stackFrame->sourceURL.isEmpty())
164 obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete);
165
166 if (!useCurrentFrame)
167 stackTrace.remove(0);
168 obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
169
170 return true;
171 }
172 return false;
173}
174
175void ErrorInstance::finishCreation(ExecState* exec, VM& vm, const String& message, bool useCurrentFrame)
81345200
A
176{
177 Base::finishCreation(vm);
178 ASSERT(inherits(info()));
179 if (!message.isNull())
180 putDirect(vm, vm.propertyNames->message, jsString(&vm, message), DontEnum);
ed1e77d3
A
181
182 unsigned bytecodeOffset = hasSourceAppender();
183 CallFrame* callFrame = nullptr;
184 bool hasTrace = addErrorInfoAndGetBytecodeOffset(exec, vm, this, useCurrentFrame, callFrame, bytecodeOffset);
185
186 if (hasTrace && callFrame && hasSourceAppender()) {
187 if (callFrame && callFrame->codeBlock())
188 appendSourceToError(callFrame, this, bytecodeOffset);
189 }
81345200
A
190}
191
9dae56ea 192} // namespace JSC