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