util/src/script/api/qscriptcontext.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 "qscriptcontext.h"
       
    26 
       
    27 #include "qscriptcontext_p.h"
       
    28 #include "qscriptcontextinfo.h"
       
    29 #include "qscriptengine.h"
       
    30 #include "qscriptengine_p.h"
       
    31 #include "../bridge/qscriptactivationobject_p.h"
       
    32 
       
    33 #include "Arguments.h"
       
    34 #include "CodeBlock.h"
       
    35 #include "Error.h"
       
    36 #include "JSFunction.h"
       
    37 #include "JSObject.h"
       
    38 #include "JSGlobalObject.h"
       
    39 
       
    40 #include <QtCore/qstringlist.h>
       
    41 
       
    42 QT_BEGIN_NAMESPACE
       
    43 
       
    44 /*!
       
    45   \since 4.3
       
    46   \class QScriptContext
       
    47 
       
    48   \brief The QScriptContext class represents a Qt Script function invocation.
       
    49 
       
    50   \ingroup script
       
    51   \mainclass
       
    52 
       
    53   A QScriptContext provides access to the `this' object and arguments
       
    54   passed to a script function. You typically want to access this
       
    55   information when you're writing a native (C++) function (see
       
    56   QScriptEngine::newFunction()) that will be called from script
       
    57   code. For example, when the script code
       
    58 
       
    59   \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 0
       
    60 
       
    61   is evaluated, a QScriptContext will be created, and the context will
       
    62   carry the arguments as QScriptValues; in this particular case, the
       
    63   arguments will be one QScriptValue containing the number 20.5, a second
       
    64   QScriptValue containing the string \c{"hello"}, and a third QScriptValue
       
    65   containing a Qt Script object.
       
    66 
       
    67   Use argumentCount() to get the number of arguments passed to the
       
    68   function, and argument() to get an argument at a certain index. The
       
    69   argumentsObject() function returns a Qt Script array object
       
    70   containing all the arguments; you can use the QScriptValueIterator
       
    71   to iterate over its elements, or pass the array on as arguments to
       
    72   another script function using QScriptValue::call().
       
    73 
       
    74   Use thisObject() to get the `this' object associated with the function call,
       
    75   and setThisObject() to set the `this' object. If you are implementing a
       
    76   native "instance method", you typically fetch the thisObject() and access
       
    77   one or more of its properties:
       
    78 
       
    79   \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 1
       
    80 
       
    81   Use isCalledAsConstructor() to determine if the function was called
       
    82   as a constructor (e.g. \c{"new foo()"} (as constructor) or just
       
    83   \c{"foo()"}).  When a function is called as a constructor, the
       
    84   thisObject() contains the newly constructed object that the function
       
    85   is expected to initialize.
       
    86 
       
    87   Use throwValue() or throwError() to throw an exception.
       
    88 
       
    89   Use callee() to obtain the QScriptValue that represents the function being
       
    90   called. This can for example be used to call the function recursively.
       
    91 
       
    92   Use parentContext() to get a pointer to the context that precedes
       
    93   this context in the activation stack. This is mostly useful for
       
    94   debugging purposes (e.g. when constructing some form of backtrace).
       
    95 
       
    96   The activationObject() function returns the object that is used to
       
    97   hold the local variables associated with this function call. You can
       
    98   replace the activation object by calling setActivationObject(). A
       
    99   typical usage of these functions is when you want script code to be
       
   100   evaluated in the context of the parent context, e.g. to implement an
       
   101   include() function:
       
   102 
       
   103   \snippet doc/src/snippets/code/src_script_qscriptcontext.cpp 2
       
   104 
       
   105   Use backtrace() to get a human-readable backtrace associated with
       
   106   this context. This can be useful for debugging purposes when
       
   107   implementing native functions. The toString() function provides a
       
   108   string representation of the context. (QScriptContextInfo provides
       
   109   more detailed debugging-related information about the
       
   110   QScriptContext.)
       
   111 
       
   112   Use engine() to obtain a pointer to the QScriptEngine that this context
       
   113   resides in.
       
   114 
       
   115   \sa QScriptContextInfo, QScriptEngine::newFunction(), QScriptable
       
   116 */
       
   117 
       
   118 /*!
       
   119     \enum QScriptContext::ExecutionState
       
   120 
       
   121     This enum specifies the frameution state of the context.
       
   122 
       
   123     \value NormalState The context is in a normal state.
       
   124 
       
   125     \value ExceptionState The context is in an exceptional state.
       
   126 */
       
   127 
       
   128 /*!
       
   129     \enum QScriptContext::Error
       
   130 
       
   131     This enum specifies types of error.
       
   132 
       
   133     \value ReferenceError A reference error.
       
   134 
       
   135     \value SyntaxError A syntax error.
       
   136 
       
   137     \value TypeError A type error.
       
   138 
       
   139     \value RangeError A range error.
       
   140 
       
   141     \value URIError A URI error.
       
   142 
       
   143     \value UnknownError An unknown error.
       
   144 */
       
   145 
       
   146 /*!
       
   147   \internal
       
   148 */
       
   149 QScriptContext::QScriptContext()
       
   150 {
       
   151     //QScriptContext doesn't exist,  pointer to QScriptContext are just pointer to  JSC::CallFrame
       
   152     Q_ASSERT(false);
       
   153 }
       
   154 
       
   155 /*!
       
   156   Throws an exception with the given \a value.
       
   157   Returns the value thrown (the same as the argument).
       
   158 
       
   159   \sa throwError(), state()
       
   160 */
       
   161 QScriptValue QScriptContext::throwValue(const QScriptValue &value)
       
   162 {
       
   163     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   164     JSC::JSValue jscValue = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(value);
       
   165     frame->setException(jscValue);
       
   166     return value;
       
   167 }
       
   168 
       
   169 /*!
       
   170   Throws an \a error with the given \a text.
       
   171   Returns the created error object.
       
   172 
       
   173   The \a text will be stored in the \c{message} property of the error
       
   174   object.
       
   175 
       
   176   The error object will be initialized to contain information about
       
   177   the location where the error occurred; specifically, it will have
       
   178   properties \c{lineNumber}, \c{fileName} and \c{stack}. These
       
   179   properties are described in \l {QtScript Extensions to ECMAScript}.
       
   180 
       
   181   \sa throwValue(), state()
       
   182 */
       
   183 QScriptValue QScriptContext::throwError(Error error, const QString &text)
       
   184 {
       
   185     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   186     JSC::ErrorType jscError = JSC::GeneralError;
       
   187     switch (error) {
       
   188     case UnknownError:
       
   189         break;
       
   190     case ReferenceError:
       
   191         jscError = JSC::ReferenceError;
       
   192         break;
       
   193     case SyntaxError:
       
   194         jscError = JSC::SyntaxError;
       
   195         break;
       
   196     case TypeError:
       
   197         jscError = JSC::TypeError;
       
   198         break;
       
   199     case RangeError:
       
   200         jscError = JSC::RangeError;
       
   201         break;
       
   202     case URIError:
       
   203         jscError = JSC::URIError;
       
   204         break;
       
   205     }
       
   206     JSC::JSObject *result = JSC::throwError(frame, jscError, text);
       
   207     return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
       
   208 }
       
   209 
       
   210 /*!
       
   211   \overload
       
   212 
       
   213   Throws an error with the given \a text.
       
   214   Returns the created error object.
       
   215 
       
   216   \sa throwValue(), state()
       
   217 */
       
   218 QScriptValue QScriptContext::throwError(const QString &text)
       
   219 {
       
   220     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   221     JSC::JSObject *result = JSC::throwError(frame, JSC::GeneralError, text);
       
   222     return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
       
   223 }
       
   224 
       
   225 /*!
       
   226   Destroys this QScriptContext.
       
   227 */
       
   228 QScriptContext::~QScriptContext()
       
   229 {
       
   230     //QScriptContext doesn't exist,  pointer to QScriptContext are just pointer to JSC::CallFrame
       
   231     Q_ASSERT(false);
       
   232 }
       
   233 
       
   234 /*!
       
   235   Returns the QScriptEngine that this QScriptContext belongs to.
       
   236 */
       
   237 QScriptEngine *QScriptContext::engine() const
       
   238 {
       
   239     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   240     return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame));
       
   241 }
       
   242 
       
   243 /*!
       
   244   Returns the function argument at the given \a index.
       
   245 
       
   246   If \a index >= argumentCount(), a QScriptValue of
       
   247   the primitive type Undefined is returned.
       
   248 
       
   249   \sa argumentCount()
       
   250 */
       
   251 QScriptValue QScriptContext::argument(int index) const
       
   252 {
       
   253     if (index < 0)
       
   254         return QScriptValue();
       
   255     if (index >= argumentCount())
       
   256         return QScriptValue(QScriptValue::UndefinedValue);
       
   257     QScriptValue v = argumentsObject().property(index);
       
   258     return v;
       
   259 }
       
   260 
       
   261 /*!
       
   262   Returns the callee. The callee is the function object that this
       
   263   QScriptContext represents an invocation of.
       
   264 */
       
   265 QScriptValue QScriptContext::callee() const
       
   266 {
       
   267     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   268     return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->callee());
       
   269 }
       
   270 
       
   271 /*!
       
   272   Returns the arguments object of this QScriptContext.
       
   273 
       
   274   The arguments object has properties \c callee (equal to callee())
       
   275   and \c length (equal to argumentCount()), and properties \c 0, \c 1,
       
   276   ..., argumentCount() - 1 that provide access to the argument
       
   277   values. Initially, property \c P (0 <= \c P < argumentCount()) has
       
   278   the same value as argument(\c P). In the case when \c P is less
       
   279   than the number of formal parameters of the function, \c P shares
       
   280   its value with the corresponding property of the activation object
       
   281   (activationObject()). This means that changing this property changes
       
   282   the corresponding property of the activation object and vice versa.
       
   283 
       
   284   \sa argument(), activationObject()
       
   285 */
       
   286 QScriptValue QScriptContext::argumentsObject() const
       
   287 {
       
   288     JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
       
   289 
       
   290     if (frame == frame->lexicalGlobalObject()->globalExec()) {
       
   291         // <global> context doesn't have arguments. return an empty object
       
   292         return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
       
   293     }
       
   294 
       
   295     //for a js function
       
   296     if (frame->codeBlock() && frame->callee()) {
       
   297         JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee()));
       
   298         return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
       
   299     }
       
   300 
       
   301     if (frame->callerFrame()->hasHostCallFrameFlag()) {
       
   302         // <eval> context doesn't have arguments. return an empty object
       
   303         return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
       
   304     }
       
   305 
       
   306     //for a native function
       
   307     if (!frame->optionalCalleeArguments()) {
       
   308         Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later
       
   309         JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters);
       
   310         frame->setCalleeArguments(arguments);
       
   311     }
       
   312     return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments());
       
   313 }
       
   314 
       
   315 /*!
       
   316   Returns true if the function was called as a constructor
       
   317   (e.g. \c{"new foo()"}); otherwise returns false.
       
   318 
       
   319   When a function is called as constructor, the thisObject()
       
   320   contains the newly constructed object to be initialized.
       
   321 */
       
   322 bool QScriptContext::isCalledAsConstructor() const
       
   323 {
       
   324     JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
       
   325 
       
   326     //For native functions, look up flags.
       
   327     uint flags = QScriptEnginePrivate::contextFlags(frame);
       
   328     if (flags & QScriptEnginePrivate::NativeContext)
       
   329         return flags & QScriptEnginePrivate::CalledAsConstructorContext;
       
   330 
       
   331     //Not a native function, try to look up in the bytecode if we where called from op_construct
       
   332     JSC::Instruction* returnPC = frame->returnPC();
       
   333 
       
   334     if (!returnPC)
       
   335         return false;
       
   336 
       
   337     JSC::CallFrame *callerFrame = QScriptEnginePrivate::frameForContext(parentContext());
       
   338     if (!callerFrame)
       
   339         return false;
       
   340 
       
   341     if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) {
       
   342         //We are maybe called from the op_construct opcode which has 6 opperands.
       
   343         //But we need to check we are not called from op_call with 4 opperands
       
   344 
       
   345         //we make sure that the returnPC[-1] (thisRegister) is smaller than the returnPC[-3] (registerOffset)
       
   346         //as if it was an op_call, the returnPC[-1] would be the registerOffset, bigger than returnPC[-3] (funcRegister)
       
   347         return returnPC[-1].u.operand < returnPC[-3].u.operand;
       
   348     }
       
   349     return false;
       
   350 }
       
   351 
       
   352 /*!
       
   353   Returns the parent context of this QScriptContext.
       
   354 */
       
   355 QScriptContext *QScriptContext::parentContext() const
       
   356 {
       
   357     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   358     JSC::CallFrame *callerFrame = frame->callerFrame()->removeHostCallFrameFlag();
       
   359     return QScriptEnginePrivate::contextForFrame(callerFrame);
       
   360 }
       
   361 
       
   362 /*!
       
   363   Returns the number of arguments passed to the function
       
   364   in this invocation.
       
   365 
       
   366   Note that the argument count can be different from the
       
   367   formal number of arguments (the \c{length} property of
       
   368   callee()).
       
   369 
       
   370   \sa argument()
       
   371 */
       
   372 int QScriptContext::argumentCount() const
       
   373 {
       
   374     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   375     int argc = frame->argumentCount();
       
   376     if (argc != 0)
       
   377         --argc; // -1 due to "this"
       
   378     return argc;
       
   379 }
       
   380 
       
   381 /*!
       
   382   \internal
       
   383 */
       
   384 QScriptValue QScriptContext::returnValue() const
       
   385 {
       
   386     qWarning("QScriptContext::returnValue() not implemented");
       
   387     return QScriptValue();
       
   388 }
       
   389 
       
   390 /*!
       
   391   \internal
       
   392 */
       
   393 void QScriptContext::setReturnValue(const QScriptValue &result)
       
   394 {
       
   395     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   396     JSC::CallFrame *callerFrame = frame->callerFrame();
       
   397     if (!callerFrame->codeBlock())
       
   398         return;
       
   399     Q_ASSERT_X(false, Q_FUNC_INFO, "check me");
       
   400     int dst = frame->registers()[JSC::RegisterFile::ReturnValueRegister].i(); // returnValueRegister() is private
       
   401     callerFrame[dst] = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(result);
       
   402 }
       
   403 
       
   404 /*!
       
   405   Returns the activation object of this QScriptContext. The activation
       
   406   object provides access to the local variables associated with this
       
   407   context.
       
   408 
       
   409   \sa argument(), argumentsObject()
       
   410 */
       
   411 
       
   412 QScriptValue QScriptContext::activationObject() const
       
   413 {
       
   414     JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
       
   415     JSC::JSObject *result = 0;
       
   416 
       
   417     uint flags = QScriptEnginePrivate::contextFlags(frame);
       
   418     if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
       
   419         //For native functions, lazily create it if needed
       
   420         QScript::QScriptActivationObject *scope = new (frame) QScript::QScriptActivationObject(frame);
       
   421         frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
       
   422         result = scope;
       
   423         QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
       
   424     } else {
       
   425         // look in scope chain
       
   426         JSC::ScopeChainNode *node = frame->scopeChain();
       
   427         JSC::ScopeChainIterator it(node);
       
   428         for (it = node->begin(); it != node->end(); ++it) {
       
   429             if ((*it) && (*it)->isVariableObject()) {
       
   430                 result = *it;
       
   431                 break;
       
   432             }
       
   433         }
       
   434     }
       
   435     if (!result) {
       
   436         if (!parentContext())
       
   437             return engine()->globalObject();
       
   438 
       
   439         qWarning("QScriptContext::activationObject:  could not get activation object for frame");
       
   440         return QScriptValue();
       
   441         /*JSC::CodeBlock *codeBlock = frame->codeBlock();
       
   442         if (!codeBlock) {
       
   443             // non-Qt native function 
       
   444             Q_ASSERT(true); //### this should in theorry not happen
       
   445             result = new (frame)QScript::QScriptActivationObject(frame);
       
   446         } else {
       
   447             // ### this is wrong
       
   448             JSC::FunctionBodyNode *body = static_cast<JSC::FunctionBodyNode*>(codeBlock->ownerNode());
       
   449             result = new (frame)JSC::JSActivation(frame, body);
       
   450         }*/
       
   451     }
       
   452 
       
   453     if (result && result->inherits(&QScript::QScriptActivationObject::info)
       
   454         && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) {
       
   455         // Return the object that property access is being delegated to
       
   456         result = static_cast<QScript::QScriptActivationObject*>(result)->delegate();
       
   457     }
       
   458 
       
   459     return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
       
   460 }
       
   461 
       
   462 /*!
       
   463   Sets the activation object of this QScriptContext to be the given \a
       
   464   activation.
       
   465 
       
   466   If \a activation is not an object, this function does nothing.
       
   467 */
       
   468 void QScriptContext::setActivationObject(const QScriptValue &activation)
       
   469 {
       
   470     if (!activation.isObject())
       
   471         return;
       
   472     else if (activation.engine() != engine()) {
       
   473         qWarning("QScriptContext::setActivationObject() failed: "
       
   474                  "cannot set an object created in "
       
   475                  "a different engine");
       
   476         return;
       
   477     }
       
   478     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   479     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
       
   480     JSC::JSObject *object = JSC::asObject(engine->scriptValueToJSCValue(activation));
       
   481     if (object == engine->originalGlobalObjectProxy)
       
   482         object = engine->originalGlobalObject();
       
   483 
       
   484     uint flags = QScriptEnginePrivate::contextFlags(frame);
       
   485     if ((flags & QScriptEnginePrivate::NativeContext) && !(flags & QScriptEnginePrivate::HasScopeContext)) {
       
   486         //For native functions, we create a scope node
       
   487         JSC::JSObject *scope = object;
       
   488         if (!scope->isVariableObject()) {
       
   489             // Create a QScriptActivationObject that acts as a proxy
       
   490             scope = new (frame) QScript::QScriptActivationObject(frame, scope);
       
   491         }
       
   492         frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
       
   493         QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
       
   494         return;
       
   495     }
       
   496 
       
   497     // else replace the first activation object in the scope chain
       
   498     JSC::ScopeChainNode *node = frame->scopeChain();
       
   499     while (node != 0) {
       
   500         if (node->object && node->object->isVariableObject()) {
       
   501             if (!object->isVariableObject()) {
       
   502                 if (node->object->inherits(&QScript::QScriptActivationObject::info)) {
       
   503                     static_cast<QScript::QScriptActivationObject*>(node->object)->setDelegate(object);
       
   504                 } else {
       
   505                     // Create a QScriptActivationObject that acts as a proxy
       
   506                     node->object = new (frame) QScript::QScriptActivationObject(frame, object);
       
   507                 }
       
   508             } else {
       
   509                 node->object = object;
       
   510             }
       
   511             break;
       
   512         }
       
   513         node = node->next;
       
   514     }
       
   515 }
       
   516 
       
   517 /*!
       
   518   Returns the `this' object associated with this QScriptContext.
       
   519 */
       
   520 QScriptValue QScriptContext::thisObject() const
       
   521 {
       
   522     JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
       
   523     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
       
   524     JSC::JSValue result = engine->thisForContext(frame);
       
   525     if (!result || result.isNull())
       
   526         result = frame->globalThisValue();
       
   527     return engine->scriptValueFromJSCValue(result);
       
   528 }
       
   529 
       
   530 /*!
       
   531   Sets the `this' object associated with this QScriptContext to be
       
   532   \a thisObject.
       
   533 
       
   534   If \a thisObject is not an object, this function does nothing.
       
   535 */
       
   536 void QScriptContext::setThisObject(const QScriptValue &thisObject)
       
   537 {
       
   538     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   539     if (!thisObject.isObject())
       
   540         return;
       
   541     if (thisObject.engine() != engine()) {
       
   542         qWarning("QScriptContext::setThisObject() failed: "
       
   543                  "cannot set an object created in "
       
   544                  "a different engine");
       
   545         return;
       
   546     }
       
   547     if (frame == frame->lexicalGlobalObject()->globalExec()) {
       
   548         engine()->setGlobalObject(thisObject);
       
   549         return;
       
   550     }
       
   551     JSC::JSValue jscThisObject = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(thisObject);
       
   552     JSC::CodeBlock *cb = frame->codeBlock();
       
   553     if (cb != 0) {
       
   554         frame[cb->thisRegister()] = jscThisObject;
       
   555     } else {
       
   556         JSC::Register* thisRegister = QScriptEnginePrivate::thisRegisterForFrame(frame);
       
   557         thisRegister[0] = jscThisObject;
       
   558     }
       
   559 }
       
   560 
       
   561 /*!
       
   562   Returns the frameution state of this QScriptContext.
       
   563 */
       
   564 QScriptContext::ExecutionState QScriptContext::state() const
       
   565 {
       
   566     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   567     if (frame->hadException())
       
   568         return QScriptContext::ExceptionState;
       
   569     return QScriptContext::NormalState;
       
   570 }
       
   571 
       
   572 /*!
       
   573   Returns a human-readable backtrace of this QScriptContext.
       
   574 
       
   575   Each line is of the form \c{<function-name>(<arguments>)@<file-name>:<line-number>}.
       
   576 
       
   577   To access individual pieces of debugging-related information (for
       
   578   example, to construct your own backtrace representation), use
       
   579   QScriptContextInfo.
       
   580 
       
   581   \sa QScriptEngine::uncaughtExceptionBacktrace(), QScriptContextInfo, toString()
       
   582 */
       
   583 QStringList QScriptContext::backtrace() const
       
   584 {
       
   585     QStringList result;
       
   586     const QScriptContext *ctx = this;
       
   587     while (ctx) {
       
   588         result.append(ctx->toString());
       
   589         ctx = ctx->parentContext();
       
   590     }
       
   591     return result;
       
   592 }
       
   593 
       
   594 /*!
       
   595   \since 4.4
       
   596 
       
   597   Returns a string representation of this context.
       
   598   This is useful for debugging.
       
   599 
       
   600   \sa backtrace()
       
   601 */
       
   602 QString QScriptContext::toString() const
       
   603 {
       
   604     QScriptContextInfo info(this);
       
   605     QString result;
       
   606 
       
   607     QString functionName = info.functionName();
       
   608     if (functionName.isEmpty()) {
       
   609         if (parentContext()) {
       
   610             const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   611             if (info.functionType() == QScriptContextInfo::ScriptFunction)
       
   612                 result.append(QLatin1String("<anonymous>"));
       
   613             else if(frame->callerFrame()->hasHostCallFrameFlag())
       
   614                 result.append(QLatin1String("<eval>"));
       
   615             else
       
   616                 result.append(QLatin1String("<native>"));
       
   617         } else {
       
   618             result.append(QLatin1String("<global>"));
       
   619         }
       
   620     } else {
       
   621         result.append(functionName);
       
   622     }
       
   623 
       
   624     QStringList parameterNames = info.functionParameterNames();
       
   625     result.append(QLatin1Char('('));
       
   626     for (int i = 0; i < argumentCount(); ++i) {
       
   627         if (i > 0)
       
   628             result.append(QLatin1String(", "));
       
   629         if (i < parameterNames.count()) {
       
   630             result.append(parameterNames.at(i));
       
   631             result.append(QLatin1String(" = "));
       
   632         }
       
   633         QScriptValue arg = argument(i);
       
   634         if (arg.isString())
       
   635             result.append(QLatin1Char('\''));
       
   636         result.append(arg.toString());
       
   637         if (arg.isString())
       
   638             result.append(QLatin1Char('\''));
       
   639 
       
   640     }
       
   641     result.append(QLatin1Char(')'));
       
   642 
       
   643     QString fileName = info.fileName();
       
   644     int lineNumber = info.lineNumber();
       
   645     result.append(QLatin1String(" at "));
       
   646     if (!fileName.isEmpty()) {
       
   647         result.append(fileName);
       
   648         result.append(QLatin1Char(':'));
       
   649     }
       
   650     result.append(QString::number(lineNumber));
       
   651     return result;
       
   652 }
       
   653 
       
   654 /*!
       
   655   \internal
       
   656   \since 4.5
       
   657 
       
   658   Returns the scope chain of this QScriptContext.
       
   659 */
       
   660 QScriptValueList QScriptContext::scopeChain() const
       
   661 {
       
   662     activationObject(); //ensure the creation of the normal scope for native context
       
   663     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   664     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
       
   665     QScriptValueList result;
       
   666     JSC::ScopeChainNode *node = frame->scopeChain();
       
   667     JSC::ScopeChainIterator it(node);
       
   668     for (it = node->begin(); it != node->end(); ++it) {
       
   669         JSC::JSObject *object = *it;
       
   670         if (!object)
       
   671             continue;
       
   672         if (object->inherits(&QScript::QScriptActivationObject::info)
       
   673             && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
       
   674             // Return the object that property access is being delegated to
       
   675             object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
       
   676         }
       
   677         result.append(engine->scriptValueFromJSCValue(object));
       
   678     }
       
   679     return result;
       
   680 }
       
   681 
       
   682 /*!
       
   683   \internal
       
   684   \since 4.5
       
   685 
       
   686   Adds the given \a object to the front of this context's scope chain.
       
   687 
       
   688   If \a object is not an object, this function does nothing.
       
   689 */
       
   690 void QScriptContext::pushScope(const QScriptValue &object)
       
   691 {
       
   692     activationObject(); //ensure the creation of the normal scope for native context
       
   693     if (!object.isObject())
       
   694         return;
       
   695     else if (object.engine() != engine()) {
       
   696         qWarning("QScriptContext::pushScope() failed: "
       
   697                  "cannot push an object created in "
       
   698                  "a different engine");
       
   699         return;
       
   700     }
       
   701     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   702     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
       
   703     JSC::JSObject *jscObject = JSC::asObject(engine->scriptValueToJSCValue(object));
       
   704     if (jscObject == engine->originalGlobalObjectProxy)
       
   705         jscObject = engine->originalGlobalObject();
       
   706     JSC::ScopeChainNode *scope = frame->scopeChain();
       
   707     Q_ASSERT(scope != 0);
       
   708     if (!scope->object) {
       
   709         // pushing to an "empty" chain
       
   710         if (!jscObject->isGlobalObject()) {
       
   711             qWarning("QScriptContext::pushScope() failed: initial object in scope chain has to be the Global Object");
       
   712             return;
       
   713         }
       
   714         scope->object = jscObject;
       
   715     }
       
   716     else
       
   717         frame->setScopeChain(scope->push(jscObject));
       
   718 }
       
   719 
       
   720 /*!
       
   721   \internal
       
   722   \since 4.5
       
   723 
       
   724   Removes the front object from this context's scope chain, and
       
   725   returns the removed object.
       
   726 
       
   727   If the scope chain is already empty, this function returns an
       
   728   invalid QScriptValue.
       
   729 */
       
   730 QScriptValue QScriptContext::popScope()
       
   731 {
       
   732     JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
       
   733     JSC::ScopeChainNode *scope = frame->scopeChain();
       
   734     Q_ASSERT(scope != 0);
       
   735     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
       
   736     QScriptValue result = engine->scriptValueFromJSCValue(scope->object);
       
   737     if (!scope->next) {
       
   738         // We cannot have a null scope chain, so just zap the object pointer.
       
   739         scope->object = 0;
       
   740     } else {
       
   741         frame->setScopeChain(scope->pop());
       
   742     }
       
   743     return result;
       
   744 }
       
   745 
       
   746 QT_END_NAMESPACE