Qt 4.8
qscriptcontext.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser
11 ** General Public License version 2.1 as published by the Free Software
12 ** Foundation and appearing in the file LICENSE.LGPL included in the
13 ** packaging of this file. Please review the following information to
14 ** ensure the GNU Lesser General Public License version 2.1 requirements
15 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** If you have questions regarding the use of this file, please contact
18 ** us via http://www.qt-project.org/.
19 **
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 
43 
159 {
160  //QScriptContext doesn't exist, pointer to QScriptContext are just pointer to JSC::CallFrame
161  Q_ASSERT(false);
162 }
163 
171 {
174  JSC::JSValue jscValue = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(value);
175  frame->setException(jscValue);
176  return value;
177 }
178 
194 {
197  JSC::ErrorType jscError = JSC::GeneralError;
198  switch (error) {
199  case UnknownError:
200  break;
201  case ReferenceError:
202  jscError = JSC::ReferenceError;
203  break;
204  case SyntaxError:
205  jscError = JSC::SyntaxError;
206  break;
207  case TypeError:
208  jscError = JSC::TypeError;
209  break;
210  case RangeError:
211  jscError = JSC::RangeError;
212  break;
213  case URIError:
214  jscError = JSC::URIError;
215  break;
216  }
217  JSC::JSObject *result = JSC::throwError(frame, jscError, text);
219 }
220 
233 {
236  JSC::JSObject *result = JSC::throwError(frame, JSC::GeneralError, text);
238 }
239 
244 {
245  //QScriptContext doesn't exist, pointer to QScriptContext are just pointer to JSC::CallFrame
246  Q_ASSERT(false);
247 }
248 
253 {
256 }
257 
267 {
268  if (index < 0)
269  return QScriptValue();
270  if (index >= argumentCount())
273  return v;
274 }
275 
281 {
284  QScript::APIShim shim(eng);
285  if (frame->callee() == eng->originalGlobalObject()) {
286  // This is a pushContext()-created context; the callee is a lie.
288  return QScriptValue();
289  }
290  return eng->scriptValueFromJSCValue(frame->callee());
291 }
292 
309 {
310  JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
312 
313  if (frame == frame->lexicalGlobalObject()->globalExec()) {
314  // <global> context doesn't have arguments. return an empty object
316  }
317 
318  //for a js function
319  if (frame->codeBlock() && frame->callee()) {
321  // We have a built-in JS host call.
322  // codeBlock is needed by retrieveArguments(), but since it
323  // contains junk, we would crash. Return an invalid value for now.
324  return QScriptValue();
325  }
326  JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee()));
328  }
329 
330  if (frame->callerFrame()->hasHostCallFrameFlag()) {
331  // <eval> context doesn't have arguments. return an empty object
333  }
334 
335  //for a native function
336  if (!frame->optionalCalleeArguments()
337  && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { // Make sure we don't go here for host JSFunctions
338  Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later
339  JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters);
340  frame->setCalleeArguments(arguments);
341  }
342  return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments());
343 }
344 
356 {
357  JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
359 
360  //For native functions, look up flags.
364 
365  //Not a native function, try to look up in the bytecode if we where called from op_construct
366  JSC::Instruction* returnPC = frame->returnPC();
367 
368  if (!returnPC)
369  return false;
370 
372  if (!callerFrame)
373  return false;
374 
375  if (returnPC[-JSC::op_construct_length].u.opcode == frame->interpreter()->getOpcode(JSC::op_construct)) {
376  //We are maybe called from the op_construct opcode which has 6 opperands.
377  //But we need to check we are not called from op_call with 4 opperands
378 
379  //we make sure that the returnPC[-1] (thisRegister) is smaller than the returnPC[-3] (registerOffset)
380  //as if it was an op_call, the returnPC[-1] would be the registerOffset, bigger than returnPC[-3] (funcRegister)
381  return returnPC[-1].u.operand < returnPC[-3].u.operand;
382  }
383  return false;
384 }
385 
390 {
393  JSC::CallFrame *callerFrame = frame->callerFrame()->removeHostCallFrameFlag();
394  return QScriptEnginePrivate::contextForFrame(callerFrame);
395 }
396 
408 {
410  int argc = frame->argumentCount();
411  if (argc != 0)
412  --argc; // -1 due to "this"
413  return argc;
414 }
415 
420 {
421  qWarning("QScriptContext::returnValue() not implemented");
422  return QScriptValue();
423 }
424 
429 {
431  JSC::CallFrame *callerFrame = frame->callerFrame();
432  if (!callerFrame->codeBlock())
433  return;
434  Q_ASSERT_X(false, Q_FUNC_INFO, "check me");
435  int dst = frame->registers()[JSC::RegisterFile::ReturnValueRegister].i(); // returnValueRegister() is private
436  callerFrame[dst] = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(result);
437 }
438 
451 {
452  JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
454  JSC::JSObject *result = 0;
455 
458  //For native functions, lazily create it if needed
460  frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
461  result = scope;
462  QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
463  } else {
464  // look in scope chain
465  JSC::ScopeChainNode *node = frame->scopeChain();
466  JSC::ScopeChainIterator it(node);
467  for (it = node->begin(); it != node->end(); ++it) {
468  if ((*it) && (*it)->isVariableObject()) {
469  result = *it;
470  break;
471  }
472  }
473  }
474  if (!result) {
475  if (!parentContext())
476  return engine()->globalObject();
477 
478  qWarning("QScriptContext::activationObject: could not get activation object for frame");
479  return QScriptValue();
480  /*JSC::CodeBlock *codeBlock = frame->codeBlock();
481  if (!codeBlock) {
482  // non-Qt native function
483  Q_ASSERT(true); //### this should in theorry not happen
484  result = new (frame)QScript::QScriptActivationObject(frame);
485  } else {
486  // ### this is wrong
487  JSC::FunctionBodyNode *body = static_cast<JSC::FunctionBodyNode*>(codeBlock->ownerNode());
488  result = new (frame)JSC::JSActivation(frame, body);
489  }*/
490  }
491 
492  if (result && result->inherits(&QScript::QScriptActivationObject::info)
493  && (static_cast<QScript::QScriptActivationObject*>(result)->delegate() != 0)) {
494  // Return the object that property access is being delegated to
495  result = static_cast<QScript::QScriptActivationObject*>(result)->delegate();
496  }
497 
499 }
500 
512 {
513  if (!activation.isObject())
514  return;
515  else if (activation.engine() != engine()) {
516  qWarning("QScriptContext::setActivationObject() failed: "
517  "cannot set an object created in "
518  "a different engine");
519  return;
520  }
523  QScript::APIShim shim(engine);
524  JSC::JSObject *object = JSC::asObject(engine->scriptValueToJSCValue(activation));
525  if (object == engine->originalGlobalObjectProxy)
526  object = engine->originalGlobalObject();
527 
530  //For native functions, we create a scope node
531  JSC::JSObject *scope = object;
532  if (!scope->isVariableObject()) {
533  // Create a QScriptActivationObject that acts as a proxy
534  scope = new (frame) QScript::QScriptActivationObject(frame, scope);
535  }
536  frame->setScopeChain(frame->scopeChain()->copy()->push(scope));
537  QScriptEnginePrivate::setContextFlags(frame, flags | QScriptEnginePrivate::HasScopeContext);
538  return;
539  }
540 
541  // else replace the first activation object in the scope chain
542  JSC::ScopeChainNode *node = frame->scopeChain();
543  while (node != 0) {
544  if (node->object && node->object->isVariableObject()) {
545  if (!object->isVariableObject()) {
546  if (node->object->inherits(&QScript::QScriptActivationObject::info)) {
547  static_cast<QScript::QScriptActivationObject*>(node->object)->setDelegate(object);
548  } else {
549  // Create a QScriptActivationObject that acts as a proxy
550  node->object = new (frame) QScript::QScriptActivationObject(frame, object);
551  }
552  } else {
553  node->object = object;
554  }
555  break;
556  }
557  node = node->next;
558  }
559 }
560 
565 {
566  JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
568  QScript::APIShim shim(engine);
569  JSC::JSValue result = engine->thisForContext(frame);
570  if (!result || result.isNull())
571  result = frame->globalThisValue();
572  return engine->scriptValueFromJSCValue(result);
573 }
574 
582 {
585  if (!thisObject.isObject())
586  return;
587  if (thisObject.engine() != engine()) {
588  qWarning("QScriptContext::setThisObject() failed: "
589  "cannot set an object created in "
590  "a different engine");
591  return;
592  }
593  if (frame == frame->lexicalGlobalObject()->globalExec()) {
594  engine()->setGlobalObject(thisObject);
595  return;
596  }
597  JSC::JSValue jscThisObject = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(thisObject);
598  JSC::CodeBlock *cb = frame->codeBlock();
599  if (cb != 0) {
600  frame[cb->thisRegister()] = jscThisObject;
601  } else {
602  JSC::Register* thisRegister = QScriptEnginePrivate::thisRegisterForFrame(frame);
603  thisRegister[0] = jscThisObject;
604  }
605 }
606 
611 {
613  if (frame->hadException())
616 }
617 
630 {
631  QStringList result;
632  const QScriptContext *ctx = this;
633  while (ctx) {
634  result.append(ctx->toString());
635  ctx = ctx->parentContext();
636  }
637  return result;
638 }
639 
652 {
653  QScriptContextInfo info(this);
654  QString result;
655 
656  QString functionName = info.functionName();
657  if (functionName.isEmpty()) {
658  if (parentContext()) {
661  result.append(QLatin1String("<anonymous>"));
662  else if(frame->callerFrame()->hasHostCallFrameFlag())
663  result.append(QLatin1String("<eval>"));
664  else
665  result.append(QLatin1String("<native>"));
666  } else {
667  result.append(QLatin1String("<global>"));
668  }
669  } else {
670  result.append(functionName);
671  }
672 
673  QStringList parameterNames = info.functionParameterNames();
674  result.append(QLatin1Char('('));
675  for (int i = 0; i < argumentCount(); ++i) {
676  if (i > 0)
677  result.append(QLatin1String(", "));
678  if (i < parameterNames.count()) {
679  result.append(parameterNames.at(i));
680  result.append(QLatin1String(" = "));
681  }
682  QScriptValue arg = argument(i);
683  if (arg.isString())
684  result.append(QLatin1Char('\''));
685  result.append(arg.toString());
686  if (arg.isString())
687  result.append(QLatin1Char('\''));
688 
689  }
690  result.append(QLatin1Char(')'));
691 
692  QString fileName = info.fileName();
693  int lineNumber = info.lineNumber();
694  result.append(QLatin1String(" at "));
695  if (!fileName.isEmpty()) {
696  result.append(fileName);
697  result.append(QLatin1Char(':'));
698  }
699  result.append(QString::number(lineNumber));
700  return result;
701 }
702 
713 {
714  activationObject(); //ensure the creation of the normal scope for native context
717  QScript::APIShim shim(engine);
718  QScriptValueList result;
719  JSC::ScopeChainNode *node = frame->scopeChain();
720  JSC::ScopeChainIterator it(node);
721  for (it = node->begin(); it != node->end(); ++it) {
722  JSC::JSObject *object = *it;
723  if (!object)
724  continue;
725  if (object->inherits(&QScript::QScriptActivationObject::info)
726  && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
727  // Return the object that property access is being delegated to
728  object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
729  }
730  result.append(engine->scriptValueFromJSCValue(object));
731  }
732  return result;
733 }
734 
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("QScriptContext::pushScope() failed: "
753  "cannot push an object created in "
754  "a different engine");
755  return;
756  }
759  QScript::APIShim shim(engine);
760  JSC::JSObject *jscObject = JSC::asObject(engine->scriptValueToJSCValue(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("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(jscObject));
775 }
776 
791 {
792  activationObject(); //ensure the creation of the normal scope for native context
794  JSC::ScopeChainNode *scope = frame->scopeChain();
795  Q_ASSERT(scope != 0);
797  QScript::APIShim shim(engine);
798  QScriptValue result = engine->scriptValueFromJSCValue(scope->object);
799  if (!scope->next) {
800  // We cannot have a null scope chain, so just zap the object pointer.
801  scope->object = 0;
802  } else {
803  frame->setScopeChain(scope->pop());
804  }
805  return result;
806 }
807 
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
The QScriptContext class represents a Qt Script function invocation.
QScriptValue property(const QString &name, const ResolveFlags &mode=ResolvePrototype) const
Returns the value of this QScriptValue&#39;s property with the given name, using the given mode to resolv...
static JSC::ExecState * frameForContext(QScriptContext *context)
QScriptEnginePrivate * scriptEngineFromExec(const JSC::ExecState *exec)
static mach_timebase_info_data_t info
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool isCalledAsConstructor() const
Returns true if the function was called as a constructor (e.g.
static JSC::Register * thisRegisterForFrame(JSC::ExecState *frame)
#define it(className, varName)
static QScriptEnginePrivate * get(QScriptEngine *q)
QString toString() const
Returns a string representation of this context.
QScriptValue callee() const
Returns the callee.
static uint contextFlags(JSC::ExecState *)
For native context, we use the ReturnValueRegister entry in the stackframe header to store flags...
QScriptValueList scopeChain() const
Returns the scope chain of this QScriptContext.
#define error(msg)
QScriptValue throwError(Error error, const QString &text)
Throws an error with the given text.
QScriptValue argumentsObject() const
Returns the arguments object of this QScriptContext.
QString toString() const
Returns the string value of this QScriptValue, as defined in ECMA-262 section 9.8, "ToString".
QScriptValue globalObject() const
Returns this engine&#39;s Global Object.
JSC::JSValue newObject()
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
quint16 u
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
QScriptEngine * engine() const
Returns the QScriptEngine that this QScriptContext belongs to.
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
ExecutionState
This enum specifies the frameution state of the context.
void setThisObject(const QScriptValue &thisObject)
Sets the `this&#39; object associated with this QScriptContext to be thisObject.
static void setContextFlags(JSC::ExecState *, uint)
void setActivationObject(const QScriptValue &activation)
Sets the activation object of this QScriptContext to be the given activation.
QString fileName() const
Returns the name of the file where the code being executed was defined, if available; otherwise retur...
QScriptValue popScope()
Removes the front object from this context&#39;s scope chain, and returns the removed object...
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
The QScriptEngine class provides an environment for evaluating Qt Script code.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
int lineNumber() const
Returns the line number corresponding to the statement being executed, or -1 if the line number is no...
JSC::JSValue scriptValueToJSCValue(const QScriptValue &value)
static QScriptContext * contextForFrame(JSC::ExecState *frame)
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
JSC::JSGlobalObject * originalGlobalObject() const
bool isString() const
Returns true if this QScriptValue is of the primitive type String; otherwise returns false...
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
QScriptEngine * engine() const
Returns the QScriptEngine that created this QScriptValue, or 0 if this QScriptValue is invalid or the...
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
QStringList backtrace() const
Returns a human-readable backtrace of this QScriptContext.
Q_CORE_EXPORT void qWarning(const char *,...)
unsigned int uint
Definition: qglobal.h:996
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
void setGlobalObject(const QScriptValue &object)
Sets this engine&#39;s Global Object to be the given object.
int argumentCount() const
Returns the number of arguments passed to the function in this invocation.
ExecutionState state() const
Returns the frameution state of this QScriptContext.
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
The QScriptContextInfo class provides additional information about a QScriptContext.
QString & append(QChar c)
Definition: qstring.cpp:1777
QStringList functionParameterNames() const
Returns the names of the formal parameters of the called function, or an empty QStringList if the par...
void setReturnValue(const QScriptValue &result)
Error
This enum specifies types of error.
#define ctx
Definition: qgl.cpp:6094
JSC::JSObject * originalGlobalObjectProxy
~QScriptContext()
Destroys this QScriptContext.
quint16 index
FunctionType functionType() const
Returns the type of the called function.
QScriptValue scriptValueFromJSCValue(JSC::JSValue value)
QScriptValue activationObject() const
Returns the activation object of this QScriptContext.
Represent a scope for native function call.
QScriptValue thisObject() const
Returns the `this&#39; object associated with this QScriptContext.
void pushScope(const QScriptValue &object)
Adds the given object to the front of this context&#39;s scope chain.
ExecState CallFrame
static JSC::JSValue thisForContext(JSC::ExecState *frame)
The QScriptValue class acts as a container for the Qt Script data types.
Definition: qscriptvalue.h:57
static QString fileName(const QString &fileUrl)
QScriptValue returnValue() const
QScriptValue argument(int index) const
Returns the function argument at the given index.
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
QScriptContext * parentContext() const
Returns the parent context of this QScriptContext.
static bool hasValidCodeBlockRegister(JSC::ExecState *frame)
bool isObject() const
Returns true if this QScriptValue is of the Object type; otherwise returns false. ...
#define text
Definition: qobjectdefs.h:80
QString functionName() const
Returns the name of the called function, or an empty string if the name is not available.
#define Q_FUNC_INFO
Definition: qglobal.h:1871
QScriptValue throwValue(const QScriptValue &value)
Throws an exception with the given value.