1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | |
5 | #include "qv4errorobject_p.h" |
6 | #include <QtCore/qnumeric.h> |
7 | #include <QtCore/qmath.h> |
8 | #include <QtCore/QDateTime> |
9 | #include <QtCore/QStringList> |
10 | #include <QtCore/QDebug> |
11 | |
12 | #include <private/qv4mm_p.h> |
13 | #include <private/qv4codegen_p.h> |
14 | |
15 | #ifndef Q_OS_WIN |
16 | # include <time.h> |
17 | # ifndef Q_OS_VXWORKS |
18 | # include <sys/time.h> |
19 | # else |
20 | # include "qplatformdefs.h" |
21 | # endif |
22 | #else |
23 | # include <qt_windows.h> |
24 | #endif |
25 | |
26 | using namespace QV4; |
27 | |
28 | void Heap::ErrorObject::init() |
29 | { |
30 | Object::init(); |
31 | stackTrace = nullptr; |
32 | |
33 | Scope scope(internalClass->engine); |
34 | Scoped<QV4::ErrorObject> e(scope, this); |
35 | |
36 | if (internalClass == scope.engine->internalClasses(icType: EngineBase::Class_ErrorProto)) |
37 | return; |
38 | |
39 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_Stack, b: scope.engine->getStackFunction()->d()); |
40 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_StackSetter, v: Value::undefinedValue()); |
41 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_FileName, v: Value::undefinedValue()); |
42 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_LineNumber, v: Value::undefinedValue()); |
43 | } |
44 | |
45 | void Heap::ErrorObject::init(const Value &message, ErrorType t) |
46 | { |
47 | Object::init(); |
48 | errorType = t; |
49 | |
50 | Scope scope(internalClass->engine); |
51 | Scoped<QV4::ErrorObject> e(scope, this); |
52 | |
53 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_Stack, b: scope.engine->getStackFunction()->d()); |
54 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_StackSetter, v: Value::undefinedValue()); |
55 | |
56 | e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); |
57 | if (!e->d()->stackTrace->isEmpty()) { |
58 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_FileName, b: scope.engine->newString(s: e->d()->stackTrace->at(i: 0).source)); |
59 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_LineNumber, v: Value::fromInt32(i: qAbs(t: e->d()->stackTrace->at(i: 0).line))); |
60 | } |
61 | |
62 | if (!message.isUndefined()) |
63 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_Message, v: message); |
64 | } |
65 | |
66 | void Heap::ErrorObject::init(const Value &message, const QString &fileName, int line, int column, ErrorObject::ErrorType t) |
67 | { |
68 | Q_UNUSED(fileName); // #### |
69 | Object::init(); |
70 | errorType = t; |
71 | |
72 | Scope scope(internalClass->engine); |
73 | Scoped<QV4::ErrorObject> e(scope, this); |
74 | |
75 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_Stack, b: scope.engine->getStackFunction()->d()); |
76 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_StackSetter, v: Value::undefinedValue()); |
77 | |
78 | e->d()->stackTrace = new StackTrace(scope.engine->stackTrace()); |
79 | StackFrame frame; |
80 | frame.source = fileName; |
81 | frame.line = line; |
82 | frame.column = column; |
83 | e->d()->stackTrace->prepend(t: frame); |
84 | |
85 | Q_ASSERT(!e->d()->stackTrace->isEmpty()); |
86 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_FileName, b: scope.engine->newString(s: e->d()->stackTrace->at(i: 0).source)); |
87 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_LineNumber, v: Value::fromInt32(i: qAbs(t: e->d()->stackTrace->at(i: 0).line))); |
88 | |
89 | if (!message.isUndefined()) |
90 | setProperty(e: scope.engine, index: QV4::ErrorObject::Index_Message, v: message); |
91 | } |
92 | |
93 | const char *ErrorObject::className(Heap::ErrorObject::ErrorType t) |
94 | { |
95 | switch (t) { |
96 | case Heap::ErrorObject::Error: |
97 | return "Error" ; |
98 | case Heap::ErrorObject::EvalError: |
99 | return "EvalError" ; |
100 | case Heap::ErrorObject::RangeError: |
101 | return "RangeError" ; |
102 | case Heap::ErrorObject::ReferenceError: |
103 | return "ReferenceError" ; |
104 | case Heap::ErrorObject::SyntaxError: |
105 | return "SyntaxError" ; |
106 | case Heap::ErrorObject::TypeError: |
107 | return "TypeError" ; |
108 | case Heap::ErrorObject::URIError: |
109 | return "URIError" ; |
110 | } |
111 | Q_UNREACHABLE(); |
112 | } |
113 | |
114 | ReturnedValue ErrorObject::method_get_stack(const FunctionObject *b, const Value *thisObject, const Value *, int) |
115 | { |
116 | ExecutionEngine *v4 = b->engine(); |
117 | const ErrorObject *This = thisObject->as<ErrorObject>(); |
118 | if (!This) |
119 | return v4->throwTypeError(); |
120 | if (!This->d()->stack) { |
121 | QString trace; |
122 | for (int i = 0; i < This->d()->stackTrace->size(); ++i) { |
123 | if (i > 0) |
124 | trace += QLatin1Char('\n'); |
125 | const StackFrame &frame = This->d()->stackTrace->at(i); |
126 | trace += frame.function + QLatin1Char('@') + frame.source; |
127 | if (frame.line >= 0) |
128 | trace += QLatin1Char(':') + QString::number(frame.line); |
129 | } |
130 | This->d()->stack.set(e: v4, newVal: v4->newString(s: trace)); |
131 | } |
132 | return This->d()->stack->asReturnedValue(); |
133 | } |
134 | |
135 | DEFINE_OBJECT_VTABLE(ErrorObject); |
136 | |
137 | void Heap::SyntaxErrorObject::init(const Value &msg) |
138 | { |
139 | Heap::ErrorObject::init(message: msg, t: SyntaxError); |
140 | } |
141 | |
142 | void Heap::SyntaxErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) |
143 | { |
144 | Heap::ErrorObject::init(message: msg, fileName, line: lineNumber, column: columnNumber, t: SyntaxError); |
145 | } |
146 | |
147 | void Heap::EvalErrorObject::init(const Value &message) |
148 | { |
149 | Heap::ErrorObject::init(message, t: EvalError); |
150 | } |
151 | |
152 | void Heap::RangeErrorObject::init(const Value &message) |
153 | { |
154 | Heap::ErrorObject::init(message, t: RangeError); |
155 | } |
156 | |
157 | void Heap::ReferenceErrorObject::init(const Value &message) |
158 | { |
159 | Heap::ErrorObject::init(message, t: ReferenceError); |
160 | } |
161 | |
162 | void Heap::ReferenceErrorObject::init(const Value &msg, const QString &fileName, int lineNumber, int columnNumber) |
163 | { |
164 | Heap::ErrorObject::init(message: msg, fileName, line: lineNumber, column: columnNumber, t: ReferenceError); |
165 | } |
166 | |
167 | void Heap::TypeErrorObject::init(const Value &message) |
168 | { |
169 | Heap::ErrorObject::init(message, t: TypeError); |
170 | } |
171 | |
172 | void Heap::URIErrorObject::init(const Value &message) |
173 | { |
174 | Heap::ErrorObject::init(message, t: URIError); |
175 | } |
176 | |
177 | DEFINE_OBJECT_VTABLE(ErrorCtor); |
178 | DEFINE_OBJECT_VTABLE(EvalErrorCtor); |
179 | DEFINE_OBJECT_VTABLE(RangeErrorCtor); |
180 | DEFINE_OBJECT_VTABLE(ReferenceErrorCtor); |
181 | DEFINE_OBJECT_VTABLE(SyntaxErrorCtor); |
182 | DEFINE_OBJECT_VTABLE(TypeErrorCtor); |
183 | DEFINE_OBJECT_VTABLE(URIErrorCtor); |
184 | |
185 | void Heap::ErrorCtor::init(QV4::ExecutionContext *scope) |
186 | { |
187 | Heap::FunctionObject::init(scope, QStringLiteral("Error" )); |
188 | } |
189 | |
190 | void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name) |
191 | { |
192 | Heap::FunctionObject::init(scope, name); |
193 | } |
194 | |
195 | ReturnedValue ErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
196 | { |
197 | Value v = argc ? *argv : Value::undefinedValue(); |
198 | return ErrorObject::create<ErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
199 | } |
200 | |
201 | ReturnedValue ErrorCtor::virtualCall(const FunctionObject *f, const Value *, const Value *argv, int argc) |
202 | { |
203 | return f->callAsConstructor(argv, argc); |
204 | } |
205 | |
206 | void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope) |
207 | { |
208 | Heap::FunctionObject::init(scope, QStringLiteral("EvalError" )); |
209 | } |
210 | |
211 | ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
212 | { |
213 | Value v = argc ? *argv : Value::undefinedValue(); |
214 | return ErrorObject::create<EvalErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
215 | } |
216 | |
217 | void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope) |
218 | { |
219 | Heap::FunctionObject::init(scope, QStringLiteral("RangeError" )); |
220 | } |
221 | |
222 | ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
223 | { |
224 | Value v = argc ? *argv : Value::undefinedValue(); |
225 | return ErrorObject::create<RangeErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
226 | } |
227 | |
228 | void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope) |
229 | { |
230 | Heap::FunctionObject::init(scope, QStringLiteral("ReferenceError" )); |
231 | } |
232 | |
233 | ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
234 | { |
235 | Value v = argc ? *argv : Value::undefinedValue(); |
236 | return ErrorObject::create<ReferenceErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
237 | } |
238 | |
239 | void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope) |
240 | { |
241 | Heap::FunctionObject::init(scope, QStringLiteral("SyntaxError" )); |
242 | } |
243 | |
244 | ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
245 | { |
246 | Value v = argc ? *argv : Value::undefinedValue(); |
247 | return ErrorObject::create<SyntaxErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
248 | } |
249 | |
250 | void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope) |
251 | { |
252 | Heap::FunctionObject::init(scope, QStringLiteral("TypeError" )); |
253 | } |
254 | |
255 | ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
256 | { |
257 | Value v = argc ? *argv : Value::undefinedValue(); |
258 | return ErrorObject::create<TypeErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
259 | } |
260 | |
261 | void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope) |
262 | { |
263 | Heap::FunctionObject::init(scope, QStringLiteral("URIError" )); |
264 | } |
265 | |
266 | ReturnedValue URIErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) |
267 | { |
268 | Value v = argc ? *argv : Value::undefinedValue(); |
269 | return ErrorObject::create<URIErrorObject>(e: f->engine(), message: v, newTarget)->asReturnedValue(); |
270 | } |
271 | |
272 | void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t) |
273 | { |
274 | Scope scope(engine); |
275 | ScopedString s(scope); |
276 | ScopedObject o(scope); |
277 | ctor->defineReadonlyProperty(name: engine->id_prototype(), value: (o = obj)); |
278 | ctor->defineReadonlyConfigurableProperty(name: engine->id_length(), value: Value::fromInt32(i: 1)); |
279 | obj->setProperty(index: Index_Constructor, b: ctor->d()); |
280 | obj->setProperty(index: Index_Message, b: engine->id_empty()->d()); |
281 | obj->setProperty(index: Index_Name, b: engine->newString(s: QString::fromLatin1(ba: ErrorObject::className(t)))); |
282 | obj->defineDefaultProperty(name: engine->id_toString(), code: method_toString, argumentCount: 0); |
283 | } |
284 | |
285 | ReturnedValue ErrorPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int) |
286 | { |
287 | ExecutionEngine *v4 = b->engine(); |
288 | const Object *o = thisObject->as<Object>(); |
289 | if (!o) |
290 | return v4->throwTypeError(); |
291 | |
292 | Scope scope(v4); |
293 | ScopedValue name(scope, o->get(name: scope.engine->id_name())); |
294 | QString qname; |
295 | if (name->isUndefined()) |
296 | qname = QStringLiteral("Error" ); |
297 | else |
298 | qname = name->toQString(); |
299 | |
300 | ScopedString s(scope, scope.engine->newString(QStringLiteral("message" ))); |
301 | ScopedValue message(scope, o->get(name: s)); |
302 | QString qmessage; |
303 | if (!message->isUndefined()) |
304 | qmessage = message->toQString(); |
305 | |
306 | QString str; |
307 | if (qname.isEmpty()) { |
308 | str = qmessage; |
309 | } else if (qmessage.isEmpty()) { |
310 | str = qname; |
311 | } else { |
312 | str = qname + QLatin1String(": " ) + qmessage; |
313 | } |
314 | |
315 | return scope.engine->newString(s: str)->asReturnedValue(); |
316 | } |
317 | |