util/src/script/api/qscriptcontextinfo.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtScript module of the Qt Toolkit.
       
     8 **
       
     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.
       
    17 **
       
    18 ** If you have questions regarding the use of this file, please contact
       
    19 ** Nokia at qt-info@nokia.com.
       
    20 ** $QT_END_LICENSE$
       
    21 **
       
    22 ****************************************************************************/
       
    23 
       
    24 #include "config.h"
       
    25 #include "qscriptcontextinfo.h"
       
    26 
       
    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"
       
    35 #if ENABLE(JIT)
       
    36 #include "MacroAssemblerCodeRef.h"
       
    37 #endif
       
    38 
       
    39 QT_BEGIN_NAMESPACE
       
    40 
       
    41 /*!
       
    42   \since 4.4
       
    43   \class QScriptContextInfo
       
    44 
       
    45   \brief The QScriptContextInfo class provides additional information about a QScriptContext.
       
    46 
       
    47   \ingroup script
       
    48 
       
    49 
       
    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
       
    53   current statement.
       
    54 
       
    55   If the called function is executing Qt Script code, you can obtain
       
    56   the script location with the functions fileName(), lineNumber() and
       
    57   columnNumber().
       
    58 
       
    59   You can obtain the starting line number and ending line number of a
       
    60   Qt Script function definition with functionStartLineNumber() and
       
    61   functionEndLineNumber(), respectively.
       
    62 
       
    63   For Qt Script functions and Qt methods (e.g. slots), you can call
       
    64   functionParameterNames() to get the names of the formal parameters of the
       
    65   function.
       
    66 
       
    67   For Qt methods and Qt property accessors, you can obtain the index
       
    68   of the underlying QMetaMethod or QMetaProperty by calling
       
    69   functionMetaIndex().
       
    70 
       
    71   \sa QScriptContext, QScriptEngineAgent
       
    72 */
       
    73 
       
    74 /*!
       
    75     \enum QScriptContextInfo::FunctionType
       
    76 
       
    77     This enum specifies the type of function being called.
       
    78 
       
    79     \value ScriptFunction The function is a Qt Script function, i.e. it was defined through a call to QScriptEngine::evaluate().
       
    80     \value QtFunction The function is a Qt function (a signal, slot or method).
       
    81     \value QtPropertyFunction The function is a Qt property getter or setter.
       
    82     \value NativeFunction The function is a built-in Qt Script function, or it was defined through a call to QScriptEngine::newFunction().
       
    83 */
       
    84 
       
    85 class QScriptContextInfoPrivate
       
    86 {
       
    87     Q_DECLARE_PUBLIC(QScriptContextInfo)
       
    88 public:
       
    89     QScriptContextInfoPrivate();
       
    90     QScriptContextInfoPrivate(const QScriptContext *context);
       
    91     ~QScriptContextInfoPrivate();
       
    92 
       
    93     qint64 scriptId;
       
    94     int lineNumber;
       
    95     int columnNumber;
       
    96     QString fileName;
       
    97 
       
    98     QString functionName;
       
    99     QScriptContextInfo::FunctionType functionType;
       
   100 
       
   101     int functionStartLineNumber;
       
   102     int functionEndLineNumber;
       
   103     int functionMetaIndex;
       
   104 
       
   105     QStringList parameterNames;
       
   106 
       
   107     QBasicAtomicInt ref;
       
   108 
       
   109     QScriptContextInfo *q_ptr;
       
   110 };
       
   111 
       
   112 /*!
       
   113   \internal
       
   114 */
       
   115 QScriptContextInfoPrivate::QScriptContextInfoPrivate()
       
   116 {
       
   117     ref = 0;
       
   118     functionType = QScriptContextInfo::NativeFunction;
       
   119     functionMetaIndex = -1;
       
   120     functionStartLineNumber = -1;
       
   121     functionEndLineNumber = -1;
       
   122     scriptId = -1;
       
   123     lineNumber = -1;
       
   124     columnNumber = -1;
       
   125 }
       
   126 
       
   127 /*!
       
   128   \internal
       
   129 */
       
   130 QScriptContextInfoPrivate::QScriptContextInfoPrivate(const QScriptContext *context)
       
   131 {
       
   132     Q_ASSERT(context);
       
   133     ref = 0;
       
   134     functionType = QScriptContextInfo::NativeFunction;
       
   135     functionMetaIndex = -1;
       
   136     functionStartLineNumber = -1;
       
   137     functionEndLineNumber = -1;
       
   138     scriptId = -1;
       
   139     lineNumber = -1;
       
   140     columnNumber = -1;
       
   141 
       
   142     JSC::CallFrame *frame = const_cast<JSC::CallFrame *>(QScriptEnginePrivate::frameForContext(context));
       
   143 
       
   144     // Get the line number:
       
   145 
       
   146     //We need to know the context directly up in the backtrace, in order to get the line number, and adjust the global context
       
   147     JSC::CallFrame *rewindContext = QScriptEnginePrivate::get(context->engine())->currentFrame;
       
   148     if (QScriptEnginePrivate::contextForFrame(rewindContext) == context) {  //top context
       
   149         frame = rewindContext; //for retreiving the global context's "fake" frame
       
   150         // An agent might have provided the line number.
       
   151         lineNumber = QScript::scriptEngineFromExec(frame)->agentLineNumber;
       
   152     } else {
       
   153         // rewind the stack from the top in order to find the frame from the caller where the returnPC is stored
       
   154         while (rewindContext && QScriptEnginePrivate::contextForFrame(rewindContext->callerFrame()->removeHostCallFrameFlag()) != context)
       
   155             rewindContext = rewindContext->callerFrame()->removeHostCallFrameFlag();
       
   156         if (rewindContext) {
       
   157             frame = rewindContext->callerFrame()->removeHostCallFrameFlag(); //for retreiving the global context's "fake" frame
       
   158 
       
   159             JSC::Instruction *returnPC = rewindContext->returnPC();
       
   160             JSC::CodeBlock *codeBlock = frame->codeBlock();
       
   161             if (returnPC && codeBlock) {
       
   162 #if ENABLE(JIT)
       
   163                 unsigned bytecodeOffset = codeBlock->getBytecodeIndex(frame, JSC::ReturnAddressPtr(returnPC));
       
   164 #else
       
   165                 unsigned bytecodeOffset = returnPC - codeBlock->instructions().begin();
       
   166 #endif
       
   167                 bytecodeOffset--; //because returnPC is on the next instruction. We want the current one
       
   168                 lineNumber = codeBlock->lineNumberForBytecodeOffset(const_cast<JSC::ExecState *>(frame), bytecodeOffset);
       
   169             }
       
   170         }
       
   171     }
       
   172 
       
   173     // Get the filename and the scriptId:
       
   174     JSC::CodeBlock *codeBlock = frame->codeBlock();
       
   175     if (codeBlock) {
       
   176            JSC::SourceProvider *source = codeBlock->source();
       
   177            scriptId = source->asID();
       
   178            fileName = source->url();
       
   179     }
       
   180 
       
   181     // Get the others informations:
       
   182     JSC::JSObject *callee = frame->callee();
       
   183     if (callee && callee->inherits(&JSC::InternalFunction::info))
       
   184         functionName = JSC::asInternalFunction(callee)->name(&frame->globalData());
       
   185     if (callee && callee->inherits(&JSC::JSFunction::info)) {
       
   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();
       
   198         if (meta != 0) {
       
   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)));
       
   203         }
       
   204     }
       
   205     else if (callee && callee->inherits(&QScript::QtPropertyFunction::info)) {
       
   206         functionType = QScriptContextInfo::QtPropertyFunction;
       
   207         functionMetaIndex = static_cast<QScript::QtPropertyFunction*>(callee)->propertyIndex();
       
   208     }
       
   209 }
       
   210 
       
   211 /*!
       
   212   \internal
       
   213 */
       
   214 QScriptContextInfoPrivate::~QScriptContextInfoPrivate()
       
   215 {
       
   216 }
       
   217 
       
   218 /*!
       
   219   Constructs a new QScriptContextInfo from the given \a context.
       
   220 
       
   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.
       
   225 */
       
   226 QScriptContextInfo::QScriptContextInfo(const QScriptContext *context)
       
   227     : d_ptr(0)
       
   228 {
       
   229     if (context) {
       
   230         d_ptr = new QScriptContextInfoPrivate(context);
       
   231         d_ptr->q_ptr = this;
       
   232     }
       
   233 }
       
   234 
       
   235 /*!
       
   236   Constructs a new QScriptContextInfo from the \a other info.
       
   237 */
       
   238 QScriptContextInfo::QScriptContextInfo(const QScriptContextInfo &other)
       
   239     : d_ptr(other.d_ptr)
       
   240 {
       
   241 }
       
   242 
       
   243 /*!
       
   244   Constructs a null QScriptContextInfo.
       
   245 
       
   246   \sa isNull()
       
   247 */
       
   248 QScriptContextInfo::QScriptContextInfo()
       
   249     : d_ptr(0)
       
   250 {
       
   251 }
       
   252 
       
   253 /*!
       
   254   Destroys the QScriptContextInfo.
       
   255 */
       
   256 QScriptContextInfo::~QScriptContextInfo()
       
   257 {
       
   258 }
       
   259 
       
   260 /*!
       
   261   Assigns the \a other info to this QScriptContextInfo,
       
   262   and returns a reference to this QScriptContextInfo.
       
   263 */
       
   264 QScriptContextInfo &QScriptContextInfo::operator=(const QScriptContextInfo &other)
       
   265 {
       
   266     d_ptr = other.d_ptr;
       
   267     return *this;
       
   268 }
       
   269 
       
   270 /*!
       
   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
       
   273   being executed).
       
   274 
       
   275   \sa QScriptEngineAgent::scriptLoad()
       
   276 */
       
   277 qint64 QScriptContextInfo::scriptId() const
       
   278 {
       
   279     Q_D(const QScriptContextInfo);
       
   280     if (!d)
       
   281         return -1;
       
   282     return d->scriptId;
       
   283 }
       
   284 
       
   285 /*!
       
   286   Returns the name of the file where the code being executed was
       
   287   defined, if available; otherwise returns an empty string.
       
   288 
       
   289   For Qt Script code, this function returns the fileName argument
       
   290   that was passed to QScriptEngine::evaluate().
       
   291 
       
   292   \sa lineNumber(), functionName()
       
   293 */
       
   294 QString QScriptContextInfo::fileName() const
       
   295 {
       
   296     Q_D(const QScriptContextInfo);
       
   297     if (!d)
       
   298         return QString();
       
   299     return d->fileName;
       
   300 }
       
   301 
       
   302 /*!
       
   303   Returns the line number corresponding to the statement being
       
   304   executed, or -1 if the line number is not available.
       
   305 
       
   306   The line number is only available if Qt Script code is being
       
   307   executed.
       
   308 
       
   309   \sa columnNumber(), fileName()
       
   310 */
       
   311 int QScriptContextInfo::lineNumber() const
       
   312 {
       
   313     Q_D(const QScriptContextInfo);
       
   314     if (!d)
       
   315         return -1;
       
   316     return d->lineNumber;
       
   317 }
       
   318 
       
   319 /*!
       
   320   Returns the column number corresponding to the statement being
       
   321   executed, or -1 if the column number is not available.
       
   322 
       
   323   The column number is only available if Qt Script code is being
       
   324   executed.
       
   325 
       
   326   \sa lineNumber(), fileName()
       
   327 */
       
   328 int QScriptContextInfo::columnNumber() const
       
   329 {
       
   330     Q_D(const QScriptContextInfo);
       
   331     if (!d)
       
   332         return -1;
       
   333     return d->columnNumber;
       
   334 }
       
   335 
       
   336 /*!
       
   337   Returns the name of the called function, or an empty string if
       
   338   the name is not available.
       
   339 
       
   340   For script functions of type QtPropertyFunction, this function
       
   341   always returns the name of the property; you can use
       
   342   QScriptContext::argumentCount() to differentiate between reads and
       
   343   writes.
       
   344 
       
   345   \sa fileName(), functionType()
       
   346 */
       
   347 QString QScriptContextInfo::functionName() const
       
   348 {
       
   349     Q_D(const QScriptContextInfo);
       
   350     if (!d)
       
   351         return QString();
       
   352     return d->functionName;
       
   353 }
       
   354 
       
   355 /*!
       
   356   Returns the type of the called function.
       
   357 
       
   358   \sa functionName(), QScriptContext::callee()
       
   359 */
       
   360 QScriptContextInfo::FunctionType QScriptContextInfo::functionType() const
       
   361 {
       
   362     Q_D(const QScriptContextInfo);
       
   363     if (!d)
       
   364         return NativeFunction;
       
   365     return d->functionType;
       
   366 }
       
   367 
       
   368 /*!
       
   369   Returns the line number where the definition of the called function
       
   370   starts, or -1 if the line number is not available.
       
   371 
       
   372   The starting line number is only available if the functionType() is
       
   373   ScriptFunction.
       
   374 
       
   375   \sa functionEndLineNumber(), fileName()
       
   376 */
       
   377 int QScriptContextInfo::functionStartLineNumber() const
       
   378 {
       
   379     Q_D(const QScriptContextInfo);
       
   380     if (!d)
       
   381         return -1;
       
   382     return d->functionStartLineNumber;
       
   383 }
       
   384 
       
   385 /*!
       
   386   Returns the line number where the definition of the called function
       
   387   ends, or -1 if the line number is not available.
       
   388 
       
   389   The ending line number is only available if the functionType() is
       
   390   ScriptFunction.
       
   391 
       
   392   \sa functionStartLineNumber()
       
   393 */
       
   394 int QScriptContextInfo::functionEndLineNumber() const
       
   395 {
       
   396     Q_D(const QScriptContextInfo);
       
   397     if (!d)
       
   398         return -1;
       
   399     return d->functionEndLineNumber;
       
   400 }
       
   401 
       
   402 /*!
       
   403   Returns the names of the formal parameters of the called function,
       
   404   or an empty QStringList if the parameter names are not available.
       
   405 
       
   406   \sa QScriptContext::argument()
       
   407 */
       
   408 QStringList QScriptContextInfo::functionParameterNames() const
       
   409 {
       
   410     Q_D(const QScriptContextInfo);
       
   411     if (!d)
       
   412         return QStringList();
       
   413     return d->parameterNames;
       
   414 }
       
   415 
       
   416 /*!
       
   417   Returns the meta index of the called function, or -1 if the meta
       
   418   index is not available.
       
   419 
       
   420   The meta index is only available if the functionType() is QtFunction
       
   421   or QtPropertyFunction. For QtFunction, the meta index can be passed
       
   422   to QMetaObject::method() to obtain the corresponding method
       
   423   definition; for QtPropertyFunction, the meta index can be passed to
       
   424   QMetaObject::property() to obtain the corresponding property
       
   425   definition.
       
   426 
       
   427   \sa QScriptContext::thisObject()
       
   428 */
       
   429 int QScriptContextInfo::functionMetaIndex() const
       
   430 {
       
   431     Q_D(const QScriptContextInfo);
       
   432     if (!d)
       
   433         return -1;
       
   434     return d->functionMetaIndex;
       
   435 }
       
   436 
       
   437 /*!
       
   438   Returns true if this QScriptContextInfo is null, i.e. does not
       
   439   contain any information.
       
   440 */
       
   441 bool QScriptContextInfo::isNull() const
       
   442 {
       
   443     Q_D(const QScriptContextInfo);
       
   444     return (d == 0);
       
   445 }
       
   446 
       
   447 /*!
       
   448   Returns true if this QScriptContextInfo is equal to the \a other
       
   449   info, otherwise returns false.
       
   450 */
       
   451 bool QScriptContextInfo::operator==(const QScriptContextInfo &other) const
       
   452 {
       
   453     Q_D(const QScriptContextInfo);
       
   454     const QScriptContextInfoPrivate *od = other.d_func();
       
   455     if (d == od)
       
   456         return true;
       
   457     if (!d || !od)
       
   458         return false;
       
   459     return ((d->scriptId == od->scriptId)
       
   460             && (d->lineNumber == od->lineNumber)
       
   461             && (d->columnNumber == od->columnNumber)
       
   462             && (d->fileName == od->fileName)
       
   463             && (d->functionName == od->functionName)
       
   464             && (d->functionType == od->functionType)
       
   465             && (d->functionStartLineNumber == od->functionStartLineNumber)
       
   466             && (d->functionEndLineNumber == od->functionEndLineNumber)
       
   467             && (d->functionMetaIndex == od->functionMetaIndex)
       
   468             && (d->parameterNames == od->parameterNames));
       
   469 }
       
   470 
       
   471 /*!
       
   472   Returns true if this QScriptContextInfo is not equal to the \a other
       
   473   info, otherwise returns false.
       
   474 */
       
   475 bool QScriptContextInfo::operator!=(const QScriptContextInfo &other) const
       
   476 {
       
   477     return !(*this == other);
       
   478 }
       
   479 
       
   480 #ifndef QT_NO_DATASTREAM
       
   481 /*!
       
   482   \fn QDataStream &operator<<(QDataStream &stream, const QScriptContextInfo &info)
       
   483   \since 4.4
       
   484   \relates QScriptContextInfo
       
   485 
       
   486   Writes the given \a info to the specified \a stream.
       
   487 */
       
   488 QDataStream &operator<<(QDataStream &out, const QScriptContextInfo &info)
       
   489 {
       
   490     out << info.scriptId();
       
   491     out << (qint32)info.lineNumber();
       
   492     out << (qint32)info.columnNumber();
       
   493 
       
   494     out << (quint32)info.functionType();
       
   495     out << (qint32)info.functionStartLineNumber();
       
   496     out << (qint32)info.functionEndLineNumber();
       
   497     out << (qint32)info.functionMetaIndex();
       
   498 
       
   499     out << info.fileName();
       
   500     out << info.functionName();
       
   501     out << info.functionParameterNames();
       
   502 
       
   503     return out;
       
   504 }
       
   505 
       
   506 /*!
       
   507   \fn QDataStream &operator>>(QDataStream &stream, QScriptContextInfo &info)
       
   508   \since 4.4
       
   509   \relates QScriptContextInfo
       
   510 
       
   511   Reads a QScriptContextInfo from the specified \a stream into the
       
   512   given \a info.
       
   513 */
       
   514 Q_SCRIPT_EXPORT QDataStream &operator>>(QDataStream &in, QScriptContextInfo &info)
       
   515 {
       
   516     if (!info.d_ptr) {
       
   517         info.d_ptr = new QScriptContextInfoPrivate();
       
   518     }
       
   519 
       
   520     in >> info.d_ptr->scriptId;
       
   521 
       
   522     qint32 line;
       
   523     in >> line;
       
   524     info.d_ptr->lineNumber = line;
       
   525 
       
   526     qint32 column;
       
   527     in >> column;
       
   528     info.d_ptr->columnNumber = column;
       
   529 
       
   530     quint32 ftype;
       
   531     in >> ftype;
       
   532     info.d_ptr->functionType = QScriptContextInfo::FunctionType(ftype);
       
   533 
       
   534     qint32 startLine;
       
   535     in >> startLine;
       
   536     info.d_ptr->functionStartLineNumber = startLine;
       
   537 
       
   538     qint32 endLine;
       
   539     in >> endLine;
       
   540     info.d_ptr->functionEndLineNumber = endLine;
       
   541 
       
   542     qint32 metaIndex;
       
   543     in >> metaIndex;
       
   544     info.d_ptr->functionMetaIndex = metaIndex;
       
   545 
       
   546     in >> info.d_ptr->fileName;
       
   547     in >> info.d_ptr->functionName;
       
   548     in >> info.d_ptr->parameterNames;
       
   549 
       
   550     return in;
       
   551 }
       
   552 #endif
       
   553 
       
   554 QT_END_NAMESPACE