1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtScript module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file. Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** If you have questions regarding the use of this file, please contact
19 ** Nokia at qt-info@nokia.com.
22 ****************************************************************************/
25 #include "qscriptcontextinfo.h"
27 #include "qscriptcontext_p.h"
28 #include "qscriptengine.h"
29 #include "qscriptengine_p.h"
30 #include "../bridge/qscriptqobject_p.h"
31 #include <QtCore/qdatastream.h>
32 #include <QtCore/qmetaobject.h>
33 #include "CodeBlock.h"
34 #include "JSFunction.h"
36 #include "MacroAssemblerCodeRef.h"
43 \class QScriptContextInfo
45 \brief The QScriptContextInfo class provides additional information about a QScriptContext.
50 QScriptContextInfo is typically used for debugging purposes. It can
51 provide information about the code being executed, such as the type
52 of the called function, and the original source code location of the
55 If the called function is executing Qt Script code, you can obtain
56 the script location with the functions fileName() and lineNumber().
58 You can obtain the starting line number and ending line number of a
59 Qt Script function definition with functionStartLineNumber() and
60 functionEndLineNumber(), respectively.
62 For Qt Script functions and Qt methods (e.g. slots), you can call
63 functionParameterNames() to get the names of the formal parameters of the
66 For Qt methods and Qt property accessors, you can obtain the index
67 of the underlying QMetaMethod or QMetaProperty by calling
70 \sa QScriptContext, QScriptEngineAgent
74 \enum QScriptContextInfo::FunctionType
76 This enum specifies the type of function being called.
78 \value ScriptFunction The function is a Qt Script function, i.e. it was defined through a call to QScriptEngine::evaluate().
79 \value QtFunction The function is a Qt function (a signal, slot or method).
80 \value QtPropertyFunction The function is a Qt property getter or setter.
81 \value NativeFunction The function is a built-in Qt Script function, or it was defined through a call to QScriptEngine::newFunction().
84 class QScriptContextInfoPrivate
86 Q_DECLARE_PUBLIC(QScriptContextInfo)
88 QScriptContextInfoPrivate();
89 QScriptContextInfoPrivate(const QScriptContext *context);
90 ~QScriptContextInfoPrivate();
98 QScriptContextInfo::FunctionType functionType;
100 int functionStartLineNumber;
101 int functionEndLineNumber;
102 int functionMetaIndex;
104 QStringList parameterNames;
108 QScriptContextInfo *q_ptr;
114 QScriptContextInfoPrivate::QScriptContextInfoPrivate()
117 functionType = QScriptContextInfo::NativeFunction;
118 functionMetaIndex = -1;
119 functionStartLineNumber = -1;
120 functionEndLineNumber = -1;
129 QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *context)
133 functionType = QScriptContextInfo::NativeFunction;
134 functionMetaIndex = -1;
135 functionStartLineNumber = -1;
136 functionEndLineNumber = -1;
141 JSC::CallFrame *frame = const_cast<JSC::CallFrame *>(QScriptEnginePrivate::frameForContext(context));
143 // Get the line number:
145 //We need to know the context directly up in the backtrace, in order to get the line number, and adjust the global context
146 JSC::CallFrame *rewindContext = QScriptEnginePrivate::get(context->engine())->currentFrame;
147 if (QScriptEnginePrivate::contextForFrame(rewindContext) == context) { //top context
148 frame = rewindContext; //for retreiving the global context's "fake" frame
149 // An agent might have provided the line number.
150 lineNumber = QScript::scriptEngineFromExec(frame)->agentLineNumber;
152 // rewind the stack from the top in order to find the frame from the caller where the returnPC is stored
153 while (rewindContext && QScriptEnginePrivate::contextForFrame(rewindContext->callerFrame()->removeHostCallFrameFlag()) != context)
154 rewindContext = rewindContext->callerFrame()->removeHostCallFrameFlag();
156 frame = rewindContext->callerFrame()->removeHostCallFrameFlag(); //for retreiving the global context's "fake" frame
158 JSC::Instruction *returnPC = rewindContext->returnPC();
159 JSC::CodeBlock *codeBlock = frame->codeBlock();
160 if (returnPC && codeBlock) {
162 unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC));
164 unsigned bytecodeOffset = returnPC - codeBlock->instructions().begin();
166 bytecodeOffset--; //because returnPC is on the next instruction. We want the current one
167 lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame), bytecodeOffset);
172 // Get the filename and the scriptId:
173 JSC::CodeBlock *codeBlock = frame->codeBlock();
175 JSC::SourceProvider *source = codeBlock->source();
176 scriptId = source->asID();
177 fileName = source->url();
180 // Get the others information:
181 JSC::JSObject *callee = frame->callee();
182 if (callee && callee->inherits(&JSC::InternalFunction::info))
183 functionName = JSC::asInternalFunction(callee)->name(frame);
184 if (callee && callee->inherits(&JSC::JSFunction::info)
185 && !JSC::asFunction(callee)->isHostFunction()) {
186 functionType = QScriptContextInfo::ScriptFunction;
187 JSC::FunctionExecutable *body = JSC::asFunction(callee)->jsExecutable();
188 functionStartLineNumber = body->lineNo();
189 functionEndLineNumber = body->lastLine();
190 for (size_t i = 0; i < body->parameterCount(); ++i)
191 parameterNames.append(body->parameterName(i));
192 // ### get the function name from the AST
193 } else if (callee && callee->inherits(&QScript::QtFunction::info)) {
194 functionType = QScriptContextInfo::QtFunction;
195 // ### the slot can be overloaded -- need to get the particular overload from the context
196 functionMetaIndex = static_cast<QScript::QtFunction*>(callee)->initialIndex();
197 const QMetaObject *meta = static_cast<QScript::QtFunction*>(callee)->metaObject();
199 QMetaMethod method = meta->method(functionMetaIndex);
200 QList<QByteArray> formals = method.parameterNames();
201 for (int i = 0; i < formals.count(); ++i)
202 parameterNames.append(QLatin1String(formals.at(i)));
205 else if (callee && callee->inherits(&QScript::QtPropertyFunction::info)) {
206 functionType = QScriptContextInfo::QtPropertyFunction;
207 functionMetaIndex = static_cast<QScript::QtPropertyFunction*>(callee)->propertyIndex();
214 QScriptContextInfoPrivate::~QScriptContextInfoPrivate()
219 Constructs a new QScriptContextInfo from the given \a context.
221 The relevant information is extracted from the \a context at
222 construction time; i.e. if you continue script execution in the \a
223 context, the new state of the context will not be reflected in a
224 previously created QScriptContextInfo.
226 QScriptContextInfo::QScriptContextInfo(const QScriptContext *context)
230 d_ptr = new QScriptContextInfoPrivate(context);
236 Constructs a new QScriptContextInfo from the \a other info.
238 QScriptContextInfo::QScriptContextInfo(const QScriptContextInfo &other)
244 Constructs a null QScriptContextInfo.
248 QScriptContextInfo::QScriptContextInfo()
254 Destroys the QScriptContextInfo.
256 QScriptContextInfo::~QScriptContextInfo()
261 Assigns the \a other info to this QScriptContextInfo,
262 and returns a reference to this QScriptContextInfo.
264 QScriptContextInfo &QScriptContextInfo::operator=(const QScriptContextInfo &other)
271 Returns the ID of the script where the code being executed was
272 defined, or -1 if the ID is not available (i.e. a native function is
275 \sa QScriptEngineAgent::scriptLoad()
277 qint64 QScriptContextInfo::scriptId() const
279 Q_D(const QScriptContextInfo);
286 Returns the name of the file where the code being executed was
287 defined, if available; otherwise returns an empty string.
289 For Qt Script code, this function returns the fileName argument
290 that was passed to QScriptEngine::evaluate().
292 \sa lineNumber(), functionName()
294 QString QScriptContextInfo::fileName() const
296 Q_D(const QScriptContextInfo);
303 Returns the line number corresponding to the statement being
304 executed, or -1 if the line number is not available.
306 The line number is only available if Qt Script code is being
309 \sa columnNumber(), fileName()
311 int QScriptContextInfo::lineNumber() const
313 Q_D(const QScriptContextInfo);
316 return d->lineNumber;
322 int QScriptContextInfo::columnNumber() const
324 Q_D(const QScriptContextInfo);
327 return d->columnNumber;
331 Returns the name of the called function, or an empty string if
332 the name is not available.
334 For script functions of type QtPropertyFunction, this function
335 always returns the name of the property; you can use
336 QScriptContext::argumentCount() to differentiate between reads and
339 \sa fileName(), functionType()
341 QString QScriptContextInfo::functionName() const
343 Q_D(const QScriptContextInfo);
346 return d->functionName;
350 Returns the type of the called function.
352 \sa functionName(), QScriptContext::callee()
354 QScriptContextInfo::FunctionType QScriptContextInfo::functionType() const
356 Q_D(const QScriptContextInfo);
358 return NativeFunction;
359 return d->functionType;
363 Returns the line number where the definition of the called function
364 starts, or -1 if the line number is not available.
366 The starting line number is only available if the functionType() is
369 \sa functionEndLineNumber(), fileName()
371 int QScriptContextInfo::functionStartLineNumber() const
373 Q_D(const QScriptContextInfo);
376 return d->functionStartLineNumber;
380 Returns the line number where the definition of the called function
381 ends, or -1 if the line number is not available.
383 The ending line number is only available if the functionType() is
386 \sa functionStartLineNumber()
388 int QScriptContextInfo::functionEndLineNumber() const
390 Q_D(const QScriptContextInfo);
393 return d->functionEndLineNumber;
397 Returns the names of the formal parameters of the called function,
398 or an empty QStringList if the parameter names are not available.
400 \sa QScriptContext::argument()
402 QStringList QScriptContextInfo::functionParameterNames() const
404 Q_D(const QScriptContextInfo);
406 return QStringList();
407 return d->parameterNames;
411 Returns the meta index of the called function, or -1 if the meta
412 index is not available.
414 The meta index is only available if the functionType() is QtFunction
415 or QtPropertyFunction. For QtFunction, the meta index can be passed
416 to QMetaObject::method() to obtain the corresponding method
417 definition; for QtPropertyFunction, the meta index can be passed to
418 QMetaObject::property() to obtain the corresponding property
421 \sa QScriptContext::thisObject()
423 int QScriptContextInfo::functionMetaIndex() const
425 Q_D(const QScriptContextInfo);
428 return d->functionMetaIndex;
432 Returns true if this QScriptContextInfo is null, i.e. does not
433 contain any information.
435 bool QScriptContextInfo::isNull() const
437 Q_D(const QScriptContextInfo);
442 Returns true if this QScriptContextInfo is equal to the \a other
443 info, otherwise returns false.
445 bool QScriptContextInfo::operator==(const QScriptContextInfo &other) const
447 Q_D(const QScriptContextInfo);
448 const QScriptContextInfoPrivate *od = other.d_func();
453 return ((d->scriptId == od->scriptId)
454 && (d->lineNumber == od->lineNumber)
455 && (d->columnNumber == od->columnNumber)
456 && (d->fileName == od->fileName)
457 && (d->functionName == od->functionName)
458 && (d->functionType == od->functionType)
459 && (d->functionStartLineNumber == od->functionStartLineNumber)
460 && (d->functionEndLineNumber == od->functionEndLineNumber)
461 && (d->functionMetaIndex == od->functionMetaIndex)
462 && (d->parameterNames == od->parameterNames));
466 Returns true if this QScriptContextInfo is not equal to the \a other
467 info, otherwise returns false.
469 bool QScriptContextInfo::operator!=(const QScriptContextInfo &other) const
471 return !(*this == other);
474 #ifndef QT_NO_DATASTREAM
476 \fn QDataStream &operator<<(QDataStream &stream, const QScriptContextInfo &info)
478 \relates QScriptContextInfo
480 Writes the given \a info to the specified \a stream.
482 QDataStream &operator<<(QDataStream &out, const QScriptContextInfo &info)
484 out << info.scriptId();
485 out << (qint32)info.lineNumber();
486 out << (qint32)info.columnNumber();
488 out << (quint32)info.functionType();
489 out << (qint32)info.functionStartLineNumber();
490 out << (qint32)info.functionEndLineNumber();
491 out << (qint32)info.functionMetaIndex();
493 out << info.fileName();
494 out << info.functionName();
495 out << info.functionParameterNames();
501 \fn QDataStream &operator>>(QDataStream &stream, QScriptContextInfo &info)
503 \relates QScriptContextInfo
505 Reads a QScriptContextInfo from the specified \a stream into the
508 Q_SCRIPT_EXPORT QDataStream &operator>>(QDataStream &in, QScriptContextInfo &info)
511 info.d_ptr = new QScriptContextInfoPrivate();
514 in >> info.d_ptr->scriptId;
518 info.d_ptr->lineNumber = line;
522 info.d_ptr->columnNumber = column;
526 info.d_ptr->functionType = QScriptContextInfo::FunctionType(ftype);
530 info.d_ptr->functionStartLineNumber = startLine;
534 info.d_ptr->functionEndLineNumber = endLine;
538 info.d_ptr->functionMetaIndex = metaIndex;
540 in >> info.d_ptr->fileName;
541 in >> info.d_ptr->functionName;
542 in >> info.d_ptr->parameterNames;