Move vmEntryGlobalObject() to VM from CallFrame.
[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->evalErrorConstructor()->errorStructure(), 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->rangeErrorConstructor()->errorStructure(), 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->referenceErrorConstructor()->errorStructure(), 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->syntaxErrorConstructor()->errorStructure(), 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->typeErrorConstructor()->errorStructure(), 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->URIErrorConstructor()->errorStructure(), 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     ErrorConstructor* errorConstructor = globalObject->errorConstructor();
165     if (!errorConstructor->stackTraceLimit())
166         return nullptr;
167
168     size_t framesToSkip = useCurrentFrame ? 0 : 1;
169     std::unique_ptr<Vector<StackFrame>> stackTrace = std::make_unique<Vector<StackFrame>>();
170     vm.interpreter->getStackTrace(obj, *stackTrace, framesToSkip, errorConstructor->stackTraceLimit().value());
171     if (!stackTrace->isEmpty())
172         ASSERT_UNUSED(exec, exec == vm.topCallFrame || exec->isGlobalExec());
173     return stackTrace;
174 }
175
176 void getBytecodeOffset(ExecState* exec, VM& vm, Vector<StackFrame>* stackTrace, CallFrame*& callFrame, unsigned& bytecodeOffset)
177 {
178     FindFirstCallerFrameWithCodeblockFunctor functor(exec);
179     StackVisitor::visit(vm.topCallFrame, &vm, functor);
180     callFrame = functor.foundCallFrame();
181     unsigned stackIndex = functor.index();
182     bytecodeOffset = 0;
183     if (stackTrace && stackIndex < stackTrace->size() && stackTrace->at(stackIndex).hasBytecodeOffset())
184         bytecodeOffset = stackTrace->at(stackIndex).bytecodeOffset();
185 }
186
187 bool getLineColumnAndSource(Vector<StackFrame>* stackTrace, unsigned& line, unsigned& column, String& sourceURL)
188 {
189     line = 0;
190     column = 0;
191     sourceURL = String();
192     
193     if (!stackTrace)
194         return false;
195     
196     for (unsigned i = 0 ; i < stackTrace->size(); ++i) {
197         StackFrame& frame = stackTrace->at(i);
198         if (frame.hasLineAndColumnInfo()) {
199             frame.computeLineAndColumn(line, column);
200             sourceURL = frame.sourceURL();
201             return true;
202         }
203     }
204     
205     return false;
206 }
207
208 bool addErrorInfo(VM& vm, Vector<StackFrame>* stackTrace, JSObject* obj)
209 {
210     if (!stackTrace)
211         return false;
212
213     if (!stackTrace->isEmpty()) {
214         unsigned line;
215         unsigned column;
216         String sourceURL;
217         getLineColumnAndSource(stackTrace, line, column, sourceURL);
218         obj->putDirect(vm, vm.propertyNames->line, jsNumber(line));
219         obj->putDirect(vm, vm.propertyNames->column, jsNumber(column));
220         if (!sourceURL.isEmpty())
221             obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, sourceURL));
222
223         obj->putDirect(vm, vm.propertyNames->stack, jsString(&vm, Interpreter::stackTraceAsString(vm, *stackTrace)), static_cast<unsigned>(PropertyAttribute::DontEnum));
224
225         return true;
226     }
227
228     obj->putDirect(vm, vm.propertyNames->stack, vm.smallStrings.emptyString(), static_cast<unsigned>(PropertyAttribute::DontEnum));
229     return false;
230 }
231
232 void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame)
233 {
234     VM& vm = exec->vm();
235     std::unique_ptr<Vector<StackFrame>> stackTrace = getStackTrace(exec, vm, obj, useCurrentFrame);
236     addErrorInfo(vm, stackTrace.get(), obj);
237 }
238
239 JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source)
240 {
241     VM& vm = callFrame->vm();
242     const String& sourceURL = source.provider()->url();
243     
244     // The putDirect() calls below should really be put() so that they trigger materialization of
245     // the line/sourceURL properties. Otherwise, what we set here will just be overwritten later.
246     // But calling put() would be bad because we'd rather not do effectful things here. Luckily, we
247     // know that this will get called on some kind of error - so we can just directly ask the
248     // ErrorInstance to materialize whatever it needs to. There's a chance that we get passed some
249     // other kind of object, which also has materializable properties. But this code is heuristic-ey
250     // enough that if we're wrong in such corner cases, it's not the end of the world.
251     if (ErrorInstance* errorInstance = jsDynamicCast<ErrorInstance*>(vm, error))
252         errorInstance->materializeErrorInfoIfNeeded(vm);
253     
254     // FIXME: This does not modify the column property, which confusingly continues to reflect
255     // the column at which the exception was thrown.
256     // https://bugs.webkit.org/show_bug.cgi?id=176673
257     if (line != -1)
258         error->putDirect(vm, vm.propertyNames->line, jsNumber(line));
259     if (!sourceURL.isNull())
260         error->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, sourceURL));
261     return error;
262 }
263
264 JSObject* throwConstructorCannotBeCalledAsFunctionTypeError(ExecState* exec, ThrowScope& scope, const char* constructorName)
265 {
266     return throwTypeError(exec, scope, makeString("calling ", constructorName, " constructor without new is invalid"));
267 }
268
269 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope)
270 {
271     return throwException(exec, scope, createTypeError(exec));
272 }
273
274 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, ASCIILiteral errorMessage)
275 {
276     return throwTypeError(exec, scope, String(errorMessage));
277 }
278
279 JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, const String& message)
280 {
281     return throwException(exec, scope, createTypeError(exec, message));
282 }
283
284 JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope)
285 {
286     return throwException(exec, scope, createSyntaxError(exec, "Syntax error"_s));
287 }
288
289 JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope, const String& message)
290 {
291     return throwException(exec, scope, createSyntaxError(exec, message));
292 }
293
294 JSValue throwDOMAttributeGetterTypeError(ExecState* exec, ThrowScope& scope, const ClassInfo* classInfo, PropertyName propertyName)
295 {
296     return throwTypeError(exec, scope, makeString("The ", classInfo->className, '.', String(propertyName.uid()), " getter can only be used on instances of ", classInfo->className));
297 }
298
299 JSObject* createError(ExecState* exec, const String& message)
300 {
301     return createError(exec, message, nullptr);
302 }
303
304 JSObject* createEvalError(ExecState* exec, const String& message)
305 {
306     return createEvalError(exec, message, nullptr);
307 }
308
309 JSObject* createRangeError(ExecState* exec, const String& message)
310 {
311     return createRangeError(exec, message, nullptr);
312 }
313
314 JSObject* createRangeError(ExecState* exec, JSGlobalObject* globalObject, const String& message)
315 {
316     return createRangeError(exec, globalObject, message, nullptr);
317 }
318
319 JSObject* createReferenceError(ExecState* exec, const String& message)
320 {
321     return createReferenceError(exec, message, nullptr);
322 }
323
324 JSObject* createSyntaxError(ExecState* exec, const String& message)
325 {
326     return createSyntaxError(exec, message, nullptr);
327 }
328
329 JSObject* createTypeError(ExecState* exec)
330 {
331     return createTypeError(exec, "Type error"_s);
332 }
333
334 JSObject* createTypeError(ExecState* exec, const String& message)
335 {
336     return createTypeError(exec, message, nullptr, TypeNothing);
337 }
338
339 JSObject* createNotEnoughArgumentsError(ExecState* exec)
340 {
341     return createNotEnoughArgumentsError(exec, nullptr);
342 }
343
344 JSObject* createURIError(ExecState* exec, const String& message)
345 {
346     return createURIError(exec, message, nullptr);
347 }
348
349 JSObject* createOutOfMemoryError(ExecState* exec)
350 {
351     auto* error = createError(exec, "Out of memory"_s, nullptr);
352     jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
353     return error;
354 }
355
356 JSObject* createOutOfMemoryError(ExecState* exec, const String& message)
357 {
358     
359     auto* error = createError(exec, makeString("Out of memory: ", message), nullptr);
360     jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
361     return error;
362 }
363
364
365 const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
366
367 void StrictModeTypeErrorFunction::destroy(JSCell* cell)
368 {
369     static_cast<StrictModeTypeErrorFunction*>(cell)->StrictModeTypeErrorFunction::~StrictModeTypeErrorFunction();
370 }
371
372 } // namespace JSC
373
374 namespace WTF {
375
376 using namespace JSC;
377
378 void printInternal(PrintStream& out, JSC::ErrorType errorType)
379 {
380     switch (errorType) {
381     case JSC::ErrorType::Error:
382         out.print("Error");
383         break;
384     case JSC::ErrorType::EvalError:
385         out.print("EvalError");
386         break;
387     case JSC::ErrorType::RangeError:
388         out.print("RangeError");
389         break;
390     case JSC::ErrorType::ReferenceError:
391         out.print("ReferenceError");
392         break;
393     case JSC::ErrorType::SyntaxError:
394         out.print("SyntaxError");
395         break;
396     case JSC::ErrorType::TypeError:
397         out.print("TypeError");
398         break;
399     case JSC::ErrorType::URIError:
400         out.print("URIError");
401         break;
402     }
403 }
404
405 } // namespace WTF