[JSC] NativeErrorConstructor should not have own IsoSubspace
[WebKit-https.git] / Source / JavaScriptCore / runtime / Error.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
4  *  Copyright (C) 2003-2017 Apple Inc. All rights reserved.
5  *  Copyright (C) 2007 Eric Seidel (eric@webkit.org)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "Error.h"
26
27 #include "ConstructData.h"
28 #include "ErrorConstructor.h"
29 #include "ExceptionHelpers.h"
30 #include "FunctionPrototype.h"
31 #include "Interpreter.h"
32 #include "JSArray.h"
33 #include "JSCInlines.h"
34 #include "JSFunction.h"
35 #include "JSGlobalObject.h"
36 #include "JSObject.h"
37 #include "JSString.h"
38 #include "NativeErrorConstructor.h"
39 #include "SourceCode.h"
40 #include "StackFrame.h"
41 #include "SuperSampler.h"
42
43 namespace JSC {
44
45 JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
46 {
47     ASSERT(!message.isEmpty());
48     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
49     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true);
50 }
51
52 JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
53 {
54     ASSERT(!message.isEmpty());
55     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
56     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::EvalError), message, appender, TypeNothing, true);
57 }
58
59 JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
60 {
61     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
62     return createRangeError(exec, globalObject, message, appender);
63 }
64
65 JSObject* createRangeError(ExecState* exec, JSGlobalObject* globalObject, const String& message, ErrorInstance::SourceAppender appender)
66 {
67     ASSERT(!message.isEmpty());
68     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::RangeError), message, appender, TypeNothing, true);
69 }
70
71 JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
72 {
73     ASSERT(!message.isEmpty());
74     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
75     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::ReferenceError), message, appender, TypeNothing, true);
76 }
77
78 JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
79 {
80     ASSERT(!message.isEmpty());
81     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
82     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::SyntaxError), message, appender, TypeNothing, true);
83 }
84
85 JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type)
86 {
87     ASSERT(!message.isEmpty());
88     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
89     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::TypeError), message, appender, type, true);
90 }
91
92 JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender)
93 {
94     return createTypeError(exec, "Not enough arguments"_s, appender, TypeNothing);
95 }
96
97 JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
98 {
99     ASSERT(!message.isEmpty());
100     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
101     return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(ErrorType::URIError), message, appender, TypeNothing, true);
102 }
103
104 JSObject* createError(ExecState* exec, ErrorType errorType, const String& message)
105 {
106     switch (errorType) {
107     case ErrorType::Error:
108         return createError(exec, message);
109     case ErrorType::EvalError:
110         return createEvalError(exec, message);
111     case ErrorType::RangeError:
112         return createRangeError(exec, message);
113     case ErrorType::ReferenceError:
114         return createReferenceError(exec, message);
115     case ErrorType::SyntaxError:
116         return createSyntaxError(exec, message);
117     case ErrorType::TypeError:
118         return createTypeError(exec, message);
119     case ErrorType::URIError:
120         return createURIError(exec, message);
121     }
122     ASSERT_NOT_REACHED();
123     return nullptr;
124 }
125
126 class FindFirstCallerFrameWithCodeblockFunctor {
127 public:
128     FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
129         : m_startCallFrame(startCallFrame)
130         , m_foundCallFrame(nullptr)
131         , m_foundStartCallFrame(false)
132         , m_index(0)
133     { }
134
135     StackVisitor::Status operator()(StackVisitor& visitor) const
136     {
137         if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
138             m_foundStartCallFrame = true;
139
140         if (m_foundStartCallFrame) {
141             if (visitor->callFrame()->codeBlock()) {
142                 m_foundCallFrame = visitor->callFrame();
143                 return StackVisitor::Done;
144             }
145             m_index++;
146         }
147
148         return StackVisitor::Continue;
149     }
150
151     CallFrame* foundCallFrame() const { return m_foundCallFrame; }
152     unsigned index() const { return m_index; }
153
154 private:
155     CallFrame* m_startCallFrame;
156     mutable CallFrame* m_foundCallFrame;
157     mutable bool m_foundStartCallFrame;
158     mutable unsigned m_index;
159 };
160
161 std::unique_ptr<Vector<StackFrame>> getStackTrace(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame)
162 {
163     JSGlobalObject* globalObject = obj->globalObject(vm);
164     if (!globalObject->stackTraceLimit())
165         return nullptr;
166
167     size_t framesToSkip = useCurrentFrame ? 0 : 1;
168     std::unique_ptr<Vector<StackFrame>> stackTrace = std::make_unique<Vector<StackFrame>>();
169     vm.interpreter->getStackTrace(obj, *stackTrace, framesToSkip, globalObject->stackTraceLimit().value());
170     if (!stackTrace->isEmpty())
171         ASSERT_UNUSED(exec, exec == vm.topCallFrame || exec->isGlobalExec());
172     return stackTrace;
173 }
174
175 void getBytecodeOffset(ExecState* exec, VM& vm, Vector<StackFrame>* stackTrace, CallFrame*& callFrame, unsigned& bytecodeOffset)
176 {
177     FindFirstCallerFrameWithCodeblockFunctor functor(exec);
178     StackVisitor::visit(vm.topCallFrame, &vm, functor);
179     callFrame = functor.foundCallFrame();
180     unsigned stackIndex = functor.index();
181     bytecodeOffset = 0;
182     if (stackTrace && stackIndex < stackTrace->size() && stackTrace->at(stackIndex).hasBytecodeOffset())
183         bytecodeOffset = stackTrace->at(stackIndex).bytecodeOffset();
184 }
185
186 bool getLineColumnAndSource(Vector<StackFrame>* stackTrace, unsigned& line, unsigned& column, String& sourceURL)
187 {
188     line = 0;
189     column = 0;
190     sourceURL = String();
191     
192     if (!stackTrace)
193         return false;
194     
195     for (unsigned i = 0 ; i < stackTrace->size(); ++i) {
196         StackFrame& frame = stackTrace->at(i);
197         if (frame.hasLineAndColumnInfo()) {
198             frame.computeLineAndColumn(line, column);
199             sourceURL = frame.sourceURL();
200             return true;
201         }
202     }
203     
204     return false;
205 }
206
207 bool addErrorInfo(VM& vm, Vector<StackFrame>* stackTrace, JSObject* obj)
208 {
209     if (!stackTrace)
210         return false;
211
212     if (!stackTrace->isEmpty()) {
213         unsigned line;
214         unsigned column;
215         String sourceURL;
216         getLineColumnAndSource(stackTrace, line, column, sourceURL);
217         obj->putDirect(vm, vm.propertyNames->line, jsNumber(line));
218         obj->putDirect(vm, vm.propertyNames->column, jsNumber(column));
219         if (!sourceURL.isEmpty())
220             obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, sourceURL));
221
222         obj->putDirect(vm, vm.propertyNames->stack, jsString(&vm, Interpreter::stackTraceAsString(vm, *stackTrace)), static_cast<unsigned>(PropertyAttribute::DontEnum));
223
224         return true;
225     }
226
227     obj->putDirect(vm, vm.propertyNames->stack, vm.smallStrings.emptyString(), static_cast<unsigned>(PropertyAttribute::DontEnum));
228     return false;
229 }
230
231 void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame)
232 {
233     VM& vm = exec->vm();
234     std::unique_ptr<Vector<StackFrame>> stackTrace = getStackTrace(exec, vm, obj, useCurrentFrame);
235     addErrorInfo(vm, stackTrace.get(), obj);
236 }
237
238 JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source)
239 {
240     VM& vm = callFrame->vm();
241     const String& sourceURL = source.provider()->url();
242     
243     // The putDirect() calls below should really be put() so that they trigger materialization of
244     // the line/sourceURL properties. Otherwise, what we set here will just be overwritten later.
245     // But calling put() would be bad because we'd rather not do effectful things here. Luckily, we
246     // know that this will get called on some kind of error - so we can just directly ask the
247     // ErrorInstance to materialize whatever it needs to. There's a chance that we get passed some
248     // other kind of object, which also has materializable properties. But this code is heuristic-ey
249     // enough that if we're wrong in such corner cases, it's not the end of the world.
250     if (ErrorInstance* errorInstance = jsDynamicCast<ErrorInstance*>(vm, error))
251         errorInstance->materializeErrorInfoIfNeeded(vm);
252     
253     // FIXME: This does not modify the column property, which confusingly continues to reflect
254     // the column at which the exception was thrown.
255     // https://bugs.webkit.org/show_bug.cgi?id=176673
256     if (line != -1)
257         error->putDirect(vm, vm.propertyNames->line, jsNumber(line));
258     if (!sourceURL.isNull())
259         error->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, sourceURL));
260     return error;
261 }
262
263 JSObject* throwConstructorCannotBeCalledAsFunctionTypeError(ExecState* exec, ThrowScope& scope, const char* constructorName)
264 {
265     return throwTypeError(exec, scope, makeString("calling ", constructorName, " constructor without new is invalid"));
266 }
267
268 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope)
269 {
270     return throwException(exec, scope, createTypeError(exec));
271 }
272
273 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, ASCIILiteral errorMessage)
274 {
275     return throwTypeError(exec, scope, String(errorMessage));
276 }
277
278 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, const String& message)
279 {
280     return throwException(exec, scope, createTypeError(exec, message));
281 }
282
283 JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope)
284 {
285     return throwException(exec, scope, createSyntaxError(exec, "Syntax error"_s));
286 }
287
288 JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope, const String& message)
289 {
290     return throwException(exec, scope, createSyntaxError(exec, message));
291 }
292
293 JSValue throwDOMAttributeGetterTypeError(ExecState* exec, ThrowScope& scope, const ClassInfo* classInfo, PropertyName propertyName)
294 {
295     return throwTypeError(exec, scope, makeString("The ", classInfo->className, '.', String(propertyName.uid()), " getter can only be used on instances of ", classInfo->className));
296 }
297
298 JSObject* createError(ExecState* exec, const String& message)
299 {
300     return createError(exec, message, nullptr);
301 }
302
303 JSObject* createEvalError(ExecState* exec, const String& message)
304 {
305     return createEvalError(exec, message, nullptr);
306 }
307
308 JSObject* createRangeError(ExecState* exec, const String& message)
309 {
310     return createRangeError(exec, message, nullptr);
311 }
312
313 JSObject* createRangeError(ExecState* exec, JSGlobalObject* globalObject, const String& message)
314 {
315     return createRangeError(exec, globalObject, message, nullptr);
316 }
317
318 JSObject* createReferenceError(ExecState* exec, const String& message)
319 {
320     return createReferenceError(exec, message, nullptr);
321 }
322
323 JSObject* createSyntaxError(ExecState* exec, const String& message)
324 {
325     return createSyntaxError(exec, message, nullptr);
326 }
327
328 JSObject* createTypeError(ExecState* exec)
329 {
330     return createTypeError(exec, "Type error"_s);
331 }
332
333 JSObject* createTypeError(ExecState* exec, const String& message)
334 {
335     return createTypeError(exec, message, nullptr, TypeNothing);
336 }
337
338 JSObject* createNotEnoughArgumentsError(ExecState* exec)
339 {
340     return createNotEnoughArgumentsError(exec, nullptr);
341 }
342
343 JSObject* createURIError(ExecState* exec, const String& message)
344 {
345     return createURIError(exec, message, nullptr);
346 }
347
348 JSObject* createOutOfMemoryError(ExecState* exec)
349 {
350     auto* error = createError(exec, "Out of memory"_s, nullptr);
351     jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
352     return error;
353 }
354
355 JSObject* createOutOfMemoryError(ExecState* exec, const String& message)
356 {
357     
358     auto* error = createError(exec, makeString("Out of memory: ", message), nullptr);
359     jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
360     return error;
361 }
362
363 } // namespace JSC