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