/*!
  Sets the `this' object associated with this QScriptContext to be
  \a thisObject.

  If \a thisObject is not an object, this function does nothing.
*/
void QScriptContext::setThisObject(const QScriptValue &thisObject)
{
    JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(this);
    QScript::APIShim shim(QScript::scriptEngineFromExec(frame));
    if (!thisObject.isObject())
        return;
    if (thisObject.engine() != engine()) {
        qWarning("QScriptContext::setThisObject() failed: "
                 "cannot set an object created in "
                 "a different engine");
        return;
    }
    if (frame == frame->lexicalGlobalObject()->globalExec()) {
        engine()->setGlobalObject(thisObject);
        return;
    }
    JSC::JSValue jscThisObject = QScript::scriptEngineFromExec(frame)->scriptValueToJSCValue(thisObject);
    JSC::CodeBlock *cb = frame->codeBlock();
    if (cb != 0) {
        frame[cb->thisRegister()] = jscThisObject;
    } else {
        JSC::Register* thisRegister = QScriptEnginePrivate::thisRegisterForFrame(frame);
        thisRegister[0] = jscThisObject;
    }
}
/*!
  Returns the arguments object of this QScriptContext.

  The arguments object has properties \c callee (equal to callee())
  and \c length (equal to argumentCount()), and properties \c 0, \c 1,
  ..., argumentCount() - 1 that provide access to the argument
  values. Initially, property \c P (0 <= \c P < argumentCount()) has
  the same value as argument(\c P). In the case when \c P is less
  than the number of formal parameters of the function, \c P shares
  its value with the corresponding property of the activation object
  (activationObject()). This means that changing this property changes
  the corresponding property of the activation object and vice versa.

  \sa argument(), activationObject()
*/
QScriptValue QScriptContext::argumentsObject() const
{
    JSC::CallFrame *frame = const_cast<JSC::ExecState*>(QScriptEnginePrivate::frameForContext(this));
    QScript::APIShim shim(QScript::scriptEngineFromExec(frame));

    if (frame == frame->lexicalGlobalObject()->globalExec()) {
        // <global> context doesn't have arguments. return an empty object
        return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
    }

    //for a js function
    if (frame->codeBlock() && frame->callee()) {
        if (!QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) {
            // We have a built-in JS host call.
            // codeBlock is needed by retrieveArguments(), but since it
            // contains junk, we would crash. Return an invalid value for now.
            return QScriptValue();
        }
        JSC::JSValue result = frame->interpreter()->retrieveArguments(frame, JSC::asFunction(frame->callee()));
        return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(result);
    }

    if (frame->callerFrame()->hasHostCallFrameFlag()) {
        // <eval> context doesn't have arguments. return an empty object
        return QScriptEnginePrivate::get(QScript::scriptEngineFromExec(frame))->newObject();
    }

    //for a native function
    if (!frame->optionalCalleeArguments()
        && QScriptEnginePrivate::hasValidCodeBlockRegister(frame)) { // Make sure we don't go here for host JSFunctions
        Q_ASSERT(frame->argumentCount() > 0); //we need at least 'this' otherwise we'll crash later
        JSC::Arguments* arguments = new (&frame->globalData())JSC::Arguments(frame, JSC::Arguments::NoParameters);
        frame->setCalleeArguments(arguments);
    }
    return QScript::scriptEngineFromExec(frame)->scriptValueFromJSCValue(frame->optionalCalleeArguments());
}